From c971fcf9c75e111a954bf461aacb4fab2ba1c14e Mon Sep 17 00:00:00 2001 From: JinHoooooou Date: Wed, 8 Sep 2021 14:34:46 +0900 Subject: [PATCH 1/5] JH-140 add url to delete topic --- v2/src/ctrlfbe/topic_urls.py | 1 + 1 file changed, 1 insertion(+) 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"), ] From b28d4ee31922f5671e2d7c415dfb0edee07a480a Mon Sep 17 00:00:00 2001 From: JinHoooooou Date: Wed, 8 Sep 2021 14:39:50 +0900 Subject: [PATCH 2/5] JH-140 add delete topic test on success --- v2/src/ctrlfbe/views.py | 5 +++ v2/src/tests/test_topic_delete.py | 54 +++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 v2/src/tests/test_topic_delete.py diff --git a/v2/src/ctrlfbe/views.py b/v2/src/ctrlfbe/views.py index f3069e9..030ba43 100644 --- a/v2/src/ctrlfbe/views.py +++ b/v2/src/ctrlfbe/views.py @@ -116,6 +116,11 @@ class TopicDetailUpdateDeleteView(BaseContentView): def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) + def delete(self, request, *args, **kwargs): + topic = Topic.objects.get(id=kwargs["topic_id"]) + topic.delete() + return Response(data={"message": "삭제 되었습니다."}, status=status.HTTP_204_NO_CONTENT) + 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..dc80bdc --- /dev/null +++ b/v2/src/tests/test_topic_delete.py @@ -0,0 +1,54 @@ +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) + # And: message로 "삭제 되었습니다."를 리턴한다. + self.assertEqual(response.data["message"], "삭제 되었습니다.") From ab44392aa861a1c1dad5b99ccdbfe126db1b4014 Mon Sep 17 00:00:00 2001 From: JinHoooooou Date: Wed, 8 Sep 2021 14:50:37 +0900 Subject: [PATCH 3/5] JH-140 add delete topic test on fail --- v2/src/ctrlfbe/views.py | 11 ++++++++--- v2/src/tests/test_topic_delete.py | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/v2/src/ctrlfbe/views.py b/v2/src/ctrlfbe/views.py index 030ba43..4ffd8c6 100644 --- a/v2/src/ctrlfbe/views.py +++ b/v2/src/ctrlfbe/views.py @@ -108,7 +108,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 @@ -117,9 +117,14 @@ def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) def delete(self, request, *args, **kwargs): + ctrlf_user = self._ctrlf_authentication(request) topic = Topic.objects.get(id=kwargs["topic_id"]) - topic.delete() - return Response(data={"message": "삭제 되었습니다."}, status=status.HTTP_204_NO_CONTENT) + + if topic.owners.filter(id=ctrlf_user.id).exists() or topic.note.owners.filter(id=ctrlf_user.id).exists(): + topic.delete() + return Response(data={"message": "삭제 되었습니다."}, status=status.HTTP_204_NO_CONTENT) + else: + return Response(data={"message": "권한이 없습니다."}, status=status.HTTP_401_UNAUTHORIZED) class PageListView(BaseContentView): diff --git a/v2/src/tests/test_topic_delete.py b/v2/src/tests/test_topic_delete.py index dc80bdc..0c1be70 100644 --- a/v2/src/tests/test_topic_delete.py +++ b/v2/src/tests/test_topic_delete.py @@ -52,3 +52,19 @@ def test_should_return_204_when_topic_owner_approve_delete(self): self.assertEqual(Topic.objects.count(), 0) # And: message로 "삭제 되었습니다."를 리턴한다. self.assertEqual(response.data["message"], "삭제 되었습니다.") + + 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"], "권한이 없습니다.") From 358bdcd2a7a293e61b07255b49266627b821a115 Mon Sep 17 00:00:00 2001 From: JinHoooooou Date: Wed, 8 Sep 2021 14:53:29 +0900 Subject: [PATCH 4/5] JH-140 add swagger --- v2/src/ctrlfbe/swagger.py | 7 +++++++ v2/src/ctrlfbe/views.py | 2 ++ 2 files changed, 9 insertions(+) diff --git a/v2/src/ctrlfbe/swagger.py b/v2/src/ctrlfbe/swagger.py index 2c1c223..7285f48 100644 --- a/v2/src/ctrlfbe/swagger.py +++ b/v2/src/ctrlfbe/swagger.py @@ -48,6 +48,13 @@ "tags": ["디테일 화면"], } +SWAGGER_TOPIC_DELETE_VIEW = { + "responses": {204: ""}, + "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/views.py b/v2/src/ctrlfbe/views.py index 4ffd8c6..a99aea8 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, ) @@ -116,6 +117,7 @@ class TopicDetailUpdateDeleteView(CtrlfAuthenticationMixin, 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"]) From da03b77cb3eab9b30256ab846f19c022b6c5940a Mon Sep 17 00:00:00 2001 From: JinHoooooou Date: Wed, 8 Sep 2021 15:07:08 +0900 Subject: [PATCH 5/5] JH-140 remove message about successing delete and modify swagger --- v2/src/ctrlfbe/swagger.py | 2 +- v2/src/ctrlfbe/views.py | 2 +- v2/src/tests/test_topic_delete.py | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/v2/src/ctrlfbe/swagger.py b/v2/src/ctrlfbe/swagger.py index 7285f48..93ac982 100644 --- a/v2/src/ctrlfbe/swagger.py +++ b/v2/src/ctrlfbe/swagger.py @@ -49,7 +49,7 @@ } SWAGGER_TOPIC_DELETE_VIEW = { - "responses": {204: ""}, + "responses": {204: "삭제 되었습니다", 401: "권한이 없습니다."}, "operation_summary": "Topic Delete API", "operation_description": "topic_id에 해당하는 Topic을 삭제합니다", "tags": ["디테일 화면"], diff --git a/v2/src/ctrlfbe/views.py b/v2/src/ctrlfbe/views.py index a99aea8..c54ff79 100644 --- a/v2/src/ctrlfbe/views.py +++ b/v2/src/ctrlfbe/views.py @@ -124,7 +124,7 @@ def delete(self, request, *args, **kwargs): if topic.owners.filter(id=ctrlf_user.id).exists() or topic.note.owners.filter(id=ctrlf_user.id).exists(): topic.delete() - return Response(data={"message": "삭제 되었습니다."}, status=status.HTTP_204_NO_CONTENT) + return Response(status=status.HTTP_204_NO_CONTENT) else: return Response(data={"message": "권한이 없습니다."}, status=status.HTTP_401_UNAUTHORIZED) diff --git a/v2/src/tests/test_topic_delete.py b/v2/src/tests/test_topic_delete.py index 0c1be70..30e4cb7 100644 --- a/v2/src/tests/test_topic_delete.py +++ b/v2/src/tests/test_topic_delete.py @@ -50,8 +50,6 @@ def test_should_return_204_when_topic_owner_approve_delete(self): self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) # And: Topic count는 0이다. self.assertEqual(Topic.objects.count(), 0) - # And: message로 "삭제 되었습니다."를 리턴한다. - self.assertEqual(response.data["message"], "삭제 되었습니다.") def test_should_return_401_when_another_user_approve_delete(self): # Given: Topic을 생성한다.