From d1f033460a369f944ace2b25b0bc43339294ae75 Mon Sep 17 00:00:00 2001 From: sm4640 Date: Mon, 28 Apr 2025 21:32:24 +0900 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Feat:=20[#32]=20project=20crud=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- projects/views.py | 142 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 140 insertions(+), 2 deletions(-) diff --git a/projects/views.py b/projects/views.py index 91ea44a..56e466b 100644 --- a/projects/views.py +++ b/projects/views.py @@ -1,3 +1,141 @@ -from django.shortcuts import render +from django.shortcuts import get_object_or_404 -# Create your views here. +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import status + +from .models import * + +from django_filters.rest_framework import DjangoFilterBackend +from rest_framework.filters import OrderingFilter +from rest_framework.generics import ListAPIView +from .serializers import ProjectListViewSerializer, ProjectCreateSerializer, ProjectTeamSerializer +from .paginations import ProjectPagination +from .filters import ProjectFilter +from .services import ProjectStateChangeService, ProjectBeforeRelCheckService + +from django.db import transaction + + +class ProjectListView(ListAPIView): + queryset = Project.objects.filter(is_published=True).order_by('-created_at') + serializer_class = ProjectListViewSerializer + pagination_class = ProjectPagination + filterset_class = ProjectFilter + filter_backends = [DjangoFilterBackend, OrderingFilter] + ordering_fields = ['view_count', 'like_count', 'scrap_count', 'created_at'] # 허용할 필드 추천순 제외 + ordering = ['-created_at'] # 기본 정렬은 최신순 + +class ProjectCreateAPIView(APIView): + @transaction.atomic + def post(self, request): + serializer = ProjectCreateSerializer(data=request.data, context={"request": request}) + if serializer.is_valid(): + serializer.save() + return Response({"message": "create project success"}, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + +class ProjectTeamManageAPIView(APIView): + # 팀원 초대 + @transaction.atomic + def post(self, request, pk): + user = request.user + project = get_object_or_404(Project, id=pk) + if user != project.owner: + return Response({"message": "Not owner"}, status=status.HTTP_403_FORBIDDEN) + nickname = request.data.get('nickname') + new_member = get_object_or_404(User, nickname=nickname) + if ProjectTeamList.objects.filter(project=project, user=new_member).exists(): + return Response({"message": "already team member"}, status=status.HTTP_400_BAD_REQUEST) + serializer = ProjectTeamSerializer(data={'user':new_member.id, 'project':project.id}) + if serializer.is_valid(): + serializer.save() + return Response({"message": "invite success"}, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + # 팀원 추방 + @transaction.atomic + def delete(self, request, pk): + user = request.user + project = get_object_or_404(Project, id=pk) + if user != project.owner: + return Response({"message": "Not owner"}, status=status.HTTP_403_FORBIDDEN) + nickname = request.data.get('nickname') + member = get_object_or_404(User, nickname=nickname) + user_in_project = get_object_or_404(ProjectTeamList, project=project, user=member) + user_in_project.delete() + return Response({"message": "delete user in project success"}) + +class ProjectDeleteAPIView(APIView): + @transaction.atomic + def delete(self, request, pk): + user = request.user + project = get_object_or_404(Project, id=pk) + if user != project.owner: + return Response({"message": "Not owner"}, status=status.HTTP_403_FORBIDDEN) + project.delete() + return Response({"message": "delete success"}, status=status.HTTP_200_OK) + +class ProjectSetRepresentAPIView(APIView): + @transaction.atomic + def patch(self, request, pk): + user = request.user + project = get_object_or_404(Project, id=pk) + if user != project.owner: + return Response({"message": "Not owner"}, status=status.HTTP_403_FORBIDDEN) + if before_represent := Project.objects.filter(owner=user, is_represent=True).first(): + before_represent.is_represent = False + project.is_represent = True + return Response({"message": "change represent success"}, status=status.HTTP_200_OK) + + +class ProjectSetPublishAPIView(APIView): + @transaction.atomic + def patch(self, request, pk): + user = request.user + project = get_object_or_404(Project, id=pk) + if user != project.owner: + return Response({"message": "Not owner"}, status=status.HTTP_403_FORBIDDEN) + project.is_published = True + project.save() + return Response({"message": "publish success"}, status=status.HTTP_200_OK) + +class ProjectChangeState(APIView): + @transaction.atomic + def patch(self, request, pk): + project = get_object_or_404(Project, pk=pk) + user = request.user + action_type = request.query_params.get('type') + try: + if ProjectBeforeRelCheckService.check_user_project_rel(action_type, project, user): + return Response({"message": "already done"}, status=status.HTTP_400_BAD_REQUEST) + except ValueError as e: + return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) + return self._handle_action(action_type, project, user, add=True) + + @transaction.atomic + def delete(self, request, pk): + project = get_object_or_404(Project, pk=pk) + user = request.user + action_type = request.query_params.get('type') + try: + if not ProjectBeforeRelCheckService.check_user_project_rel(action_type, project, user): + return Response({"message": "never done before"}, status=status.HTTP_400_BAD_REQUEST) + except ValueError as e: + return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) + return self._handle_action(action_type, project, user, add=False) + + def _handle_action(self, action_type, project, user, add=True): + if not action_type: + return Response({'message': 'Missing action type'}, status=status.HTTP_400_BAD_REQUEST) + + try: + ProjectStateChangeService.change_user_project_rel(action_type, project, user, add) + ProjectStateChangeService.change_count_project_state(action_type, project, add) + except ValueError as e: + return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + return Response({ + 'message': f'{action_type} {"added" if add else "removed"}' + }, status=status.HTTP_200_OK) +