From 417c2e017c6d336c9a59150916fd45f72a43d78c Mon Sep 17 00:00:00 2001 From: akhdanre Date: Wed, 30 Apr 2025 23:46:40 +0700 Subject: [PATCH] feat: working on the detail history" --- app/blueprints/history.py | 8 ++++ app/controllers/history_controller.py | 9 +++++ app/main.py | 4 +- app/repositories/answer_repository.py | 6 ++- app/schemas/response/__init__.py | 3 ++ .../history/detail_history_response.py | 27 +++++++++++++ app/services/history_service.py | 40 ++++++++++++++++++- 7 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 app/schemas/response/history/detail_history_response.py diff --git a/app/blueprints/history.py b/app/blueprints/history.py index bf32497..5a06955 100644 --- a/app/blueprints/history.py +++ b/app/blueprints/history.py @@ -12,3 +12,11 @@ def user_history( user_id: str, controller: HistoryController = Provide[Container.history_controller] ): return controller.get_quiz_by_user(user_id) + + +@history_blueprint.route("/detail/", methods=["GET"]) +@inject +def user_detail_history( + answer_id, controller: HistoryController = Provide[Container.history_controller] +): + return controller.get_detail_quiz_history(answer_id) diff --git a/app/controllers/history_controller.py b/app/controllers/history_controller.py index 6ed3e83..b08e719 100644 --- a/app/controllers/history_controller.py +++ b/app/controllers/history_controller.py @@ -13,3 +13,12 @@ class HistoryController: return make_response(message="retrive history data", data=data) except Exception as e: return make_error_response(e) + + def get_detail_quiz_history(self, answer_id: str): + try: + data = self.history_service.get_history_by_answer_id(answer_id) + return make_response( + message="success retrive detail history data", data=data + ) + except Exception as e: + return make_error_response(e) diff --git a/app/main.py b/app/main.py index b0ed641..32a3940 100644 --- a/app/main.py +++ b/app/main.py @@ -54,8 +54,8 @@ def createApp() -> Flask: app.register_blueprint(quiz_bp, url_prefix="/api/quiz") app.register_blueprint(history_blueprint, url_prefix="/api/history") - for rule in app.url_map.iter_rules(): - print(f"Route: {rule} -> Methods: {rule.methods}") + # for rule in app.url_map.iter_rules(): + # print(f"Route: {rule} -> Methods: {rule.methods}") return app diff --git a/app/repositories/answer_repository.py b/app/repositories/answer_repository.py index 0dd8363..91c7b40 100644 --- a/app/repositories/answer_repository.py +++ b/app/repositories/answer_repository.py @@ -13,9 +13,11 @@ class UserAnswerRepository: result = self.collection.insert_one(data) return str(result.inserted_id) - def get_by_id(self, id: str) -> Optional[dict]: + def get_by_id(self, id: str) -> Optional[UserAnswerEntity]: result = self.collection.find_one({"_id": ObjectId(id)}) - return result + if not result: + return None + return UserAnswerEntity(**result) def get_by_user_and_quiz(self, user_id: str, quiz_id: str) -> List[dict]: result = self.collection.find( diff --git a/app/schemas/response/__init__.py b/app/schemas/response/__init__.py index 42da729..458792c 100644 --- a/app/schemas/response/__init__.py +++ b/app/schemas/response/__init__.py @@ -3,6 +3,7 @@ from .quiz.quiz_get_response import QuizGetSchema from .quiz.question_item_schema import QuestionItemSchema from .quiz.quiz_data_rsp_schema import UserQuizListResponse from .history.history_response import HistoryResultSchema +from .history.detail_history_response import QuizHistoryResponse, QuestionResult __all__ = [ "QuizCreationResponse", @@ -10,4 +11,6 @@ __all__ = [ "QuestionItemSchema", "UserQuizListResponse", "HistoryResultSchema", + "QuizHistoryResponse", + "QuestionResult", ] diff --git a/app/schemas/response/history/detail_history_response.py b/app/schemas/response/history/detail_history_response.py new file mode 100644 index 0000000..60cfd53 --- /dev/null +++ b/app/schemas/response/history/detail_history_response.py @@ -0,0 +1,27 @@ +from typing import List, Optional +from pydantic import BaseModel +from datetime import datetime + + +class QuestionResult(BaseModel): + index: int + question: str + type: str + target_answer: str + user_answer: Optional[str] + is_correct: Optional[bool] + time_spent: Optional[float] + options: Optional[List[str]] + + +class QuizHistoryResponse(BaseModel): + answer_id: str + quiz_id: str + title: str + description: str + author_id: str + answered_at: str + total_correct: int + total_score: int + total_solve_time: float + question_listings: List[QuestionResult] diff --git a/app/services/history_service.py b/app/services/history_service.py index 57440c9..57ab51f 100644 --- a/app/services/history_service.py +++ b/app/services/history_service.py @@ -1,5 +1,5 @@ from repositories import UserAnswerRepository, QuizRepository -from schemas.response import HistoryResultSchema +from schemas.response import HistoryResultSchema, QuizHistoryResponse, QuestionResult class HistoryService: @@ -37,3 +37,41 @@ class HistoryService: ) return result + + def get_history_by_answer_id(self, answer_id: str): + answer = self.answer_repository.get_by_id(answer_id) + quiz = self.quiz_repository.get_by_id(answer.quiz_id) + + total_solve_time = sum([a.time_spent for a in answer.answers]) + + question_results = [] + for q in quiz.question_listings: + user_answer = next( + (a for a in answer.answers if a.question_index == q.index), None + ) + question_results.append( + QuestionResult( + index=q.index, + question=q.question, + type=q.type, + target_answer=q.target_answer, + user_answer=user_answer.answer if user_answer else None, + is_correct=user_answer.is_correct if user_answer else None, + time_spent=user_answer.time_spent if user_answer else None, + options=q.options, + ) + ) + + result = QuizHistoryResponse( + answer_id=str(answer.id), + quiz_id=str(quiz.id), + title=quiz.title, + description=quiz.description, + author_id=quiz.author_id, + answered_at=answer.answered_at.strftime("%d-%B-%Y"), + total_correct=answer.total_correct, + total_score=answer.total_score, + total_solve_time=total_solve_time, + question_listings=question_results, + ) + return result