feat: adding recomendation
This commit is contained in:
parent
a099da34f4
commit
faf6a0f4b9
|
@ -56,14 +56,25 @@ def get_answer(controller: QuizController = Provide[Container.quiz_controller]):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@quiz_bp.route("/recomendation", methods=["GET"])
|
@quiz_bp.route("/populer", methods=["GET"])
|
||||||
@inject
|
@inject
|
||||||
def get_quiz_recommendation(
|
def get_quiz_populer(
|
||||||
controller: QuizController = Provide[Container.quiz_controller],
|
controller: QuizController = Provide[Container.quiz_controller],
|
||||||
):
|
):
|
||||||
page = request.args.get("page")
|
page = request.args.get("page")
|
||||||
limit = request.args.get("limit")
|
limit = request.args.get("limit")
|
||||||
return controller.get_quiz_recommendation(page=page, limit=limit)
|
return controller.get_quiz_populer(page=page, limit=limit)
|
||||||
|
|
||||||
|
|
||||||
|
@quiz_bp.route("/recommendation", methods=["GET"])
|
||||||
|
@inject
|
||||||
|
def get_quiz_recommendation(
|
||||||
|
controller: QuizController = Provide[Container.quiz_controller],
|
||||||
|
):
|
||||||
|
user_id = request.args.get("user_id")
|
||||||
|
page = request.args.get("page")
|
||||||
|
limit = request.args.get("limit")
|
||||||
|
return controller.get_quiz_recommendation(user_id=user_id, page=page, limit=limit)
|
||||||
|
|
||||||
|
|
||||||
@quiz_bp.route("/user/<user_id>", methods=["GET"])
|
@quiz_bp.route("/user/<user_id>", methods=["GET"])
|
||||||
|
|
|
@ -43,9 +43,9 @@ class QuizController:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return make_error_response(e)
|
return make_error_response(e)
|
||||||
|
|
||||||
def quiz_recomendation(self):
|
def quiz_populer(self):
|
||||||
try:
|
try:
|
||||||
result = self.quiz_service.get_quiz_recommendation()
|
result = self.quiz_service.get_quiz_populer()
|
||||||
if not result:
|
if not result:
|
||||||
return make_response(message="Quiz not found", status_code=404)
|
return make_response(message="Quiz not found", status_code=404)
|
||||||
return make_response(message="Quiz Found", data=result.model_dump())
|
return make_response(message="Quiz Found", data=result.model_dump())
|
||||||
|
@ -94,14 +94,33 @@ class QuizController:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return make_error_response(e)
|
return make_error_response(e)
|
||||||
|
|
||||||
def get_quiz_recommendation(self, page, limit):
|
def get_quiz_populer(self, page, limit):
|
||||||
try:
|
try:
|
||||||
page = int(page) if page is not None else 1
|
page = int(page) if page is not None else 1
|
||||||
limit = int(limit) if limit is not None else 3
|
limit = int(limit) if limit is not None else 3
|
||||||
result = self.quiz_service.get_quiz_recommendation(page=page, limit=limit)
|
result = self.quiz_service.get_quiz_populer(page=page, limit=limit)
|
||||||
|
return make_response(message="success retrieve populer quiz", data=result)
|
||||||
|
except DataNotFoundException as e:
|
||||||
|
return make_response(message=e.message, status_code=e.status_code)
|
||||||
|
except ValueError as e:
|
||||||
|
return make_response(message=str(e), data=None, status_code=400)
|
||||||
|
except ValidationError as e:
|
||||||
return make_response(
|
return make_response(
|
||||||
message="success retrieve recommendation quiz", data=result
|
message="validation error", data=json.loads(e.json()), status_code=400
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return make_error_response(e)
|
||||||
|
|
||||||
|
def get_quiz_recommendation(self, user_id, page, limit):
|
||||||
|
try:
|
||||||
|
page = int(page) if page is not None else 1
|
||||||
|
limit = int(limit) if limit is not None else 3
|
||||||
|
result = self.quiz_service.get_quiz_recommendation(
|
||||||
|
user_id=user_id,
|
||||||
|
page=page,
|
||||||
|
limit=limit,
|
||||||
|
)
|
||||||
|
return make_response(message="success retrieve populer quiz", data=result)
|
||||||
except DataNotFoundException as e:
|
except DataNotFoundException as e:
|
||||||
return make_response(message=e.message, status_code=e.status_code)
|
return make_response(message=e.message, status_code=e.status_code)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
|
|
|
@ -75,6 +75,7 @@ class Container(containers.DeclarativeContainer):
|
||||||
quiz_repository,
|
quiz_repository,
|
||||||
user_repository,
|
user_repository,
|
||||||
subject_repository,
|
subject_repository,
|
||||||
|
answer_repository,
|
||||||
)
|
)
|
||||||
answer_service = providers.Factory(
|
answer_service = providers.Factory(
|
||||||
AnswerService,
|
AnswerService,
|
||||||
|
|
|
@ -76,7 +76,7 @@ class QuizMapper:
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def quiz_to_recomendation_mapper(
|
def quiz_to_populer_mapper(
|
||||||
quiz_entity: QuizEntity,
|
quiz_entity: QuizEntity,
|
||||||
user_entity: UserEntity,
|
user_entity: UserEntity,
|
||||||
) -> ListingQuizResponse:
|
) -> ListingQuizResponse:
|
||||||
|
|
|
@ -14,8 +14,9 @@ class QuizEntity(BaseModel):
|
||||||
is_public: bool = False
|
is_public: bool = False
|
||||||
date: datetime
|
date: datetime
|
||||||
total_quiz: int = 0
|
total_quiz: int = 0
|
||||||
limit_duration: Optional[int] = 0 # in
|
limit_duration: Optional[int] = 0
|
||||||
total_user_playing: int = 0
|
total_user_playing: int = 0
|
||||||
|
language_code: Optional[str] = "id"
|
||||||
question_listings: Optional[list[QuestionItemEntity]] = []
|
question_listings: Optional[list[QuestionItemEntity]] = []
|
||||||
|
|
||||||
class ConfigDict:
|
class ConfigDict:
|
||||||
|
|
|
@ -20,34 +20,6 @@ class QuizRepository:
|
||||||
return QuizEntity(**data)
|
return QuizEntity(**data)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# def search_by_title_or_category(
|
|
||||||
# self, keyword: str, page: int, page_size: int
|
|
||||||
# ) -> List[QuizEntity]:
|
|
||||||
# skip = (page - 1) * page_size
|
|
||||||
# pipeline = [
|
|
||||||
# {
|
|
||||||
# "$lookup": {
|
|
||||||
# "from": "category",
|
|
||||||
# "localField": "category_id",
|
|
||||||
# "foreignField": "_id",
|
|
||||||
# "as": "category_info",
|
|
||||||
# }
|
|
||||||
# },
|
|
||||||
# {"$unwind": "$category_info"},
|
|
||||||
# {
|
|
||||||
# "$match": {
|
|
||||||
# "$or": [
|
|
||||||
# {"title": {"$regex": keyword, "$options": "i"}},
|
|
||||||
# {"category_info.name": {"$regex": keyword, "$options": "i"}},
|
|
||||||
# ]
|
|
||||||
# }
|
|
||||||
# },
|
|
||||||
# {"$skip": skip},
|
|
||||||
# {"$limit": page_size},
|
|
||||||
# ]
|
|
||||||
# cursor = self.collection.aggregate(pipeline)
|
|
||||||
# return [QuizEntity(**doc) for doc in cursor]
|
|
||||||
|
|
||||||
def search_by_title_or_category(
|
def search_by_title_or_category(
|
||||||
self, keyword: str, subject_id: Optional[str], page: int, page_size: int
|
self, keyword: str, subject_id: Optional[str], page: int, page_size: int
|
||||||
) -> List[QuizEntity]:
|
) -> List[QuizEntity]:
|
||||||
|
@ -87,7 +59,6 @@ class QuizRepository:
|
||||||
cursor = self.collection.find({"_id": {"$in": object_ids}})
|
cursor = self.collection.find({"_id": {"$in": object_ids}})
|
||||||
datas = list(cursor)
|
datas = list(cursor)
|
||||||
|
|
||||||
|
|
||||||
if not datas:
|
if not datas:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -137,3 +108,13 @@ class QuizRepository:
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
)
|
)
|
||||||
return [QuizEntity(**doc) for doc in cursor]
|
return [QuizEntity(**doc) for doc in cursor]
|
||||||
|
|
||||||
|
def get_random_quizzes_by_subjects(
|
||||||
|
self, subject_ids: List[str], limit: int = 3
|
||||||
|
) -> List[QuizEntity]:
|
||||||
|
pipeline = [
|
||||||
|
{"$match": {"subject_id": {"$in": subject_ids}, "is_public": True}},
|
||||||
|
{"$sample": {"size": limit}},
|
||||||
|
]
|
||||||
|
cursor = self.collection.aggregate(pipeline)
|
||||||
|
return [QuizEntity(**doc) for doc in cursor]
|
||||||
|
|
|
@ -4,11 +4,11 @@ from .quiz.question_item_schema import QuestionItemSchema
|
||||||
from .quiz.quiz_data_rsp_schema import UserQuizListResponse
|
from .quiz.quiz_data_rsp_schema import UserQuizListResponse
|
||||||
from .history.history_response import HistoryResultSchema
|
from .history.history_response import HistoryResultSchema
|
||||||
from .history.detail_history_response import QuizHistoryResponse, QuestionResult
|
from .history.detail_history_response import QuizHistoryResponse, QuestionResult
|
||||||
from .recomendation.recomendation_response_schema import ListingQuizResponse
|
|
||||||
from .subject.get_subject_schema import GetSubjectResponse
|
from .subject.get_subject_schema import GetSubjectResponse
|
||||||
from .auth.login_response import LoginResponseSchema
|
from .auth.login_response import LoginResponseSchema
|
||||||
from .user.user_response_scema import UserResponseSchema
|
from .user.user_response_scema import UserResponseSchema
|
||||||
from .answer.answer_session_response import AnsweredQuizResponse
|
from .answer.answer_session_response import AnsweredQuizResponse
|
||||||
|
from .recomendation.recomendation_response_schema import ListingQuizResponse
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"QuizCreationResponse",
|
"QuizCreationResponse",
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
from typing import List
|
from typing import List
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from app.schemas.response.recomendation.recomendation_response_schema import (
|
from ..recomendation.recomendation_response_schema import ListingQuizResponse
|
||||||
ListingQuizResponse,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class UserQuizListResponse(BaseModel):
|
class UserQuizListResponse(BaseModel):
|
||||||
|
|
|
@ -1,25 +1,34 @@
|
||||||
from app.repositories import QuizRepository, UserRepository, SubjectRepository
|
from app.repositories import (
|
||||||
|
QuizRepository,
|
||||||
|
UserRepository,
|
||||||
|
SubjectRepository,
|
||||||
|
UserAnswerRepository,
|
||||||
|
)
|
||||||
from app.schemas.requests import QuizCreateSchema
|
from app.schemas.requests import QuizCreateSchema
|
||||||
from app.schemas.response import (
|
from app.schemas.response import (
|
||||||
UserQuizListResponse,
|
UserQuizListResponse,
|
||||||
ListingQuizResponse,
|
|
||||||
QuizGetSchema,
|
QuizGetSchema,
|
||||||
|
ListingQuizResponse,
|
||||||
)
|
)
|
||||||
from app.exception import DataNotFoundException, ValidationException
|
from app.exception import DataNotFoundException, ValidationException
|
||||||
from app.mapper import QuizMapper
|
from app.mapper import QuizMapper
|
||||||
from app.helpers import DatetimeUtil
|
from app.helpers import DatetimeUtil
|
||||||
|
|
||||||
|
from flask import current_app
|
||||||
|
|
||||||
|
|
||||||
class QuizService:
|
class QuizService:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
quiz_repository=QuizRepository,
|
quiz_repository: QuizRepository,
|
||||||
user_repository=UserRepository,
|
user_repository: UserRepository,
|
||||||
subject_repository=SubjectRepository,
|
subject_repository: SubjectRepository,
|
||||||
|
answer_repository: UserAnswerRepository,
|
||||||
):
|
):
|
||||||
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
|
self.subject_repository = subject_repository
|
||||||
|
self.answer_repository = answer_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)
|
||||||
|
@ -46,7 +55,7 @@ class QuizService:
|
||||||
if author is None:
|
if author is None:
|
||||||
continue
|
continue
|
||||||
mapped_quizzes.append(
|
mapped_quizzes.append(
|
||||||
QuizMapper.quiz_to_recomendation_mapper(
|
QuizMapper.quiz_to_populer_mapper(
|
||||||
quiz_entity=quiz,
|
quiz_entity=quiz,
|
||||||
user_entity=author,
|
user_entity=author,
|
||||||
)
|
)
|
||||||
|
@ -63,13 +72,9 @@ class QuizService:
|
||||||
|
|
||||||
total_user_quiz = self.quiz_repository.count_by_user_id(user_id)
|
total_user_quiz = self.quiz_repository.count_by_user_id(user_id)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
user = self.user_repostory.get_user_by_id(user_id)
|
user = self.user_repostory.get_user_by_id(user_id)
|
||||||
|
|
||||||
quiz_data = [
|
quiz_data = [QuizMapper.quiz_to_populer_mapper(quiz, user) for quiz in quizzes]
|
||||||
QuizMapper.quiz_to_recomendation_mapper(quiz, user) for quiz in quizzes
|
|
||||||
]
|
|
||||||
|
|
||||||
return UserQuizListResponse(total=total_user_quiz, quizzes=quiz_data)
|
return UserQuizListResponse(total=total_user_quiz, quizzes=quiz_data)
|
||||||
|
|
||||||
|
@ -100,7 +105,7 @@ class QuizService:
|
||||||
def delete_quiz(self, quiz_id):
|
def delete_quiz(self, quiz_id):
|
||||||
return self.quiz_repository.delete(quiz_id)
|
return self.quiz_repository.delete(quiz_id)
|
||||||
|
|
||||||
def get_quiz_recommendation(self, page: int, limit: int):
|
def get_quiz_populer(self, page: int, limit: int):
|
||||||
|
|
||||||
data = self.quiz_repository.get_top_played_quizzes(page=page, limit=limit)
|
data = self.quiz_repository.get_top_played_quizzes(page=page, limit=limit)
|
||||||
if not data:
|
if not data:
|
||||||
|
@ -110,9 +115,30 @@ class QuizService:
|
||||||
for quiz in data:
|
for quiz in data:
|
||||||
author = self.user_repostory.get_user_by_id(user_id=quiz.author_id)
|
author = self.user_repostory.get_user_by_id(user_id=quiz.author_id)
|
||||||
result.append(
|
result.append(
|
||||||
QuizMapper.quiz_to_recomendation_mapper(
|
QuizMapper.quiz_to_populer_mapper(
|
||||||
quiz_entity=quiz,
|
quiz_entity=quiz,
|
||||||
user_entity=author,
|
user_entity=author,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def get_quiz_recommendation(self, user_id: str, page: int, limit: int):
|
||||||
|
current_app.logger.info("in here is should execute")
|
||||||
|
user_answer = self.answer_repository.get_by_user(user_id=user_id)
|
||||||
|
|
||||||
|
if not user_answer:
|
||||||
|
return []
|
||||||
|
|
||||||
|
quiz_ids = list({answer.quiz_id for answer in user_answer})
|
||||||
|
quiz_work = self.quiz_repository.get_by_ids(quiz_ids)
|
||||||
|
|
||||||
|
if not quiz_work:
|
||||||
|
return []
|
||||||
|
|
||||||
|
quiz_subjects = list({quiz.subject_id for quiz in quiz_work})
|
||||||
|
|
||||||
|
result = self.quiz_repository.get_random_quizzes_by_subjects(
|
||||||
|
subject_ids=quiz_subjects, limit=limit
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
|
@ -225,7 +225,7 @@ paths:
|
||||||
"404":
|
"404":
|
||||||
$ref: "#/components/responses/NotFound"
|
$ref: "#/components/responses/NotFound"
|
||||||
|
|
||||||
/quiz/recomendation:
|
/quiz/populer:
|
||||||
get:
|
get:
|
||||||
summary: Get recommended quizzes
|
summary: Get recommended quizzes
|
||||||
description: Returns a list of recommended quizzes for the user
|
description: Returns a list of recommended quizzes for the user
|
||||||
|
@ -235,7 +235,7 @@ paths:
|
||||||
- $ref: "#/components/parameters/LimitParam"
|
- $ref: "#/components/parameters/LimitParam"
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: Successfully retrieved recommendation quiz list
|
description: Successfully retrieved populer quiz list
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
|
@ -243,7 +243,7 @@ paths:
|
||||||
properties:
|
properties:
|
||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
example: success retrieve recommendation quiz
|
example: success retrieve populer quiz
|
||||||
data:
|
data:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
|
|
@ -114,7 +114,7 @@
|
||||||
# assert result.quizzes == []
|
# assert result.quizzes == []
|
||||||
|
|
||||||
|
|
||||||
# def test_get_quiz_recommendation_found(quiz_service, mock_repositories):
|
# def test_get_quiz_populer_found(quiz_service, mock_repositories):
|
||||||
# quiz = QuizEntity(
|
# quiz = QuizEntity(
|
||||||
# id=ObjectId(),
|
# id=ObjectId(),
|
||||||
# author_id="user1",
|
# author_id="user1",
|
||||||
|
@ -131,14 +131,14 @@
|
||||||
# mock_repositories["quiz_repository"].get_top_played_quizzes.return_value = [quiz]
|
# mock_repositories["quiz_repository"].get_top_played_quizzes.return_value = [quiz]
|
||||||
# mock_repositories["user_repository"].get_user_by_id.return_value = MagicMock()
|
# mock_repositories["user_repository"].get_user_by_id.return_value = MagicMock()
|
||||||
|
|
||||||
# result = quiz_service.get_quiz_recommendation(1, 5)
|
# result = quiz_service.get_quiz_populer(1, 5)
|
||||||
# assert len(result) == 1
|
# assert len(result) == 1
|
||||||
|
|
||||||
|
|
||||||
# def test_get_quiz_recommendation_not_found(quiz_service, mock_repositories):
|
# def test_get_quiz_populer_not_found(quiz_service, mock_repositories):
|
||||||
# mock_repositories["quiz_repository"].get_top_played_quizzes.return_value = []
|
# mock_repositories["quiz_repository"].get_top_played_quizzes.return_value = []
|
||||||
# with pytest.raises(DataNotFoundException):
|
# with pytest.raises(DataNotFoundException):
|
||||||
# quiz_service.get_quiz_recommendation(1, 5)
|
# quiz_service.get_quiz_populer(1, 5)
|
||||||
|
|
||||||
|
|
||||||
# def test_update_quiz(quiz_service, mock_repositories):
|
# def test_update_quiz(quiz_service, mock_repositories):
|
||||||
|
|
Loading…
Reference in New Issue