feat: new subject request
This commit is contained in:
parent
a2df303e02
commit
ad00d2b9de
|
@ -4,6 +4,7 @@ from .auth import auth_blueprint
|
|||
from .user import user_blueprint
|
||||
from .quiz import quiz_bp
|
||||
from .history import history_blueprint
|
||||
from .subject import subject_blueprint
|
||||
|
||||
__all__ = [
|
||||
"default_blueprint",
|
||||
|
@ -11,6 +12,7 @@ __all__ = [
|
|||
"user_blueprint",
|
||||
"quiz_bp",
|
||||
"history_blueprint",
|
||||
"subject_blueprint",
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
from flask import Blueprint, request
|
||||
from di_container import Container
|
||||
from dependency_injector.wiring import inject, Provide
|
||||
from controllers import SubjectController
|
||||
|
||||
|
||||
subject_blueprint = Blueprint("subject", __name__)
|
||||
|
||||
|
||||
@subject_blueprint.route("", methods=["POST"])
|
||||
@inject
|
||||
def create_subject(
|
||||
controller: SubjectController = Provide[Container.subject_controller],
|
||||
):
|
||||
return controller.create(request.get_json())
|
||||
|
||||
|
||||
@subject_blueprint.route("", methods=["GET"])
|
||||
@inject
|
||||
def get_all_subjects(
|
||||
controller: SubjectController = Provide[Container.subject_controller],
|
||||
):
|
||||
return controller.get_all()
|
||||
|
||||
|
||||
@subject_blueprint.route("/<subject_id>", methods=["GET"])
|
||||
@inject
|
||||
def get_subject(
|
||||
subject_id: str,
|
||||
controller: SubjectController = Provide[Container.subject_controller],
|
||||
):
|
||||
return controller.get_by_id(subject_id)
|
||||
|
||||
|
||||
@subject_blueprint.route("/<subject_id>", methods=["PUT"])
|
||||
@inject
|
||||
def update_subject(
|
||||
subject_id: str,
|
||||
controller: SubjectController = Provide[Container.subject_controller],
|
||||
):
|
||||
return controller.update(subject_id, request.get_json())
|
||||
|
||||
|
||||
@subject_blueprint.route("/<subject_id>", methods=["DELETE"])
|
||||
@inject
|
||||
def delete_subject(
|
||||
subject_id: str,
|
||||
controller: SubjectController = Provide[Container.subject_controller],
|
||||
):
|
||||
return controller.delete(subject_id)
|
|
@ -2,11 +2,12 @@ from .auth_controller import AuthController
|
|||
from .user_controller import UserController
|
||||
from .quiz_controller import QuizController
|
||||
from .history_controller import HistoryController
|
||||
|
||||
from .subject_controller import SubjectController
|
||||
|
||||
__all__ = [
|
||||
"AuthController",
|
||||
"UserController",
|
||||
"QuizController",
|
||||
"HistoryController",
|
||||
"SubjectController",
|
||||
]
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
from services.subject_service import SubjectService
|
||||
from helpers import make_response, make_error_response
|
||||
|
||||
|
||||
class SubjectController:
|
||||
def __init__(self, service: SubjectService):
|
||||
self.service = service
|
||||
|
||||
def create(self, req_body):
|
||||
try:
|
||||
new_id = self.service.create_subject(req_body)
|
||||
return make_response(message="Subject created", data={"id": new_id})
|
||||
except Exception as e:
|
||||
return make_error_response(e)
|
||||
|
||||
def get_all(self):
|
||||
try:
|
||||
subjects = self.service.get_all_subjects()
|
||||
return make_response(message="success retrieve subject", data=subjects)
|
||||
except Exception as e:
|
||||
return make_error_response(e)
|
||||
|
||||
def get_by_id(self, subject_id: str):
|
||||
try:
|
||||
subject = self.service.get_subject_by_id(subject_id)
|
||||
if not subject:
|
||||
return make_response(message="Subject not found", status_code=404)
|
||||
return make_response(data=subject.model_dump())
|
||||
except Exception as e:
|
||||
return make_error_response(e)
|
||||
|
||||
def update(self, subject_id: str, req_body):
|
||||
try:
|
||||
updated = self.service.update_subject(subject_id, req_body)
|
||||
if not updated:
|
||||
return make_response(message="No subject updated", status_code=404)
|
||||
return make_response(message="Subject updated")
|
||||
except Exception as e:
|
||||
return make_error_response(e)
|
||||
|
||||
def delete(self, subject_id: str):
|
||||
try:
|
||||
deleted = self.service.delete_subject(subject_id)
|
||||
if not deleted:
|
||||
return make_response(message="No subject deleted", status_code=404)
|
||||
return make_response(message="Subject deleted")
|
||||
except Exception as e:
|
||||
return make_error_response(e)
|
|
@ -1,5 +1,6 @@
|
|||
from flask_pymongo import PyMongo
|
||||
from flask import Flask, current_app
|
||||
from .seed.subject_seed import seed_subjects
|
||||
|
||||
|
||||
def init_db(app: Flask) -> PyMongo:
|
||||
|
@ -8,8 +9,8 @@ def init_db(app: Flask) -> PyMongo:
|
|||
|
||||
mongo.cx.server_info()
|
||||
app.logger.info("MongoDB connection established")
|
||||
seed_subjects(mongo)
|
||||
return mongo
|
||||
|
||||
except Exception as e:
|
||||
app.logger.error(f"MongoDB connection failed: {e}")
|
||||
return None # Handle failure gracefully
|
||||
return None
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
from flask_pymongo import PyMongo
|
||||
|
||||
|
||||
def seed_subjects(mongo: PyMongo):
|
||||
subject_collection = mongo.db.subjects
|
||||
|
||||
base_subjects = [
|
||||
{
|
||||
"name": "Ilmu Pengetahuan Alam",
|
||||
"short_name": "IPA",
|
||||
"description": "Pelajaran tentang sains dan alam",
|
||||
},
|
||||
{
|
||||
"name": "Ilmu Pengetahuan Sosial",
|
||||
"short_name": "IPS",
|
||||
"description": "Pelajaran tentang masyarakat dan geografi",
|
||||
},
|
||||
{
|
||||
"name": "Sejarah",
|
||||
"short_name": "Sejarah",
|
||||
"description": "Pelajaran mengenai sejarah di indonesia",
|
||||
},
|
||||
{
|
||||
"name": "Matematika",
|
||||
"short_name": "Matematika",
|
||||
"description": "Pelajaran tentang angka dan logika",
|
||||
},
|
||||
{
|
||||
"name": "Bahasa Indonesia",
|
||||
"short_name": "B.Indonesia",
|
||||
"description": "Pelajaran tentang bahasa nasional",
|
||||
},
|
||||
{
|
||||
"name": "Sejarah",
|
||||
"short_name": "Sejarah",
|
||||
"description": "Pelajaran sejarah Indonesia",
|
||||
},
|
||||
]
|
||||
|
||||
for subject in base_subjects:
|
||||
if not subject_collection.find_one({"name": subject["name"]}):
|
||||
subject_collection.insert_one(subject)
|
|
@ -1,17 +1,26 @@
|
|||
from dependency_injector import containers, providers
|
||||
from controllers import (
|
||||
UserController,
|
||||
AuthController,
|
||||
QuizController,
|
||||
HistoryController,
|
||||
from repositories import (
|
||||
UserRepository,
|
||||
QuizRepository,
|
||||
UserAnswerRepository,
|
||||
SubjectRepository,
|
||||
)
|
||||
from repositories import UserRepository, QuizRepository, UserAnswerRepository
|
||||
|
||||
from services import (
|
||||
UserService,
|
||||
AuthService,
|
||||
QuizService,
|
||||
AnswerService,
|
||||
HistoryService,
|
||||
SubjectService,
|
||||
)
|
||||
|
||||
from controllers import (
|
||||
UserController,
|
||||
AuthController,
|
||||
QuizController,
|
||||
HistoryController,
|
||||
SubjectController,
|
||||
)
|
||||
|
||||
|
||||
|
@ -24,10 +33,19 @@ class Container(containers.DeclarativeContainer):
|
|||
user_repository = providers.Factory(UserRepository, mongo.provided.db)
|
||||
quiz_repository = providers.Factory(QuizRepository, mongo.provided.db)
|
||||
answer_repository = providers.Factory(UserAnswerRepository, mongo.provided.db)
|
||||
subject_repository = providers.Factory(SubjectRepository, mongo.provided.db)
|
||||
|
||||
# services
|
||||
auth_service = providers.Factory(AuthService, user_repository)
|
||||
user_service = providers.Factory(UserService, user_repository)
|
||||
auth_service = providers.Factory(
|
||||
AuthService,
|
||||
user_repository,
|
||||
)
|
||||
|
||||
user_service = providers.Factory(
|
||||
UserService,
|
||||
user_repository,
|
||||
)
|
||||
|
||||
quiz_service = providers.Factory(
|
||||
QuizService,
|
||||
quiz_repository,
|
||||
|
@ -46,8 +64,14 @@ class Container(containers.DeclarativeContainer):
|
|||
answer_repository,
|
||||
)
|
||||
|
||||
subject_service = providers.Factory(
|
||||
SubjectService,
|
||||
subject_repository,
|
||||
)
|
||||
|
||||
# controllers
|
||||
auth_controller = providers.Factory(AuthController, user_service, auth_service)
|
||||
user_controller = providers.Factory(UserController, user_service)
|
||||
quiz_controller = providers.Factory(QuizController, quiz_service, answer_service)
|
||||
history_controller = providers.Factory(HistoryController, history_service)
|
||||
subject_controller = providers.Factory(SubjectController, subject_service)
|
||||
|
|
|
@ -12,6 +12,7 @@ from blueprints import (
|
|||
quiz_bp,
|
||||
default_blueprint,
|
||||
history_blueprint,
|
||||
subject_blueprint,
|
||||
)
|
||||
from database import init_db
|
||||
import logging
|
||||
|
@ -34,16 +35,13 @@ def createApp() -> Flask:
|
|||
if mongo is not None:
|
||||
container.mongo.override(mongo)
|
||||
|
||||
# container.wire(modules=["blueprints.auth"])
|
||||
# container.wire(modules=["blueprints.user"])
|
||||
# container.wire(modules=["blueprints.quiz"])
|
||||
|
||||
container.wire(
|
||||
modules=[
|
||||
"blueprints.auth",
|
||||
"blueprints.user",
|
||||
"blueprints.quiz",
|
||||
"blueprints.history",
|
||||
"blueprints.subject",
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -53,6 +51,7 @@ def createApp() -> Flask:
|
|||
app.register_blueprint(user_blueprint, url_prefix="/api")
|
||||
app.register_blueprint(quiz_bp, url_prefix="/api/quiz")
|
||||
app.register_blueprint(history_blueprint, url_prefix="/api/history")
|
||||
app.register_blueprint(subject_blueprint, url_prefix="/api/subject")
|
||||
|
||||
# for rule in app.url_map.iter_rules():
|
||||
# print(f"Route: {rule} -> Methods: {rule.methods}")
|
||||
|
|
|
@ -4,6 +4,7 @@ from .quiz_entity import QuizEntity
|
|||
from .question_item_entity import QuestionItemEntity
|
||||
from .user_answer_entity import UserAnswerEntity
|
||||
from .answer_item import AnswerItemEntity
|
||||
from .subject_entity import SubjectEntity
|
||||
|
||||
__all__ = [
|
||||
"UserEntity",
|
||||
|
@ -11,4 +12,6 @@ __all__ = [
|
|||
"QuizEntity",
|
||||
"QuestionItemEntity",
|
||||
"UserAnswerEntity",
|
||||
"AnswerItemEntity",
|
||||
"SubjectEntity",
|
||||
]
|
||||
|
|
|
@ -10,6 +10,7 @@ class QuizEntity(BaseModel):
|
|||
author_id: Optional[str] = None
|
||||
title: str
|
||||
description: Optional[str] = None
|
||||
subject: str
|
||||
is_public: bool = False
|
||||
date: Optional[datetime] = None
|
||||
total_quiz: Optional[int] = 0
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
from typing import Optional
|
||||
from bson import ObjectId
|
||||
from pydantic import BaseModel, Field
|
||||
from models.entities import PyObjectId
|
||||
|
||||
|
||||
class SubjectEntity(BaseModel):
|
||||
id: Optional[PyObjectId] = Field(default=None, alias="_id")
|
||||
name: str
|
||||
short_name: str
|
||||
description: Optional[str] = None
|
||||
icon: Optional[str] = None
|
||||
|
||||
class Config:
|
||||
populate_by_name = True
|
||||
json_encoders = {ObjectId: str}
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"_id": "sejarah",
|
||||
"name": "Sejarah",
|
||||
"description": "Kuis tentang sejarah Indonesia",
|
||||
"icon": "http://",
|
||||
}
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
from .user_repository import UserRepository
|
||||
from .quiz_repositroy import QuizRepository
|
||||
from .answer_repository import UserAnswerRepository
|
||||
from .subject_repository import SubjectRepository
|
||||
|
||||
__all__ = [
|
||||
"UserRepository",
|
||||
"QuizRepository",
|
||||
"UserAnswerRepository",
|
||||
"SubjectRepository",
|
||||
]
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
from typing import List, Optional
|
||||
from pymongo.database import Database
|
||||
from pymongo.collection import Collection
|
||||
from models.entities import SubjectEntity
|
||||
from bson import ObjectId
|
||||
|
||||
|
||||
class SubjectRepository:
|
||||
def __init__(self, db: Database):
|
||||
self.collection: Collection = db.subjects
|
||||
|
||||
def create(self, subject: SubjectEntity) -> str:
|
||||
subject_dict = subject.dict(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]
|
||||
|
||||
def get_by_id(self, subject_id: str) -> Optional[SubjectEntity]:
|
||||
doc = self.collection.find_one({"_id": ObjectId(subject_id)})
|
||||
if doc:
|
||||
return SubjectEntity(**doc)
|
||||
return None
|
||||
|
||||
def update(self, subject_id: str, update_data: dict) -> bool:
|
||||
result = self.collection.update_one(
|
||||
{"_id": ObjectId(subject_id)}, {"$set": update_data}
|
||||
)
|
||||
return result.modified_count > 0
|
||||
|
||||
def delete(self, subject_id: str) -> bool:
|
||||
result = self.collection.delete_one({"_id": ObjectId(subject_id)})
|
||||
return result.deleted_count > 0
|
|
@ -8,6 +8,9 @@ from .quiz import (
|
|||
from .answer.answer_request_schema import UserAnswerSchema
|
||||
from .answer.answer_item_request_schema import AnswerItemSchema
|
||||
|
||||
from .subject.create_subject_schema import SubjectCreateRequest
|
||||
from .subject.update_subject_schema import SubjectUpdateRequest
|
||||
|
||||
|
||||
__all__ = [
|
||||
"RegisterSchema",
|
||||
|
@ -15,4 +18,6 @@ __all__ = [
|
|||
"QuizCreateSchema",
|
||||
"UserAnswerSchema",
|
||||
"AnswerItemSchema",
|
||||
"SubjectCreateRequest",
|
||||
"SubjectUpdateRequest",
|
||||
]
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
from pydantic import BaseModel, Field
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class SubjectCreateRequest(BaseModel):
|
||||
name: str = Field(..., example="Ilmu Pengetahuan ALam")
|
||||
alias: str = Field(..., examples="IPA", alias="short_name")
|
||||
description: Optional[str] = Field(
|
||||
None, example="Pelajaran tentang angka dan logika"
|
||||
)
|
|
@ -0,0 +1,7 @@
|
|||
from pydantic import BaseModel, Field
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class SubjectUpdateRequest(BaseModel):
|
||||
name: Optional[str] = Field(None, example="Fisika")
|
||||
description: Optional[str] = Field(None, example="Pelajaran tentang hukum alam")
|
|
@ -5,6 +5,7 @@ from .quiz.quiz_data_rsp_schema import UserQuizListResponse
|
|||
from .history.history_response import HistoryResultSchema
|
||||
from .history.detail_history_response import QuizHistoryResponse, QuestionResult
|
||||
from .recomendation.recomendation_response_schema import RecomendationResponse
|
||||
from .subject.get_subject_schema import GetSubjectResponse
|
||||
|
||||
__all__ = [
|
||||
"QuizCreationResponse",
|
||||
|
@ -15,4 +16,5 @@ __all__ = [
|
|||
"QuizHistoryResponse",
|
||||
"QuestionResult",
|
||||
"RecomendationResponse",
|
||||
"GetSubjectResponse",
|
||||
]
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
from pydantic import BaseModel, Field
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class GetSubjectResponse(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
alias: str
|
||||
description: Optional[str]
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
allow_population_by_field_name = True
|
|
@ -3,6 +3,7 @@ from .user_service import UserService
|
|||
from .quiz_service import QuizService
|
||||
from .answer_service import AnswerService
|
||||
from .history_service import HistoryService
|
||||
from .subject_service import SubjectService
|
||||
|
||||
__all__ = [
|
||||
"AuthService",
|
||||
|
@ -10,4 +11,5 @@ __all__ = [
|
|||
"QuizService",
|
||||
"AnswerService",
|
||||
"HistoryService",
|
||||
"SubjectService",
|
||||
]
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
from typing import List, Optional
|
||||
from models.entities import SubjectEntity
|
||||
from schemas.requests import SubjectCreateRequest, SubjectUpdateRequest
|
||||
from schemas.response import GetSubjectResponse
|
||||
from repositories import SubjectRepository
|
||||
|
||||
|
||||
class SubjectService:
|
||||
def __init__(self, repository: SubjectRepository):
|
||||
self.repository = repository
|
||||
|
||||
def create_subject(self, request: SubjectCreateRequest) -> str:
|
||||
subject = SubjectEntity(**request)
|
||||
return self.repository.create(subject)
|
||||
|
||||
def get_all_subjects(self) -> List[GetSubjectResponse]:
|
||||
subjects = self.repository.get_all()
|
||||
return [
|
||||
GetSubjectResponse(
|
||||
id=str(subject.id),
|
||||
name=subject.name,
|
||||
alias=subject.short_name,
|
||||
description=subject.description,
|
||||
)
|
||||
for subject in subjects
|
||||
]
|
||||
|
||||
def get_subject_by_id(self, subject_id: str) -> Optional[GetSubjectResponse]:
|
||||
subject = self.repository.get_by_id(subject_id)
|
||||
if subject:
|
||||
return GetSubjectResponse(
|
||||
id=str(subject.id),
|
||||
name=subject.name,
|
||||
alias=subject.short_name,
|
||||
description=subject.description,
|
||||
)
|
||||
return None
|
||||
|
||||
def update_subject(self, subject_id: str, request: SubjectUpdateRequest) -> bool:
|
||||
update_data = request.dict(exclude_unset=True)
|
||||
return self.repository.update(subject_id, update_data)
|
||||
|
||||
def delete_subject(self, subject_id: str) -> bool:
|
||||
return self.repository.delete(subject_id)
|
Loading…
Reference in New Issue