fix: response properties

This commit is contained in:
akhdanre 2025-05-04 01:10:18 +07:00
parent 5774850aaa
commit 3c0d8e1e15
12 changed files with 91 additions and 33 deletions

View File

@ -50,6 +50,7 @@ class Container(containers.DeclarativeContainer):
QuizService,
quiz_repository,
user_repository,
subject_repository,
)
answer_service = providers.Factory(
AnswerService,

View File

@ -1,6 +1,7 @@
from datetime import datetime
from helpers import DatetimeUtil
from models import QuizEntity, QuestionItemEntity, UserEntity
from models.entities import SubjectEntity
from schemas import QuizGetSchema, QuestionItemSchema
from schemas.response import RecomendationResponse
from schemas.requests import QuizCreateSchema
@ -31,10 +32,15 @@ class QuizMapper:
)
@staticmethod
def map_quiz_entity_to_schema(entity: QuizEntity) -> QuizGetSchema:
def map_quiz_entity_to_schema(
entity: QuizEntity,
subjectE: SubjectEntity,
) -> QuizGetSchema:
return QuizGetSchema(
id=str(entity.id),
author_id=entity.author_id,
subject_id=str(subjectE.id),
subject_alias=subjectE.short_name,
title=entity.title,
description=entity.description,
is_public=entity.is_public,
@ -56,6 +62,7 @@ class QuizMapper:
) -> QuizEntity:
return QuizEntity(
author_id=schema.author_id,
subject_id=schema.subject_id,
title=schema.title,
description=schema.description,
is_public=schema.is_public,

View File

@ -1,8 +1,9 @@
from pydantic import BaseModel
from typing import Union
class AnswerItemEntity(BaseModel):
question_index: int
answer: str
answer: Union[str | int | bool]
is_correct: bool
time_spent: float

View File

@ -8,9 +8,9 @@ from .question_item_entity import QuestionItemEntity
class QuizEntity(BaseModel):
id: Optional[PyObjectId] = Field(default=None, alias="_id")
author_id: Optional[str] = None
subject_id: str
title: str
description: Optional[str] = None
# subject: str
is_public: bool = False
date: datetime
total_quiz: int = 0

View File

@ -1,35 +1,61 @@
from typing import List, Optional
from pymongo.database import Database
from pymongo.collection import Collection
from bson import ObjectId, errors as bson_errors
from models.entities import SubjectEntity
from bson import ObjectId
class SubjectRepository:
COLLECTION_NAME = "subjects"
def __init__(self, db: Database):
self.collection: Collection = db.subjects
self.collection: Collection = db[self.COLLECTION_NAME]
def create(self, subject: SubjectEntity) -> str:
subject_dict = subject.dict(by_alias=True, exclude_none=True)
subject_dict = subject.model_dump(by_alias=True, exclude_none=True)
result = self.collection.insert_one(subject_dict)
return str(result.inserted_id)
def get_all(self) -> List[SubjectEntity]:
cursor = self.collection.find({})
return [SubjectEntity(**doc) for doc in cursor]
return [SubjectEntity(**doc) for doc in self.collection.find()]
def get_by_id(self, subject_id: str) -> Optional[SubjectEntity]:
doc = self.collection.find_one({"_id": ObjectId(subject_id)})
if doc:
return SubjectEntity(**doc)
try:
oid = ObjectId(subject_id)
except bson_errors.InvalidId:
return None
doc = self.collection.find_one({"_id": oid})
return SubjectEntity(**doc) if doc else None
def get_by_ids(self, subject_ids: List[str]) -> List[SubjectEntity]:
object_ids = []
for sid in subject_ids:
try:
object_ids.append(ObjectId(sid))
except bson_errors.InvalidId:
continue
if not object_ids:
return []
cursor = self.collection.find({"_id": {"$in": object_ids}})
return [SubjectEntity(**doc) for doc in cursor]
def update(self, subject_id: str, update_data: dict) -> bool:
result = self.collection.update_one(
{"_id": ObjectId(subject_id)}, {"$set": update_data}
)
try:
oid = ObjectId(subject_id)
except bson_errors.InvalidId:
return False
result = self.collection.update_one({"_id": oid}, {"$set": update_data})
return result.modified_count > 0
def delete(self, subject_id: str) -> bool:
result = self.collection.delete_one({"_id": ObjectId(subject_id)})
try:
oid = ObjectId(subject_id)
except bson_errors.InvalidId:
return False
result = self.collection.delete_one({"_id": oid})
return result.deleted_count > 0

View File

@ -1,8 +1,9 @@
from pydantic import BaseModel
from typing import Union
class AnswerItemSchema(BaseModel):
question_index: int
answer: str
answer: Union[str | int | bool]
is_correct: bool
time_spent: float

View File

@ -8,5 +8,6 @@ class QuizCreateSchema(BaseModel):
title: str
description: Optional[str] = None
is_public: bool = False
subject_id: str
author_id: Optional[str] = None
question_listings: Optional[List[QuestionItemSchema]] = []

View File

@ -1,4 +1,4 @@
from typing import List, Optional
from typing import List, Optional, Union
from pydantic import BaseModel
from datetime import datetime
@ -7,8 +7,8 @@ class QuestionResult(BaseModel):
index: int
question: str
type: str
target_answer: str
user_answer: Optional[str]
target_answer: Union[str | bool | int]
user_answer: Optional[Union[str | bool | int]]
is_correct: Optional[bool]
time_spent: Optional[float]
options: Optional[List[str]]

View File

@ -1,8 +1,10 @@
from typing import List
from pydantic import BaseModel
from schemas.response import QuizGetSchema
from schemas.response.recomendation.recomendation_response_schema import (
RecomendationResponse,
)
class UserQuizListResponse(BaseModel):
total: int
quizzes: List[QuizGetSchema]
quizzes: List[RecomendationResponse]

View File

@ -7,6 +7,8 @@ from .question_item_schema import QuestionItemSchema
class QuizGetSchema(BaseModel):
id: str
author_id: str
subject_id: str
subject_alias: str
title: str
description: Optional[str] = None
is_public: bool = False

View File

@ -47,11 +47,13 @@ class AnswerService:
)
correct = False
if question.type in ["fill_the_blank", "true_false"]:
if question.type == "fill_the_blank":
correct = (
user_answer.answer.strip().lower()
== question.target_answer.strip().lower()
)
elif question.type == "true_false":
correct = user_answer.answer == question.target_answer
elif question.type == "option":
try:
answer_index = int(user_answer.answer)

View File

@ -1,8 +1,6 @@
from models import QuizEntity
from repositories import QuizRepository, UserRepository
from schemas import QuizGetSchema
from repositories import QuizRepository, UserRepository, SubjectRepository
from schemas.requests import QuizCreateSchema
from schemas.response import UserQuizListResponse, RecomendationResponse
from schemas.response import UserQuizListResponse, RecomendationResponse, QuizGetSchema
from exception import DataNotFoundException
from mapper import QuizMapper
from exception import ValidationException
@ -10,15 +8,23 @@ from helpers import DatetimeUtil
class QuizService:
def __init__(self, quiz_repository=QuizRepository, user_repository=UserRepository):
def __init__(
self,
quiz_repository=QuizRepository,
user_repository=UserRepository,
subject_repository=SubjectRepository,
):
self.quiz_repository = quiz_repository
self.user_repostory = user_repository
self.subject_repository = subject_repository
def get_quiz(self, quiz_id) -> QuizGetSchema:
data = self.quiz_repository.get_by_id(quiz_id)
if data is None:
raise DataNotFoundException("Quiz not found")
return QuizMapper.map_quiz_entity_to_schema(data)
quiz_subject = self.subject_repository.get_by_id(data.subject_id)
return QuizMapper.map_quiz_entity_to_schema(data, quiz_subject)
def search_quiz(
self, keyword: str, page: int = 1, page_size: int = 10
@ -46,11 +52,20 @@ class QuizService:
self, user_id: str, page: int = 1, page_size: int = 10
) -> UserQuizListResponse:
quizzes = self.quiz_repository.get_by_user_id(user_id, page, page_size)
if not quizzes:
return UserQuizListResponse(total=0, quizzes=[])
total_user_quiz = self.quiz_repository.count_by_user_id(user_id)
return UserQuizListResponse(
total=total_user_quiz,
quizzes=[QuizMapper.map_quiz_entity_to_schema(quiz) for quiz in quizzes],
)
print(total_user_quiz)
user = self.user_repostory.get_user_by_id(user_id)
quiz_data = [
QuizMapper.quiz_to_recomendation_mapper(quiz, user) for quiz in quizzes
]
return UserQuizListResponse(total=total_user_quiz, quizzes=quiz_data)
def create_quiz(self, quiz_data: QuizCreateSchema):
total_time = 0