fix: user id data not showing

This commit is contained in:
akhdanre 2025-04-27 23:00:33 +07:00
parent 7a521b9ca2
commit a797061cce
11 changed files with 61 additions and 38 deletions

View File

@ -4,10 +4,10 @@ from dependency_injector.wiring import inject, Provide
from controllers import QuizController from controllers import QuizController
quiz_bp = Blueprint("quiz", __name__, url_prefix="/quiz") quiz_bp = Blueprint("quiz", __name__)
@quiz_bp.route("/", methods=["POST"]) @quiz_bp.route("", methods=["POST"])
@inject @inject
def create_quiz(controller: QuizController = Provide[Container.quiz_controller]): def create_quiz(controller: QuizController = Provide[Container.quiz_controller]):
reqBody = request.get_json() reqBody = request.get_json()

View File

@ -23,15 +23,26 @@ def createApp() -> Flask:
if mongo is not None: if mongo is not None:
container.mongo.override(mongo) container.mongo.override(mongo)
container.wire(modules=["blueprints.auth"]) # container.wire(modules=["blueprints.auth"])
container.wire(modules=["blueprints.user"]) # container.wire(modules=["blueprints.user"])
container.wire(modules=["blueprints.quiz"]) # container.wire(modules=["blueprints.quiz"])
container.wire(
modules=[
"blueprints.auth",
"blueprints.user",
"blueprints.quiz",
]
)
# Register Blueprints # Register Blueprints
app.register_blueprint(default_blueprint) app.register_blueprint(default_blueprint)
app.register_blueprint(auth_blueprint, url_prefix="/api") app.register_blueprint(auth_blueprint, url_prefix="/api")
app.register_blueprint(user_blueprint, url_prefix="/api") app.register_blueprint(user_blueprint, url_prefix="/api")
app.register_blueprint(quiz_bp, url_prefix="/api") app.register_blueprint(quiz_bp, url_prefix="/api/quiz")
# for rule in app.url_map.iter_rules():
# print(f"Route: {rule} -> Methods: {rule.methods}")
return app return app

View File

@ -42,8 +42,9 @@ class UserMapper:
@staticmethod @staticmethod
def user_entity_to_response(user: UserEntity) -> UserResponseModel: def user_entity_to_response(user: UserEntity) -> UserResponseModel:
print(user.id)
return UserResponseModel( return UserResponseModel(
_id=str(user._id) if user._id else None, id=str(user.id) if user.id else None,
google_id=user.google_id, google_id=user.google_id,
email=user.email, email=user.email,
name=user.name, name=user.name,

View File

@ -1,23 +1,29 @@
from bson import ObjectId from bson import ObjectId
from pydantic import GetJsonSchemaHandler from pydantic import GetCoreSchemaHandler
from pydantic.json_schema import JsonSchemaValue from pydantic_core import core_schema
class PyObjectId(ObjectId): class PyObjectId(ObjectId):
"""Custom ObjectId type for Pydantic v2 to handle MongoDB _id""" """Custom ObjectId type for Pydantic v2 to handle MongoDB _id"""
@classmethod @classmethod
def __get_validators__(cls): def __get_pydantic_core_schema__(
yield cls.validate cls, source, handler: GetCoreSchemaHandler
) -> core_schema.CoreSchema:
return core_schema.no_info_after_validator_function(
cls.validate,
core_schema.union_schema(
[
core_schema.str_schema(),
core_schema.is_instance_schema(ObjectId),
]
),
)
@classmethod @classmethod
def validate(cls, v): def validate(cls, v):
if not ObjectId.is_valid(v): if isinstance(v, ObjectId):
raise ValueError("Invalid ObjectId") return v
if isinstance(v, str) and ObjectId.is_valid(v):
return ObjectId(v) return ObjectId(v)
raise ValueError(f"Invalid ObjectId: {v}")
@classmethod
def __get_pydantic_json_schema__(
cls, schema: JsonSchemaValue, handler: GetJsonSchemaHandler
) -> JsonSchemaValue:
return {"type": "string"}

View File

@ -19,6 +19,6 @@ class UserAnswerEntity(BaseModel):
total_questions: int total_questions: int
class Config: class Config:
allow_population_by_field_name = True populate_by_name = True
arbitrary_types_allowed = True arbitrary_types_allowed = True
json_encoders = {ObjectId: str} json_encoders = {ObjectId: str}

View File

@ -1,13 +1,13 @@
from typing import Optional from typing import Optional
from pydantic import BaseModel, EmailStr from pydantic import BaseModel, Field
from datetime import datetime from datetime import datetime
from .base import PyObjectId from .base import PyObjectId
class UserEntity(BaseModel): class UserEntity(BaseModel):
_id: Optional[PyObjectId] = None id: Optional[PyObjectId] = Field(default=None, alias="_id")
google_id: Optional[str] = None google_id: Optional[str] = None
email: EmailStr email: str
password: Optional[str] = None password: Optional[str] = None
name: str name: str
birth_date: Optional[datetime] = None birth_date: Optional[datetime] = None
@ -16,3 +16,7 @@ class UserEntity(BaseModel):
locale: str = "en-US" locale: str = "en-US"
created_at: Optional[datetime] = None created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None updated_at: Optional[datetime] = None
class Config:
populate_by_name = True
json_encoders = {PyObjectId: str}

View File

@ -14,7 +14,7 @@ class UserResponseModel(BaseModel):
locale: str locale: str
class Config: class Config:
allow_population_by_field_name = True populate_by_name = True
json_encoders = { json_encoders = {
datetime: lambda v: v.isoformat(), datetime: lambda v: v.isoformat(),
} }

View File

@ -4,44 +4,43 @@ from models import UserEntity
class UserRepository: class UserRepository:
def __init__(self, db): def __init__(self, db):
self.collection = db.users self.collection = db.users
def get_all_users(self) -> list[UserEntity]: def get_all_users(self) -> list[UserEntity]:
"""Mengambil semua user dari database.""" """Retrieve all users from the database."""
users = list(self.collection.find({}, {"_id": 0})) users = list(self.collection.find({}, {"_id": 0}))
return [UserEntity(**user) for user in users] return [UserEntity(**user) for user in users]
def get_user_by_email(self, email: str) -> Optional[UserEntity]: def get_user_by_email(self, email: str) -> Optional[UserEntity]:
"""Mendapatkan user berdasarkan email.""" """Retrieve a user based on their email address."""
user = self.collection.find_one({"email": email}, {"_id": 0}) user = self.collection.find_one({"email": email})
return UserEntity(**user) if user else None return UserEntity(**user) if user else None
def get_user_by_id(self, user_id: str) -> Optional[UserEntity]: def get_user_by_id(self, user_id: str) -> Optional[UserEntity]:
"""Mendapatkan user berdasarkan ID.""" """Retrieve a user based on their ID."""
object_id = ObjectId(user_id) object_id = ObjectId(user_id)
user = self.collection.find_one({"_id": object_id}) user = self.collection.find_one({"_id": object_id})
return UserEntity(**user) if user else None return UserEntity(**user) if user else None
def get_by_google_id(self, google_id: str) -> Optional[UserEntity]: def get_by_google_id(self, google_id: str) -> Optional[UserEntity]:
"""Retrieve a user based on their Google ID."""
user_data = self.collection.find_one({"google_id": google_id}) user_data = self.collection.find_one({"google_id": google_id})
return UserEntity(**user_data) if user_data else None return UserEntity(**user_data) if user_data else None
def insert_user(self, user_data: UserEntity) -> str: def insert_user(self, user_data: UserEntity) -> str:
"""Menambahkan pengguna baru ke dalam database dan mengembalikan ID pengguna.""" """Insert a new user into the database and return the user's ID."""
result = self.collection.insert_one(user_data.model_dump()) result = self.collection.insert_one(user_data.model_dump())
return str(result.inserted_id) return str(result.inserted_id)
def update_user(self, user_id: str, update_data: dict) -> bool: def update_user(self, user_id: str, update_data: dict) -> bool:
"""Mengupdate seluruh data user berdasarkan ID.""" """Update all fields of a user based on their ID."""
object_id = ObjectId(user_id) object_id = ObjectId(user_id)
result = self.collection.update_one({"_id": object_id}, {"$set": update_data}) result = self.collection.update_one({"_id": object_id}, {"$set": update_data})
return result.modified_count > 0 return result.modified_count > 0
def update_user_field(self, user_id: str, field: str, value) -> bool: def update_user_field(self, user_id: str, field: str, value) -> bool:
"""Mengupdate satu field dari user berdasarkan ID.""" """Update a single field of a user based on their ID."""
object_id = ObjectId(user_id) object_id = ObjectId(user_id)
result = self.collection.update_one( result = self.collection.update_one(
{"_id": object_id}, {"$set": {field: value}} {"_id": object_id}, {"$set": {field: value}}
@ -49,7 +48,7 @@ class UserRepository:
return result.modified_count > 0 return result.modified_count > 0
def delete_user(self, user_id: str) -> bool: def delete_user(self, user_id: str) -> bool:
"""Menghapus user berdasarkan ID.""" """Delete a user based on their ID."""
object_id = ObjectId(user_id) object_id = ObjectId(user_id)
result = self.collection.delete_one({"_id": object_id}) result = self.collection.delete_one({"_id": object_id})
return result.deleted_count > 0 return result.deleted_count > 0

View File

@ -8,7 +8,7 @@ class QuizCreateSchema(BaseModel):
title: str title: str
description: Optional[str] = None description: Optional[str] = None
is_public: bool = False is_public: bool = False
date: Optional[datetime] = None date: Optional[str] = None
total_quiz: Optional[int] = 0 total_quiz: Optional[int] = 0
limit_duration: Optional[int] = 0 limit_duration: Optional[int] = 0
author_id: Optional[str] = None author_id: Optional[str] = None

View File

@ -1,3 +1,4 @@
from typing import List, Optional
from pydantic import BaseModel from pydantic import BaseModel
@ -6,3 +7,4 @@ class QuestionItemSchema(BaseModel):
target_answer: str target_answer: str
duration: int duration: int
type: str type: str
options: Optional[List[str]] = None

View File

@ -37,10 +37,10 @@ class AuthService:
def login(self, data: LoginSchema): def login(self, data: LoginSchema):
current_app.logger.info(f"request data: {data}") # current_app.logger.info(f"request data: {data}")
user_data = self.user_repository.get_user_by_email(data.email) user_data = self.user_repository.get_user_by_email(data.email)
current_app.logger.info(f"user_data: {user_data}") # current_app.logger.info(f"user_data: {user_data}")
if user_data == None: if user_data == None:
return None return None