diff --git a/v2/src/ctrlfbe/swagger.py b/v2/src/ctrlfbe/swagger.py index 2c1c223..93ac982 100644 --- a/v2/src/ctrlfbe/swagger.py +++ b/v2/src/ctrlfbe/swagger.py @@ -48,6 +48,13 @@ "tags": ["디테일 화면"], } +SWAGGER_TOPIC_DELETE_VIEW = { + "responses": {204: "삭제 되었습니다", 401: "권한이 없습니다."}, + "operation_summary": "Topic Delete API", + "operation_description": "topic_id에 해당하는 Topic을 삭제합니다", + "tags": ["디테일 화면"], +} + SWAGGER_PAGE_DETAIL_VIEW = { "responses": {200: PageSerializer()}, "operation_summary": "Page Detail API", diff --git a/v2/src/ctrlfbe/topic_urls.py b/v2/src/ctrlfbe/topic_urls.py index 7ecf2bb..f555342 100644 --- a/v2/src/ctrlfbe/topic_urls.py +++ b/v2/src/ctrlfbe/topic_urls.py @@ -7,4 +7,5 @@ urlpatterns = [ path("/pages", PageListView.as_view(), name="page_list"), path("", TopicDetailUpdateDeleteView.as_view(), name="topic_detail"), + path("", TopicDetailUpdateDeleteView.as_view(), name="topic_delete"), ] diff --git a/v2/src/ctrlfbe/views.py b/v2/src/ctrlfbe/views.py index f3069e9..c54ff79 100644 --- a/v2/src/ctrlfbe/views.py +++ b/v2/src/ctrlfbe/views.py @@ -7,6 +7,7 @@ SWAGGER_NOTE_LIST_VIEW, SWAGGER_PAGE_DETAIL_VIEW, SWAGGER_PAGE_LIST_VIEW, + SWAGGER_TOPIC_DELETE_VIEW, SWAGGER_TOPIC_DETAIL_VIEW, SWAGGER_TOPIC_LIST_VIEW, ) @@ -108,7 +109,7 @@ def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) -class TopicDetailUpdateDeleteView(BaseContentView): +class TopicDetailUpdateDeleteView(CtrlfAuthenticationMixin, BaseContentView): parent_model = Topic serializer = TopicSerializer @@ -116,6 +117,17 @@ class TopicDetailUpdateDeleteView(BaseContentView): def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) + @swagger_auto_schema(**SWAGGER_TOPIC_DELETE_VIEW) + def delete(self, request, *args, **kwargs): + ctrlf_user = self._ctrlf_authentication(request) + topic = Topic.objects.get(id=kwargs["topic_id"]) + + if topic.owners.filter(id=ctrlf_user.id).exists() or topic.note.owners.filter(id=ctrlf_user.id).exists(): + topic.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + else: + return Response(data={"message": "권한이 없습니다."}, status=status.HTTP_401_UNAUTHORIZED) + class PageListView(BaseContentView): parent_model = Topic diff --git a/v2/src/tests/test_topic_delete.py b/v2/src/tests/test_topic_delete.py new file mode 100644 index 0000000..30e4cb7 --- /dev/null +++ b/v2/src/tests/test_topic_delete.py @@ -0,0 +1,68 @@ +from ctrlf_auth.models import CtrlfUser +from ctrlf_auth.serializers import LoginSerializer +from ctrlfbe.models import Note, Topic +from django.test import Client, TestCase +from django.urls import reverse +from rest_framework import status + + +class TestTopicDelete(TestCase): + def setUp(self) -> None: + self.client = Client() + self.topic_owner_data = { + "email": "test@test.com", + "password": "12345", + } + self.another_user_data = { + "email": "testtest2@test.com", + "password": "54321", + } + self.topic_owner = CtrlfUser.objects.create_user(**self.topic_owner_data) + CtrlfUser.objects.create_user(**self.another_user_data) + + def _create_topic(self, owner): + note = Note.objects.create(title="test note title") + note.owners.add(owner) + self.topic = Topic.objects.create(note=note, title="test topic title") + self.topic.owners.add(owner) + + def _login(self, user_data): + serializer = LoginSerializer() + return serializer.validate(user_data)["token"] + + def _call_api(self, token=None): + if token: + header = {"HTTP_AUTHORIZATION": f"Bearer {token}"} + else: + header = {} + return self.client.delete(reverse("topics:topic_delete", kwargs={"topic_id": self.topic.id}), **header) + + def test_should_return_204_when_topic_owner_approve_delete(self): + # Given: Topic을 생성한다. + self._create_topic(self.topic_owner) + # And: Topic을 생성한 계정으로 로그인하여 토큰을 발급받는다. + owner_token = self._login(self.topic_owner_data) + + # When: delete topic api를 호출한다. + response = self._call_api(owner_token) + + # Then: status code 204을 리턴한다. + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + # And: Topic count는 0이다. + self.assertEqual(Topic.objects.count(), 0) + + def test_should_return_401_when_another_user_approve_delete(self): + # Given: Topic을 생성한다. + self._create_topic(self.topic_owner) + # And: Topic을 생성한 계정이 아닌 다른 계정으로 로그인하여 토큰을 발급받는다. + another_user_token = self._login(self.another_user_data) + + # When: delete topic api를 호출한다. + response = self._call_api(another_user_token) + + # Then: status code 204을 리턴한다. + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + # And: Topic count는 1이다. + self.assertEqual(Topic.objects.count(), 1) + # And: message로 "권한이 없습니다."를 리턴한다. + self.assertEqual(response.data["message"], "권한이 없습니다.")