Skip to content

Commit 4205417

Browse files
committed
feat: 수정 심사 테이블 추가 및 API 추가
1 parent d59d0d9 commit 4205417

File tree

8 files changed

+717
-0
lines changed

8 files changed

+717
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import typing
2+
import unicodedata
3+
4+
from participant_portal_api.models import ModificationAudit, ModificationAuditComment
5+
from rest_framework import serializers
6+
from user.models import UserExt
7+
8+
9+
class ModificationAuditResponseAdminSerializer(serializers.ModelSerializer):
10+
class ModificationAuditCommentAdminSerializer(serializers.ModelSerializer):
11+
class ModificationAuditCommentAdminUserSerializer(serializers.ModelSerializer):
12+
class Meta:
13+
model = UserExt
14+
fields = read_only_fields = ("id", "nickname", "is_superuser")
15+
16+
created_by = ModificationAuditCommentAdminUserSerializer(read_only=True)
17+
18+
class Meta:
19+
model = ModificationAuditComment
20+
fields = read_only_fields = ("id", "content", "created_at", "created_by", "updated_at")
21+
22+
comments = ModificationAuditCommentAdminSerializer(many=True, read_only=True)
23+
str_repr = serializers.CharField(source="__str__", read_only=True)
24+
25+
class Meta:
26+
model = ModificationAudit
27+
fields = read_only_fields = (
28+
"id",
29+
"status",
30+
"created_at",
31+
"updated_at",
32+
"modification_data",
33+
"comments",
34+
"str_repr",
35+
)
36+
37+
38+
class ModificationAuditApprovalAdminSerializer(serializers.ModelSerializer):
39+
class Meta:
40+
model = ModificationAudit
41+
fields = read_only_fields = ("id",)
42+
43+
def validate(self, attrs: dict) -> dict:
44+
if typing.cast(ModificationAudit, self.instance).status != ModificationAudit.Status.REQUESTED:
45+
raise serializers.ValidationError("심사가 진행 중인 수정 요청만 승인할 수 있습니다.")
46+
47+
return attrs
48+
49+
def save(self, **kwargs: dict) -> ModificationAudit:
50+
instance: ModificationAudit = self.instance
51+
instance.status = ModificationAudit.Status.APPROVED
52+
instance.apply_modification(save=True)
53+
54+
return instance
55+
56+
57+
class ModificationAuditRejectionAdminSerializer(serializers.ModelSerializer):
58+
reason = serializers.CharField(required=True, allow_blank=True, allow_null=True, write_only=True)
59+
60+
class Meta:
61+
model = ModificationAudit
62+
fields = ("reason",)
63+
64+
def validate_reason(self, reason: str | None) -> str | None:
65+
if not (reason and (normalized_reason := unicodedata.normalize("NFC", reason).strip())):
66+
return None
67+
68+
return normalized_reason
69+
70+
def validate(self, attrs: dict) -> dict:
71+
if typing.cast(ModificationAudit, self.instance).status != ModificationAudit.Status.REQUESTED:
72+
raise serializers.ValidationError("심사가 진행 중인 수정 요청만 반려할 수 있습니다.")
73+
74+
return attrs
75+
76+
def save(self, **kwargs: dict) -> ModificationAudit:
77+
instance: ModificationAudit = self.instance
78+
instance.status = ModificationAudit.Status.REJECTED
79+
instance.save(update_fields=["status"])
80+
81+
if reason := self.validated_data["reason"]:
82+
ModificationAuditComment.objects.create(audit=instance, content=reason)
83+
84+
return instance
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from admin_api.serializers.modification_audit import (
2+
ModificationAuditApprovalAdminSerializer,
3+
ModificationAuditRejectionAdminSerializer,
4+
ModificationAuditResponseAdminSerializer,
5+
)
6+
from core.const.tag import OpenAPITag
7+
from core.permissions import IsSuperUser
8+
from django.db import models
9+
from drf_spectacular import utils
10+
from participant_portal_api.models import ModificationAudit, ModificationAuditComment
11+
from rest_framework import decorators, mixins, request, response, status, viewsets
12+
13+
14+
@utils.extend_schema_view(
15+
list=utils.extend_schema(tags=[OpenAPITag.ADMIN_MODIFICATION_AUDIT]),
16+
retrieve=utils.extend_schema(tags=[OpenAPITag.ADMIN_MODIFICATION_AUDIT]),
17+
)
18+
class ModificationAuditAdminViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
19+
serializer_class = ModificationAuditResponseAdminSerializer
20+
permission_classes = [IsSuperUser]
21+
queryset = (
22+
ModificationAudit.objects.filter_active()
23+
.prefetch_related(
24+
models.Prefetch("comments", queryset=ModificationAuditComment.objects.select_related("created_by"))
25+
)
26+
.select_related("created_by", "updated_by", "deleted_by")
27+
)
28+
29+
@utils.extend_schema(
30+
tags=[OpenAPITag.ADMIN_MODIFICATION_AUDIT],
31+
responses={status.HTTP_200_OK: ModificationAuditApprovalAdminSerializer},
32+
)
33+
@decorators.action(detail=True, methods=["patch"], url_path="aprove")
34+
def cancel_audit(self, request: request.Request, *args: tuple, **kwargs: dict) -> response.Response:
35+
serializer = ModificationAuditApprovalAdminSerializer(self.get_object(), data=request.data)
36+
serializer.is_valid(raise_exception=True)
37+
instance = serializer.save()
38+
39+
return response.Response(data=self.get_serializer(instance).data)
40+
41+
@utils.extend_schema(
42+
tags=[OpenAPITag.ADMIN_MODIFICATION_AUDIT],
43+
responses={status.HTTP_200_OK: ModificationAuditRejectionAdminSerializer},
44+
)
45+
@decorators.action(detail=True, methods=["patch"], url_path="reject")
46+
def reject_audit(self, request: request.Request, *args: tuple, **kwargs: dict) -> response.Response:
47+
serializer = ModificationAuditRejectionAdminSerializer(self.get_object(), data=request.data)
48+
serializer.is_valid(raise_exception=True)
49+
instance = serializer.save()
50+
51+
return response.Response(data=self.get_serializer(instance).data)

app/notification/migrations/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)