fix: response properties
This commit is contained in:
parent
5774850aaa
commit
3c0d8e1e15
|
@ -50,6 +50,7 @@ class Container(containers.DeclarativeContainer):
|
||||||
QuizService,
|
QuizService,
|
||||||
quiz_repository,
|
quiz_repository,
|
||||||
user_repository,
|
user_repository,
|
||||||
|
subject_repository,
|
||||||
)
|
)
|
||||||
answer_service = providers.Factory(
|
answer_service = providers.Factory(
|
||||||
AnswerService,
|
AnswerService,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from helpers import DatetimeUtil
|
from helpers import DatetimeUtil
|
||||||
from models import QuizEntity, QuestionItemEntity, UserEntity
|
from models import QuizEntity, QuestionItemEntity, UserEntity
|
||||||
|
from models.entities import SubjectEntity
|
||||||
from schemas import QuizGetSchema, QuestionItemSchema
|
from schemas import QuizGetSchema, QuestionItemSchema
|
||||||
from schemas.response import RecomendationResponse
|
from schemas.response import RecomendationResponse
|
||||||
from schemas.requests import QuizCreateSchema
|
from schemas.requests import QuizCreateSchema
|
||||||
|
@ -31,10 +32,15 @@ class QuizMapper:
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def map_quiz_entity_to_schema(entity: QuizEntity) -> QuizGetSchema:
|
def map_quiz_entity_to_schema(
|
||||||
|
entity: QuizEntity,
|
||||||
|
subjectE: SubjectEntity,
|
||||||
|
) -> QuizGetSchema:
|
||||||
return QuizGetSchema(
|
return QuizGetSchema(
|
||||||
id=str(entity.id),
|
id=str(entity.id),
|
||||||
author_id=entity.author_id,
|
author_id=entity.author_id,
|
||||||
|
subject_id=str(subjectE.id),
|
||||||
|
subject_alias=subjectE.short_name,
|
||||||
title=entity.title,
|
title=entity.title,
|
||||||
description=entity.description,
|
description=entity.description,
|
||||||
is_public=entity.is_public,
|
is_public=entity.is_public,
|
||||||
|
@ -56,6 +62,7 @@ class QuizMapper:
|
||||||
) -> QuizEntity:
|
) -> QuizEntity:
|
||||||
return QuizEntity(
|
return QuizEntity(
|
||||||
author_id=schema.author_id,
|
author_id=schema.author_id,
|
||||||
|
subject_id=schema.subject_id,
|
||||||
title=schema.title,
|
title=schema.title,
|
||||||
description=schema.description,
|
description=schema.description,
|
||||||
is_public=schema.is_public,
|
is_public=schema.is_public,
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
class AnswerItemEntity(BaseModel):
|
class AnswerItemEntity(BaseModel):
|
||||||
question_index: int
|
question_index: int
|
||||||
answer: str
|
answer: Union[str | int | bool]
|
||||||
is_correct: bool
|
is_correct: bool
|
||||||
time_spent: float
|
time_spent: float
|
||||||
|
|
|
@ -8,9 +8,9 @@ from .question_item_entity import QuestionItemEntity
|
||||||
class QuizEntity(BaseModel):
|
class QuizEntity(BaseModel):
|
||||||
id: Optional[PyObjectId] = Field(default=None, alias="_id")
|
id: Optional[PyObjectId] = Field(default=None, alias="_id")
|
||||||
author_id: Optional[str] = None
|
author_id: Optional[str] = None
|
||||||
|
subject_id: str
|
||||||
title: str
|
title: str
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
# subject: str
|
|
||||||
is_public: bool = False
|
is_public: bool = False
|
||||||
date: datetime
|
date: datetime
|
||||||
total_quiz: int = 0
|
total_quiz: int = 0
|
||||||
|
|
|
@ -1,35 +1,61 @@
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
from pymongo.database import Database
|
from pymongo.database import Database
|
||||||
from pymongo.collection import Collection
|
from pymongo.collection import Collection
|
||||||
|
from bson import ObjectId, errors as bson_errors
|
||||||
from models.entities import SubjectEntity
|
from models.entities import SubjectEntity
|
||||||
from bson import ObjectId
|
|
||||||
|
|
||||||
|
|
||||||
class SubjectRepository:
|
class SubjectRepository:
|
||||||
|
COLLECTION_NAME = "subjects"
|
||||||
|
|
||||||
def __init__(self, db: Database):
|
def __init__(self, db: Database):
|
||||||
self.collection: Collection = db.subjects
|
self.collection: Collection = db[self.COLLECTION_NAME]
|
||||||
|
|
||||||
def create(self, subject: SubjectEntity) -> str:
|
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)
|
result = self.collection.insert_one(subject_dict)
|
||||||
return str(result.inserted_id)
|
return str(result.inserted_id)
|
||||||
|
|
||||||
def get_all(self) -> List[SubjectEntity]:
|
def get_all(self) -> List[SubjectEntity]:
|
||||||
cursor = self.collection.find({})
|
return [SubjectEntity(**doc) for doc in self.collection.find()]
|
||||||
return [SubjectEntity(**doc) for doc in cursor]
|
|
||||||
|
|
||||||
def get_by_id(self, subject_id: str) -> Optional[SubjectEntity]:
|
def get_by_id(self, subject_id: str) -> Optional[SubjectEntity]:
|
||||||
doc = self.collection.find_one({"_id": ObjectId(subject_id)})
|
try:
|
||||||
if doc:
|
oid = ObjectId(subject_id)
|
||||||
return SubjectEntity(**doc)
|
except bson_errors.InvalidId:
|
||||||
return None
|
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:
|
def update(self, subject_id: str, update_data: dict) -> bool:
|
||||||
result = self.collection.update_one(
|
try:
|
||||||
{"_id": ObjectId(subject_id)}, {"$set": update_data}
|
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
|
return result.modified_count > 0
|
||||||
|
|
||||||
def delete(self, subject_id: str) -> bool:
|
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
|
return result.deleted_count > 0
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
class AnswerItemSchema(BaseModel):
|
class AnswerItemSchema(BaseModel):
|
||||||
question_index: int
|
question_index: int
|
||||||
answer: str
|
answer: Union[str | int | bool]
|
||||||
is_correct: bool
|
is_correct: bool
|
||||||
time_spent: float
|
time_spent: float
|
||||||
|
|
|
@ -8,5 +8,6 @@ class QuizCreateSchema(BaseModel):
|
||||||
title: str
|
title: str
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
is_public: bool = False
|
is_public: bool = False
|
||||||
|
subject_id: str
|
||||||
author_id: Optional[str] = None
|
author_id: Optional[str] = None
|
||||||
question_listings: Optional[List[QuestionItemSchema]] = []
|
question_listings: Optional[List[QuestionItemSchema]] = []
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import List, Optional
|
from typing import List, Optional, Union
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@ class QuestionResult(BaseModel):
|
||||||
index: int
|
index: int
|
||||||
question: str
|
question: str
|
||||||
type: str
|
type: str
|
||||||
target_answer: str
|
target_answer: Union[str | bool | int]
|
||||||
user_answer: Optional[str]
|
user_answer: Optional[Union[str | bool | int]]
|
||||||
is_correct: Optional[bool]
|
is_correct: Optional[bool]
|
||||||
time_spent: Optional[float]
|
time_spent: Optional[float]
|
||||||
options: Optional[List[str]]
|
options: Optional[List[str]]
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
from typing import List
|
from typing import List
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from schemas.response import QuizGetSchema
|
from schemas.response.recomendation.recomendation_response_schema import (
|
||||||
|
RecomendationResponse,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserQuizListResponse(BaseModel):
|
class UserQuizListResponse(BaseModel):
|
||||||
total: int
|
total: int
|
||||||
quizzes: List[QuizGetSchema]
|
quizzes: List[RecomendationResponse]
|
||||||
|
|
|
@ -7,6 +7,8 @@ from .question_item_schema import QuestionItemSchema
|
||||||
class QuizGetSchema(BaseModel):
|
class QuizGetSchema(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
author_id: str
|
author_id: str
|
||||||
|
subject_id: str
|
||||||
|
subject_alias: str
|
||||||
title: str
|
title: str
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
is_public: bool = False
|
is_public: bool = False
|
||||||
|
|
|
@ -47,11 +47,13 @@ class AnswerService:
|
||||||
)
|
)
|
||||||
|
|
||||||
correct = False
|
correct = False
|
||||||
if question.type in ["fill_the_blank", "true_false"]:
|
if question.type == "fill_the_blank":
|
||||||
correct = (
|
correct = (
|
||||||
user_answer.answer.strip().lower()
|
user_answer.answer.strip().lower()
|
||||||
== question.target_answer.strip().lower()
|
== question.target_answer.strip().lower()
|
||||||
)
|
)
|
||||||
|
elif question.type == "true_false":
|
||||||
|
correct = user_answer.answer == question.target_answer
|
||||||
elif question.type == "option":
|
elif question.type == "option":
|
||||||
try:
|
try:
|
||||||
answer_index = int(user_answer.answer)
|
answer_index = int(user_answer.answer)
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
from models import QuizEntity
|
from repositories import QuizRepository, UserRepository, SubjectRepository
|
||||||
from repositories import QuizRepository, UserRepository
|
|
||||||
from schemas import QuizGetSchema
|
|
||||||
from schemas.requests import QuizCreateSchema
|
from schemas.requests import QuizCreateSchema
|
||||||
from schemas.response import UserQuizListResponse, RecomendationResponse
|
from schemas.response import UserQuizListResponse, RecomendationResponse, QuizGetSchema
|
||||||
from exception import DataNotFoundException
|
from exception import DataNotFoundException
|
||||||
from mapper import QuizMapper
|
from mapper import QuizMapper
|
||||||
from exception import ValidationException
|
from exception import ValidationException
|
||||||
|
@ -10,15 +8,23 @@ from helpers import DatetimeUtil
|
||||||
|
|
||||||
|
|
||||||
class QuizService:
|
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.quiz_repository = quiz_repository
|
||||||
self.user_repostory = user_repository
|
self.user_repostory = user_repository
|
||||||
|
self.subject_repository = subject_repository
|
||||||
|
|
||||||
def get_quiz(self, quiz_id) -> QuizGetSchema:
|
def get_quiz(self, quiz_id) -> QuizGetSchema:
|
||||||
data = self.quiz_repository.get_by_id(quiz_id)
|
data = self.quiz_repository.get_by_id(quiz_id)
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
raise DataNotFoundException("Quiz not found")
|
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(
|
def search_quiz(
|
||||||
self, keyword: str, page: int = 1, page_size: int = 10
|
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
|
self, user_id: str, page: int = 1, page_size: int = 10
|
||||||
) -> UserQuizListResponse:
|
) -> UserQuizListResponse:
|
||||||
quizzes = self.quiz_repository.get_by_user_id(user_id, page, page_size)
|
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)
|
total_user_quiz = self.quiz_repository.count_by_user_id(user_id)
|
||||||
return UserQuizListResponse(
|
|
||||||
total=total_user_quiz,
|
print(total_user_quiz)
|
||||||
quizzes=[QuizMapper.map_quiz_entity_to_schema(quiz) for quiz in quizzes],
|
|
||||||
)
|
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):
|
def create_quiz(self, quiz_data: QuizCreateSchema):
|
||||||
total_time = 0
|
total_time = 0
|
||||||
|
|
Loading…
Reference in New Issue