Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat #25 - 유치원 요약 정보 조회 API 구현 #26

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions mung_manager/pet_kindergardens/apis/api_managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from mung_manager.pet_kindergardens.apis.apis import (
PetKindergardenListAPI,
PetKindergardenSelectionAPI,
PetKindergardenSummaryInfoAPI,
)
from mung_manager.schemas.errors.authentications import (
ErrorAuthenticationPasswordChangedSchema,
Expand Down Expand Up @@ -117,3 +118,43 @@ class PetKindergardenSelectionAPIManager(BaseAPIManager):
)
def post(self, request, *args, **kwargs):
return self.VIEWS_BY_METHOD["POST"]()(request, *args, **kwargs)


class PetKindergardenSummaryInfoAPIManager(BaseAPIManager):
VIEWS_BY_METHOD = {
"GET": PetKindergardenSummaryInfoAPI.as_view,
}

@extend_schema(
tags=["반려동물 유치원"],
summary="반려동물 유치원 요약 정보 조회",
description="""
Rogic
- 유저 토큰 클레임에 포함된 반려동물 유치원 아이디로 해당 반려동물 유치원의 요약 정보를 조회합니다.
""",
responses={
status.HTTP_200_OK: VIEWS_BY_METHOD["GET"]().cls.OutputSerializer,
status.HTTP_401_UNAUTHORIZED: OpenApiResponse(
response=OpenApiTypes.OBJECT,
examples=[
ErrorAuthenticationFailedSchema,
ErrorNotAuthenticatedSchema,
ErrorInvalidTokenSchema,
ErrorAuthorizationHeaderSchema,
ErrorAuthenticationPasswordChangedSchema,
ErrorAuthenticationUserDeletedSchema,
ErrorAuthenticationUserInactiveSchema,
ErrorAuthenticationUserNotFoundSchema,
ErrorTokenIdentificationSchema,
],
),
status.HTTP_403_FORBIDDEN: OpenApiResponse(
response=OpenApiTypes.OBJECT, examples=[ErrorPermissionDeniedSchema]
),
status.HTTP_500_INTERNAL_SERVER_ERROR: OpenApiResponse(
response=OpenApiTypes.OBJECT, examples=[ErrorUnknownServerSchema]
),
},
)
def get(self, request, *args, **kwargs):
return self.VIEWS_BY_METHOD["GET"]()(request, *args, **kwargs)
22 changes: 21 additions & 1 deletion mung_manager/pet_kindergardens/apis/apis.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from rest_framework.response import Response
from rest_framework.views import APIView

from mung_manager.apis.mixins import APIAuthMixin
from mung_manager.apis.mixins import APIAuthMixin, APIAuthWithPetKindergardenAccessMixin
from mung_manager.authentications.containers import AuthenticationContainer
from mung_manager.commons.base.serializers import BaseSerializer
from mung_manager.pet_kindergardens.containers import PetKindergardenContainer
Expand Down Expand Up @@ -56,3 +56,23 @@ def post(self, request: Request) -> Response:
}
).data
return Response(data=auth_data, status=status.HTTP_200_OK)


class PetKindergardenSummaryInfoAPI(APIAuthWithPetKindergardenAccessMixin, APIView):
class OutputSerializer(BaseSerializer):
id = serializers.IntegerField(label="유치원 아이디")
name = serializers.CharField(label="유치원 이름")
business_start_hour = serializers.TimeField(label="영업 시작 시간", format="%H:%M")
business_end_hour = serializers.TimeField(label="영업 종료 시간", format="%H:%M")

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._pet_kindergarden_selector = PetKindergardenContainer.pet_kindergarden_selector()

def get(self, request: Request) -> Response:
pet_kindergarden_id = request.pet_kindergarden_id
pet_kindergarden = self._pet_kindergarden_selector.get_by_pet_kindergarden_id_for_summary_info(
pet_kindergarden_id
).get()
pet_kindergardens_data = self.OutputSerializer(pet_kindergarden).data
return Response(data=pet_kindergardens_data, status=status.HTTP_200_OK)
6 changes: 6 additions & 0 deletions mung_manager/pet_kindergardens/apis/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from mung_manager.pet_kindergardens.apis.api_managers import (
PetkindergardenListAPIManager,
PetKindergardenSelectionAPIManager,
PetKindergardenSummaryInfoAPIManager,
)

urlpatterns = [
Expand All @@ -16,4 +17,9 @@
PetKindergardenSelectionAPIManager.as_view(),
name="pet-kindergarden-selection",
),
path(
"/summary",
PetKindergardenSummaryInfoAPIManager.as_view(),
name="pet-kindergarden-summary-info",
),
]
19 changes: 15 additions & 4 deletions mung_manager/pet_kindergardens/selectors/abstracts.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
from abc import ABC, abstractmethod
from typing import Any

from django.db.models.query import QuerySet
from django.db.models import QuerySet
from django_stubs_ext import ValuesQuerySet, WithAnnotations

from mung_manager.errors.exceptions import NotImplementedException
from mung_manager.pet_kindergardens.models import PetKindergarden
from mung_manager.pet_kindergardens.selectors.pet_kindergardens import (
info_for_full_address,
)
from mung_manager.pet_kindergardens.types import info_for_summary


class AbstractPetKindergardenSelector(ABC):

@abstractmethod
def get_queryset_by_user(
self,
user,
) -> QuerySet[Any]:
self, user
) -> QuerySet[WithAnnotations[PetKindergarden, info_for_full_address], dict[str, Any]]:
raise NotImplementedException()

@abstractmethod
def get_by_pet_kindergarden_id_for_summary_info(
self, pet_kindergarden_id: int
) -> ValuesQuerySet[PetKindergarden, info_for_summary]:
raise NotImplementedException()
29 changes: 26 additions & 3 deletions mung_manager/pet_kindergardens/selectors/pet_kindergardens.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,53 @@

from django.db.models import F, QuerySet, Value
from django.db.models.functions import Concat
from django_stubs_ext import WithAnnotations
from django_stubs_ext.aliases import ValuesQuerySet

from mung_manager.pet_kindergardens.models import PetKindergarden
from mung_manager.pet_kindergardens.selectors.abstracts import (
AbstractPetKindergardenSelector,
)
from mung_manager.pet_kindergardens.types import info_for_full_address, info_for_summary


class PetKindergardenSelector(AbstractPetKindergardenSelector):
"""
이 클래스는 반려동물 유치원을 DB에서 PULL하는 비즈니스 로직을 담당합니다.
"""

def get_queryset_by_user(self, user) -> QuerySet[Any]:
"""이 함수는 사용자 정보로, 해당 사용자가 속한 유치원 목록을 조회합니다.
def get_queryset_by_user(
self, user
) -> QuerySet[WithAnnotations[PetKindergarden, info_for_full_address], dict[str, Any]]:
"""
이 함수는 사용자 정보로, 해당 사용자가 속한 유치원 목록을 조회합니다.

Args:
user: User: 유저 객체

Returns:
QuerySet[Any]: 존재하지 않으면 빈 쿼리셋을 반환
QuerySet[WithAnnotations[PetKindergarden, info_for_full_address], dict[str, Any]]: 정의된 응답 스키마
"""

return (
PetKindergarden.objects.filter(customers__user=user)
.annotate(full_address=Concat(F("road_address"), Value(" "), F("detail_address")))
.values("id", "name", "full_address", "profile_thumbnail_url")
)

def get_by_pet_kindergarden_id_for_summary_info(
self, pet_kindergarden_id: int
) -> ValuesQuerySet[PetKindergarden, info_for_summary]:
"""
이 함수는 반려동물 유치원 아이디로 해당 반려동물 유치원의 요약 정보를 조회합니다.

Args:
pet_kindergarden_id (int): 반려동물 유치원 아이디

Returns:
ValuesQuerySet[PetKindergarden, info_for_summary]: 정의된 응답 스키마
"""

return PetKindergarden.objects.filter(id=pet_kindergarden_id).values(
"id", "name", "business_start_hour", "business_end_hour"
)
7 changes: 7 additions & 0 deletions mung_manager/pet_kindergardens/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from datetime import time
from typing import TypedDict

info_for_full_address = TypedDict("info_for_full_address", {"full_address": str})
info_for_summary = TypedDict(
"info_for_summary", {"id": int, "name": str, "business_start_hour": time, "business_end_hour": time}
)
Loading