from app.repositories import UserAnswerRepository, QuizRepository, UserRepository from app.schemas.requests import UserAnswerSchema from app.schemas.response import AnsweredQuizResponse from app.models import UserAnswerEntity from app.models.entities import AnswerItemEntity from app.exception import ValidationException from app.helpers import DatetimeUtil class AnswerService: def __init__( self, answer_repository: UserAnswerRepository, quiz_repository: QuizRepository, user_repositroy: UserRepository, ): self.answer_repository = answer_repository self.quiz_repository = quiz_repository self.user_repositroy = user_repositroy def get_answer_by_id(self, answer_id): return self.answer_repository.get_answer_by_id(answer_id) def get_answer(self, quiz_id, user_id, session_id): if quiz_id is not None: return self.answer_repository def create_answer(self, answer_data: UserAnswerSchema): quiz_data = self.quiz_repository.get_by_id(answer_data.quiz_id) if not quiz_data: raise ValidationException(message="Quiz not found") user_data = self.user_repositroy.get_user_by_id(answer_data.user_id) if not user_data: raise ValidationException(message="user is not registered") total_quiz_played = quiz_data.total_user_playing + 1 self.quiz_repository.update_user_playing( quiz_id=quiz_data.id, total_user=total_quiz_played ) question_map = {q.index: q for q in quiz_data.question_listings} answer_item_Entity = [] total_correct = 0 for user_answer in answer_data.answers: question = question_map.get(user_answer.question_index) if question is None: raise ValueError( f"Question index {user_answer.question_index} tidak ditemukan di kuis." ) correct = 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": answer_index = int(user_answer.answer) if 0 <= answer_index < len(question.options): correct = answer_index == question.target_answer else: raise ValueError( f"Index jawaban tidak valid untuk soal {question.index}" ) else: raise ValueError(f"Tipe soal tidak dikenali: {question.type}") user_answer.is_correct = correct if correct: total_correct += 1 answer_item_Entity.append( AnswerItemEntity( question_index=user_answer.question_index, answer=user_answer.answer, is_correct=user_answer.is_correct, time_spent=user_answer.time_spent, ) ) total_questions = len(quiz_data.question_listings) total_score = total_correct * 100 // total_questions answer_entity = UserAnswerEntity( session_id=answer_data.session_id, quiz_id=answer_data.quiz_id, user_id=answer_data.user_id, answered_at=answer_data.answered_at, answers=answer_item_Entity, total_correct=total_correct, total_questions=total_questions, total_score=total_score, ) return self.answer_repository.create(answer_entity) def update_answer(self, answer_id, answer_data): return self.answer_repository.update(answer_id, answer_data) def delete_answer(self, answer_id): return self.answer_repository.delete_by_id(answer_id) def get_answer_session(self, session_id: str, user_id: str) -> AnsweredQuizResponse: answer_data: UserAnswerEntity = ( self.answer_repository.get_by_userid_and_sessionid( session_id=session_id, user_id=user_id, ) ) if not answer_data: return None quiz = self.quiz_repository.get_by_id(answer_data.quiz_id) question_listings = quiz.question_listings # List[QuestionItemEntity] # Mapping question_index ke QuestionItemEntity question_map = {q.index: q for q in question_listings} answers_data = [] for ans in answer_data.answers: question_entity = question_map.get(ans.question_index) question_fields = question_entity.dict() if question_entity else {} answers_data.append( { **question_fields, # Langsung unpack semua field QuestionItemEntity ke dalam dictionary "answer": ans.answer, "is_correct": ans.is_correct, "time_spent": ans.time_spent, } ) data = AnsweredQuizResponse( id=str(answer_data.id), session_id=answer_data.session_id, quiz_id=answer_data.quiz_id, user_id=answer_data.user_id, answered_at=DatetimeUtil.to_string(answer_data.answered_at), answers=answers_data, total_score=answer_data.total_score, total_correct=answer_data.total_correct, ) return data