From e923549474a19724208c4a144c0518fa91e949e0 Mon Sep 17 00:00:00 2001 From: jrhong95 Date: Fri, 3 Sep 2021 02:05:53 +0900 Subject: [PATCH 1/7] SH-128 Add topic create api with success test --- v2/src/ctrlfbe/constants.py | 2 +- v2/src/ctrlfbe/serializers.py | 90 +++++++++++++++++++++++- v2/src/ctrlfbe/topic_urls.py | 3 +- v2/src/ctrlfbe/views.py | 16 +++++ v2/src/tests/test_content_list_detail.py | 50 ++++++++++++- 5 files changed, 156 insertions(+), 5 deletions(-) diff --git a/v2/src/ctrlfbe/constants.py b/v2/src/ctrlfbe/constants.py index f14fd14..cb17ba8 100644 --- a/v2/src/ctrlfbe/constants.py +++ b/v2/src/ctrlfbe/constants.py @@ -3,6 +3,6 @@ ERR_TOPIC_NOT_FOUND = "토픽을 찾을 수 없습니다." ERR_PAGE_NOT_FOUND = "페이지를 찾을 수 없습니다." ERR_UNEXPECTED = "알 수 없는 에러가 발생 하였습니다." - +ERR_KEY_INPUT_MSG = "을(를) 입력하세요." ERR_NOT_FOUND_MSG_MAP = {"note": ERR_NOTE_NOT_FOUND, "topic": ERR_TOPIC_NOT_FOUND, "page": ERR_PAGE_NOT_FOUND} diff --git a/v2/src/ctrlfbe/serializers.py b/v2/src/ctrlfbe/serializers.py index c04a13c..d84e337 100644 --- a/v2/src/ctrlfbe/serializers.py +++ b/v2/src/ctrlfbe/serializers.py @@ -1,9 +1,12 @@ -from rest_framework import serializers +from rest_framework import serializers, status +from rest_framework.exceptions import ValidationError +from .constants import ERR_KEY_INPUT_MSG, ERR_NOTE_NOT_FOUND from .models import ( ContentRequest, CtrlfActionType, CtrlfContentType, + CtrlfIssueStatus, Issue, Note, Page, @@ -61,12 +64,95 @@ class NoteListQuerySerializer(serializers.Serializer): class TopicSerializer(serializers.ModelSerializer): class Meta: model = Topic - fields = "__all__" + fields = ["id", "created_at", "updated_at", "title", "note", "is_approved"] read_only_fields = ["id", "created_at"] + def create(self, validated_data): + owner = validated_data.pop("owner") + topic = Topic.objects.create(**validated_data) + topic.owners.add(owner) + topic.save() + return topic + class PageSerializer(serializers.ModelSerializer): class Meta: model = Page fields = "__all__" read_only_fields = ["id", "created_at"] + + +class ContentRequestSerializer(serializers.ModelSerializer): + class Meta: + model = ContentRequest + fields = "__all__" + + def create(self, validated_data): + content_request = ContentRequest.objects.create(**validated_data) + content_request.save() + return content_request + + +class IssueSerializer(serializers.ModelSerializer): + class Meta: + model = Issue + fields = "__all__" + + def create(self, validated_data): + issue = Issue.objects.create(**validated_data) + issue.save() + return issue + + +class TopicCreateSerializer(serializers.Serializer): + note = serializers.IntegerField() + title = serializers.CharField() + content = serializers.CharField() + + def validate(self, request_data): + try: + Note.objects.get(id=request_data["note"]) + except Note.DoesNotExist: + raise ValidationError(detail=ERR_NOTE_NOT_FOUND, code=status.HTTP_404_NOT_FOUND) + + for key in request_data: + if key == "note": + continue + if not request_data[key]: + raise ValidationError(detail=key + ERR_KEY_INPUT_MSG, code=status.HTTP_400_BAD_REQUEST) + return request_data + + def create(self, validated_data): + topic_data = { + "note": validated_data["note"], + "title": validated_data["title"], + } + topic = TopicSerializer(data=topic_data) + if not topic.is_valid(): + raise ValidationError(detail="topic 생성 실패", code=status.HTTP_400_BAD_REQUEST) + topic = topic.save(owner=validated_data["owner"]) + + content_request_data = { + "type": CtrlfContentType.TOPIC, + "action": CtrlfActionType.CREATE, + "sub_id": topic.id, + "user": validated_data["owner"].id, + } + content_request = ContentRequestSerializer(data=content_request_data) + if not content_request.is_valid(): + raise ValidationError(detail="content_request 생성 실패", code=status.HTTP_400_BAD_REQUEST) + content_request = content_request.save() + + issue_data = { + "owner": validated_data["owner"].id, + "content_request": content_request.id, + "title": validated_data["title"], + "content": validated_data["content"], + "status": CtrlfIssueStatus.REQUESTED, + } + issue = IssueSerializer(data=issue_data) + if not issue.is_valid(): + raise ValidationError(detail="issue 생성 실패", code=status.HTTP_400_BAD_REQUEST) + issue = issue.save() + + return issue diff --git a/v2/src/ctrlfbe/topic_urls.py b/v2/src/ctrlfbe/topic_urls.py index 7ecf2bb..d6cb8da 100644 --- a/v2/src/ctrlfbe/topic_urls.py +++ b/v2/src/ctrlfbe/topic_urls.py @@ -1,10 +1,11 @@ from django.urls import path -from .views import PageListView, TopicDetailUpdateDeleteView +from .views import PageListView, TopicCreateView, TopicDetailUpdateDeleteView app_name = "topics" urlpatterns = [ + path("", TopicCreateView.as_view(), name="topic_create"), path("/pages", PageListView.as_view(), name="page_list"), path("", TopicDetailUpdateDeleteView.as_view(), name="topic_detail"), ] diff --git a/v2/src/ctrlfbe/views.py b/v2/src/ctrlfbe/views.py index f3069e9..18fcb52 100644 --- a/v2/src/ctrlfbe/views.py +++ b/v2/src/ctrlfbe/views.py @@ -22,6 +22,7 @@ IssueCreateSerializer, NoteSerializer, PageSerializer, + TopicCreateSerializer, TopicSerializer, ) @@ -108,6 +109,21 @@ def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) +class TopicCreateView(CtrlfAuthenticationMixin, APIView): + def post(self, request, *args, **kwargs): + ctrlf_user = self._ctrlf_authentication(request) + serializer = TopicCreateSerializer(data=request.data) + + if serializer.is_valid(): + serializer.save(owner=ctrlf_user) + return Response(status=status.HTTP_201_CREATED) + else: + for _, message in serializer.errors.items(): + err = message[0] + print(err) + return Response({"message": err}, status=err.code) + + class TopicDetailUpdateDeleteView(BaseContentView): parent_model = Topic serializer = TopicSerializer diff --git a/v2/src/tests/test_content_list_detail.py b/v2/src/tests/test_content_list_detail.py index d1a393c..226012b 100644 --- a/v2/src/tests/test_content_list_detail.py +++ b/v2/src/tests/test_content_list_detail.py @@ -1,5 +1,6 @@ from ctrlf_auth.models import CtrlfUser -from ctrlfbe.models import Note, Page, Topic +from ctrlf_auth.serializers import LoginSerializer +from ctrlfbe.models import Issue, Note, Page, Topic from django.test import Client, TestCase from django.urls import reverse from rest_framework import status @@ -219,3 +220,50 @@ def test_page_detail_should_return_404_by_invalid_page_id(self): # And : 메세지는 "페이지를 찾을 수 없습니다." 이어야 한다. response = response.data self.assertEqual(response["message"], "페이지를 찾을 수 없습니다.") + + +class TestTopicCreate(TestCase): + def setUp(self) -> None: + self.client = Client() + self.data = { + "email": "test@test.com", + "password": "12345", + } + self.user = CtrlfUser.objects.create_user(**self.data) + + def _login(self): + serializer = LoginSerializer() + return serializer.validate(self.data)["token"] + + def _call_api(self, request_body, token=None): + if token: + header = {"HTTP_AUTHORIZATION": f"Bearer {token}"} + else: + header = {} + return self.client.post(reverse("topics:topic_create"), request_body, **header) + + def make_note(self): + self.note = Note.objects.create(title="test note title") + self.note.owners.add(self.user) + + def test_topic_create_should_return_201(self): + # Given: 미리 생성된 노트, 로그인 하여 얻은 토큰, 유효한 토픽 생성 정보 + self.make_note() + token = self._login() + request_body = {"note": self.note.id, "title": "test title", "content": "test issue content"} + + # When : API 실행 + response = self._call_api(request_body, token=token) + + # Then : 상태코드 201이어야 함. + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + # And : 생성된 토픽 정보가 일치해야 한다. + topic = Topic.objects.all()[0] + self.assertEqual(topic.note, self.note) + self.assertEqual(topic.title, "test title") + + # And : 생성된 이슈 정보와 일치해야 한다. + issue = Issue.objects.all()[0] + self.assertEqual(issue.title, "test title") + self.assertEqual(issue.content, "test issue content") From a7e7fa3fc9a433cd7818c49245a931f439fe17aa Mon Sep 17 00:00:00 2001 From: jrhong95 Date: Fri, 3 Sep 2021 13:33:43 +0900 Subject: [PATCH 2/7] SH-128 Add topic create failure test when not login --- v2/src/ctrlfbe/views.py | 1 - v2/src/tests/test_content_list_detail.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/v2/src/ctrlfbe/views.py b/v2/src/ctrlfbe/views.py index 18fcb52..07f1d6e 100644 --- a/v2/src/ctrlfbe/views.py +++ b/v2/src/ctrlfbe/views.py @@ -120,7 +120,6 @@ def post(self, request, *args, **kwargs): else: for _, message in serializer.errors.items(): err = message[0] - print(err) return Response({"message": err}, status=err.code) diff --git a/v2/src/tests/test_content_list_detail.py b/v2/src/tests/test_content_list_detail.py index 226012b..ada1fec 100644 --- a/v2/src/tests/test_content_list_detail.py +++ b/v2/src/tests/test_content_list_detail.py @@ -267,3 +267,14 @@ def test_topic_create_should_return_201(self): issue = Issue.objects.all()[0] self.assertEqual(issue.title, "test title") self.assertEqual(issue.content, "test issue content") + + def test_topic_create_should_return_401_without_login(self): + # Given: 미리 생성된 노트, 로그인 하여 얻은 토큰, 유효한 토픽 생성 정보 + self.make_note() + request_body = {"note": self.note.id, "title": "test title", "content": "test issue content"} + + # When : API 실행 + response = self._call_api(request_body) + + # Then : 상태코드 401이어야 함. + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) From b71f0aead439dd9932763437a1f4805ec3e47391 Mon Sep 17 00:00:00 2001 From: jrhong95 Date: Fri, 3 Sep 2021 17:56:22 +0900 Subject: [PATCH 3/7] SH-128 Add topic create failure test with no title, content --- v2/src/ctrlfbe/serializers.py | 8 +--- v2/src/ctrlfbe/views.py | 11 ++++- v2/src/tests/test_content_list_detail.py | 53 +++++++++++++++++++++++- 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/v2/src/ctrlfbe/serializers.py b/v2/src/ctrlfbe/serializers.py index d84e337..d431ccc 100644 --- a/v2/src/ctrlfbe/serializers.py +++ b/v2/src/ctrlfbe/serializers.py @@ -1,7 +1,7 @@ from rest_framework import serializers, status from rest_framework.exceptions import ValidationError -from .constants import ERR_KEY_INPUT_MSG, ERR_NOTE_NOT_FOUND +from .constants import ERR_NOTE_NOT_FOUND from .models import ( ContentRequest, CtrlfActionType, @@ -114,12 +114,6 @@ def validate(self, request_data): Note.objects.get(id=request_data["note"]) except Note.DoesNotExist: raise ValidationError(detail=ERR_NOTE_NOT_FOUND, code=status.HTTP_404_NOT_FOUND) - - for key in request_data: - if key == "note": - continue - if not request_data[key]: - raise ValidationError(detail=key + ERR_KEY_INPUT_MSG, code=status.HTTP_400_BAD_REQUEST) return request_data def create(self, validated_data): diff --git a/v2/src/ctrlfbe/views.py b/v2/src/ctrlfbe/views.py index 07f1d6e..c56489e 100644 --- a/v2/src/ctrlfbe/views.py +++ b/v2/src/ctrlfbe/views.py @@ -16,7 +16,12 @@ from rest_framework.response import Response from rest_framework.views import APIView -from .constants import ERR_NOT_FOUND_MSG_MAP, ERR_UNEXPECTED, MAX_PRINTABLE_NOTE_COUNT +from .constants import ( + ERR_KEY_INPUT_MSG, + ERR_NOT_FOUND_MSG_MAP, + ERR_UNEXPECTED, + MAX_PRINTABLE_NOTE_COUNT, +) from .models import CtrlfIssueStatus, Note, Page, Topic from .serializers import ( IssueCreateSerializer, @@ -118,8 +123,10 @@ def post(self, request, *args, **kwargs): serializer.save(owner=ctrlf_user) return Response(status=status.HTTP_201_CREATED) else: - for _, message in serializer.errors.items(): + for key, message in serializer.errors.items(): err = message[0] + if err.code == "required": + return Response({"message": key + ERR_KEY_INPUT_MSG}, status=status.HTTP_400_BAD_REQUEST) return Response({"message": err}, status=err.code) diff --git a/v2/src/tests/test_content_list_detail.py b/v2/src/tests/test_content_list_detail.py index ada1fec..ab0cdb5 100644 --- a/v2/src/tests/test_content_list_detail.py +++ b/v2/src/tests/test_content_list_detail.py @@ -247,12 +247,12 @@ def make_note(self): self.note.owners.add(self.user) def test_topic_create_should_return_201(self): - # Given: 미리 생성된 노트, 로그인 하여 얻은 토큰, 유효한 토픽 생성 정보 + # Given: 미리 생성된 노트, 로그인 하여 얻은 토큰, 유효한 토픽 생성 정보. self.make_note() token = self._login() request_body = {"note": self.note.id, "title": "test title", "content": "test issue content"} - # When : API 실행 + # When : API 실행. response = self._call_api(request_body, token=token) # Then : 상태코드 201이어야 함. @@ -278,3 +278,52 @@ def test_topic_create_should_return_401_without_login(self): # Then : 상태코드 401이어야 함. self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + + def test_topic_create_should_return_404_by_invalid_note_id(self): + # Given: 미리 생성된 노트, 로그인 하여 얻은 토큰, 유효하지 않은 노트 ID. + self.make_note() + token = self._login() + invalid_note_id = 1234 + request_body = {"note": invalid_note_id, "title": "test title", "content": "test issue content"} + + # When : API 실행. + response = self._call_api(request_body, token=token) + + # Then : 상태코드 404이어야 함. + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + # And : 메세지는 노트를 찾을 수 없습니다. 이어야 함. + response = response.data + self.assertEqual(response["message"], "노트를 찾을 수 없습니다.") + + def test_topic_create_should_return_400_without_title(self): + # Given: 미리 생성된 노트, 로그인 하여 얻은 토큰, title 없음. + self.make_note() + token = self._login() + request_body = {"note": self.note.id, "content": "test issue content"} + + # When : API 실행. + response = self._call_api(request_body, token=token) + + # Then : 상태코드 400이어야 함. + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + # And : 메세지는 title을(를) 입력하세요. 이어야 함. + response = response.data + self.assertEqual(response["message"], "title을(를) 입력하세요.") + + def test_topic_create_should_return_400_without_content(self): + # Given: 미리 생성된 노트, 로그인 하여 얻은 토큰, content 없음. + self.make_note() + token = self._login() + request_body = {"note": self.note.id, "title": "test title"} + + # When : API 실행. + response = self._call_api(request_body, token=token) + + # Then : 상태코드 400이어야 함. + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + # And : 메세지는 content을(를) 입력하세요. 이어야 함. + response = response.data + self.assertEqual(response["message"], "content을(를) 입력하세요.") From 818e35ce8fb0f9285d88df491e364949a2560a89 Mon Sep 17 00:00:00 2001 From: jrhong95 Date: Fri, 3 Sep 2021 18:17:23 +0900 Subject: [PATCH 4/7] SH-128 Add topic create swagger --- v2/src/ctrlfbe/swagger.py | 9 +++++++++ v2/src/ctrlfbe/views.py | 2 ++ 2 files changed, 11 insertions(+) diff --git a/v2/src/ctrlfbe/swagger.py b/v2/src/ctrlfbe/swagger.py index 2c1c223..39958b1 100644 --- a/v2/src/ctrlfbe/swagger.py +++ b/v2/src/ctrlfbe/swagger.py @@ -3,6 +3,7 @@ NoteListQuerySerializer, NoteSerializer, PageSerializer, + TopicCreateSerializer, TopicSerializer, ) @@ -54,3 +55,11 @@ "operation_description": "page_id에 해당하는 Page의 상세 내용을 리턴합니다", "tags": ["디테일 화면"], } + +SWAGGER_TOPIC_CREATE_VIEW = { + "request_body": TopicCreateSerializer, + "responses": {201: ""}, + "operation_summary": "Topic Create API", + "operation_description": "미승인 토픽을 생성하고 토픽 생성 이슈를 등록합니다.", + "tags": ["디테일 화면"], +} diff --git a/v2/src/ctrlfbe/views.py b/v2/src/ctrlfbe/views.py index c56489e..c295f1c 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_CREATE_VIEW, SWAGGER_TOPIC_DETAIL_VIEW, SWAGGER_TOPIC_LIST_VIEW, ) @@ -115,6 +116,7 @@ def get(self, request, *args, **kwargs): class TopicCreateView(CtrlfAuthenticationMixin, APIView): + @swagger_auto_schema(**SWAGGER_TOPIC_CREATE_VIEW) def post(self, request, *args, **kwargs): ctrlf_user = self._ctrlf_authentication(request) serializer = TopicCreateSerializer(data=request.data) From a2e6e46ba13e6ad0e8148f3fac89204366a82c60 Mon Sep 17 00:00:00 2001 From: jrhong95 Date: Sat, 4 Sep 2021 00:10:32 +0900 Subject: [PATCH 5/7] SH-128 Add page create api with failure test --- v2/src/ctrlfbe/page_urls.py | 3 +- v2/src/ctrlfbe/serializers.py | 61 ++++++++- v2/src/ctrlfbe/views.py | 17 +++ v2/src/tests/test_content_list_detail.py | 163 ++++++++++++++++++++++- 4 files changed, 240 insertions(+), 4 deletions(-) diff --git a/v2/src/ctrlfbe/page_urls.py b/v2/src/ctrlfbe/page_urls.py index 6d0e3b0..3e9bd3a 100644 --- a/v2/src/ctrlfbe/page_urls.py +++ b/v2/src/ctrlfbe/page_urls.py @@ -1,9 +1,10 @@ from django.urls import path -from .views import PageDetailUpdateDeleteView +from .views import PageCreateView, PageDetailUpdateDeleteView app_name = "pages" urlpatterns = [ + path("", PageCreateView.as_view(), name="page_create"), path("", PageDetailUpdateDeleteView.as_view(), name="page_detail"), ] diff --git a/v2/src/ctrlfbe/serializers.py b/v2/src/ctrlfbe/serializers.py index d431ccc..e7f498e 100644 --- a/v2/src/ctrlfbe/serializers.py +++ b/v2/src/ctrlfbe/serializers.py @@ -1,7 +1,7 @@ from rest_framework import serializers, status from rest_framework.exceptions import ValidationError -from .constants import ERR_NOTE_NOT_FOUND +from .constants import ERR_NOTE_NOT_FOUND, ERR_TOPIC_NOT_FOUND from .models import ( ContentRequest, CtrlfActionType, @@ -78,9 +78,16 @@ def create(self, validated_data): class PageSerializer(serializers.ModelSerializer): class Meta: model = Page - fields = "__all__" + fields = ["id", "created_at", "updated_at", "title", "content", "topic", "is_approved"] read_only_fields = ["id", "created_at"] + def create(self, validated_data): + owner = validated_data.pop("owner") + page = Page.objects.create(**validated_data) + page.owners.add(owner) + page.save() + return page + class ContentRequestSerializer(serializers.ModelSerializer): class Meta: @@ -150,3 +157,53 @@ def create(self, validated_data): issue = issue.save() return issue + + +class PageCreateSerializer(serializers.Serializer): + topic = serializers.IntegerField() + title = serializers.CharField() + content = serializers.CharField() + issue_content = serializers.CharField() + + def validate(self, request_data): + try: + Topic.objects.get(id=request_data["topic"]) + except Topic.DoesNotExist: + raise ValidationError(detail=ERR_TOPIC_NOT_FOUND, code=status.HTTP_404_NOT_FOUND) + return request_data + + def create(self, validated_data): + page_data = { + "topic": validated_data["topic"], + "title": validated_data["title"], + "content": validated_data["content"], + } + page = PageSerializer(data=page_data) + if not page.is_valid(): + raise ValidationError(detail="page 생성 실패", code=status.HTTP_400_BAD_REQUEST) + page = page.save(owner=validated_data["owner"]) + + content_request_data = { + "type": CtrlfContentType.PAGE, + "action": CtrlfActionType.CREATE, + "sub_id": page.id, + "user": validated_data["owner"].id, + } + content_request = ContentRequestSerializer(data=content_request_data) + if not content_request.is_valid(): + raise ValidationError(detail="content_request 생성 실패", code=status.HTTP_400_BAD_REQUEST) + content_request = content_request.save() + + issue_data = { + "owner": validated_data["owner"].id, + "content_request": content_request.id, + "title": validated_data["title"], + "content": validated_data["issue_content"], + "status": CtrlfIssueStatus.REQUESTED, + } + issue = IssueSerializer(data=issue_data) + if not issue.is_valid(): + raise ValidationError(detail="issue 생성 실패", code=status.HTTP_400_BAD_REQUEST) + issue = issue.save() + + return issue diff --git a/v2/src/ctrlfbe/views.py b/v2/src/ctrlfbe/views.py index c295f1c..6d77b77 100644 --- a/v2/src/ctrlfbe/views.py +++ b/v2/src/ctrlfbe/views.py @@ -27,6 +27,7 @@ from .serializers import ( IssueCreateSerializer, NoteSerializer, + PageCreateSerializer, PageSerializer, TopicCreateSerializer, TopicSerializer, @@ -159,3 +160,19 @@ class PageDetailUpdateDeleteView(BaseContentView): @swagger_auto_schema(**SWAGGER_PAGE_DETAIL_VIEW) def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) + + +class PageCreateView(CtrlfAuthenticationMixin, APIView): + def post(self, request, *args, **kwargs): + ctrlf_user = self._ctrlf_authentication(request) + serializer = PageCreateSerializer(data=request.data) + + if serializer.is_valid(): + serializer.save(owner=ctrlf_user) + return Response(status=status.HTTP_201_CREATED) + else: + for key, message in serializer.errors.items(): + err = message[0] + if err.code == "required": + return Response({"message": key + ERR_KEY_INPUT_MSG}, status=status.HTTP_400_BAD_REQUEST) + return Response({"message": err}, status=err.code) diff --git a/v2/src/tests/test_content_list_detail.py b/v2/src/tests/test_content_list_detail.py index ab0cdb5..0bf5646 100644 --- a/v2/src/tests/test_content_list_detail.py +++ b/v2/src/tests/test_content_list_detail.py @@ -269,7 +269,7 @@ def test_topic_create_should_return_201(self): self.assertEqual(issue.content, "test issue content") def test_topic_create_should_return_401_without_login(self): - # Given: 미리 생성된 노트, 로그인 하여 얻은 토큰, 유효한 토픽 생성 정보 + # Given: 미리 생성된 노트, 유효한 토픽 생성 정보 self.make_note() request_body = {"note": self.note.id, "title": "test title", "content": "test issue content"} @@ -327,3 +327,164 @@ def test_topic_create_should_return_400_without_content(self): # And : 메세지는 content을(를) 입력하세요. 이어야 함. response = response.data self.assertEqual(response["message"], "content을(를) 입력하세요.") + + +class TestPageCreate(TestCase): + def setUp(self) -> None: + self.client = Client() + self.data = { + "email": "test@test.com", + "password": "12345", + } + self.user = CtrlfUser.objects.create_user(**self.data) + + def _login(self): + serializer = LoginSerializer() + return serializer.validate(self.data)["token"] + + def _call_api(self, request_body, token=None): + if token: + header = {"HTTP_AUTHORIZATION": f"Bearer {token}"} + else: + header = {} + return self.client.post(reverse("pages:page_create"), request_body, **header) + + def make_note(self): + self.note = Note.objects.create(title="test note title") + self.note.owners.add(self.user) + + def make_topic(self): + self.topic = Topic.objects.create(note=self.note, title="test topic title") + self.topic.owners.add(self.user) + + def test_page_create_should_return_201(self): + # Given: 미리 생성된 노트, 토픽, 로그인 하여 얻은 토큰, 유효한 페이지 생성 정보. + self.make_note() + self.make_topic() + token = self._login() + request_body = { + "topic": self.topic.id, + "title": "test title", + "content": "test page content", + "issue_content": "test issue content", + } + + # When : API 실행. + response = self._call_api(request_body, token=token) + + # Then : 상태코드 201이어야 함. + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + # And : 생성된 페이지 정보가 일치해야 한다. + page = Page.objects.all()[0] + self.assertEqual(page.topic, self.topic) + self.assertEqual(page.title, "test title") + self.assertEqual(page.content, "test page content") + + # And : 생성된 이슈 정보와 일치해야 한다. + issue = Issue.objects.all()[0] + self.assertEqual(issue.title, "test title") + self.assertEqual(issue.content, "test issue content") + + def test_page_create_should_return_401_without_login(self): + # Given: 미리 생성된 노트, 토픽, 유효한 페이지 생성 정보 + self.make_note() + self.make_topic() + request_body = { + "topic": self.topic.id, + "title": "test title", + "content": "test page content", + "issue_content": "test issue content", + } + + # When : API 실행 + response = self._call_api(request_body) + + # Then : 상태코드 401이어야 함. + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + + def test_page_create_should_return_404_by_invalid_note_id(self): + # Given: 미리 생성된 노트, 토픽, 로그인 하여 얻은 토큰, 유효하지 않은 토픽 ID. + self.make_note() + self.make_topic() + token = self._login() + invalid_topic_id = 1234 + request_body = { + "topic": invalid_topic_id, + "title": "test title", + "content": "test page content", + "issue_content": "test issue content", + } + + # When : API 실행. + response = self._call_api(request_body, token=token) + + # Then : 상태코드 404이어야 함. + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + # And : 메세지는 토픽을 찾을 수 없습니다. 이어야 함. + response = response.data + self.assertEqual(response["message"], "토픽을 찾을 수 없습니다.") + + def test_page_create_should_return_400_without_title(self): + # Given: 미리 생성된 노트, 토픽, 로그인 하여 얻은 토큰, title 없음. + self.make_note() + self.make_topic() + token = self._login() + request_body = { + "topic": self.topic.id, + "content": "test page content", + "issue_content": "test issue content", + } + + # When : API 실행. + response = self._call_api(request_body, token=token) + + # Then : 상태코드 400이어야 함. + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + # And : 메세지는 title을(를) 입력하세요. 이어야 함. + response = response.data + self.assertEqual(response["message"], "title을(를) 입력하세요.") + + def test_page_create_should_return_400_without_content(self): + # Given: 미리 생성된 노트, 토픽, 로그인 하여 얻은 토큰, content 없음. + self.make_note() + self.make_topic() + token = self._login() + request_body = { + "topic": self.topic.id, + "title": "test title", + "issue_content": "test issue content", + } + + # When : API 실행. + response = self._call_api(request_body, token=token) + + # Then : 상태코드 400이어야 함. + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + # And : 메세지는 content을(를) 입력하세요. 이어야 함. + response = response.data + self.assertEqual(response["message"], "content을(를) 입력하세요.") + + def test_page_create_should_return_400_without_issue_content(self): + # Given: 미리 생성된 노트, 토픽, 로그인 하여 얻은 토큰, issue_content 없음. + self.make_note() + self.make_topic() + token = self._login() + request_body = { + "topic": self.topic.id, + "title": "test title", + "content": "test content", + } + + # When : API 실행. + response = self._call_api(request_body, token=token) + + # Then : 상태코드 400이어야 함. + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + # And : 메세지는 issue_content을(를) 입력하세요. 이어야 함. + response = response.data + self.assertEqual(response["message"], "issue_content을(를) 입력하세요.") From bf095f18e4e787fbf36c31a1e6cdb819c3d23c50 Mon Sep 17 00:00:00 2001 From: jrhong95 Date: Sat, 4 Sep 2021 00:20:13 +0900 Subject: [PATCH 6/7] SH-128 Rename page create test invalid_topic_id --- v2/src/tests/test_content_list_detail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/src/tests/test_content_list_detail.py b/v2/src/tests/test_content_list_detail.py index 0bf5646..5859bed 100644 --- a/v2/src/tests/test_content_list_detail.py +++ b/v2/src/tests/test_content_list_detail.py @@ -403,7 +403,7 @@ def test_page_create_should_return_401_without_login(self): # Then : 상태코드 401이어야 함. self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) - def test_page_create_should_return_404_by_invalid_note_id(self): + def test_page_create_should_return_404_by_invalid_topic_id(self): # Given: 미리 생성된 노트, 토픽, 로그인 하여 얻은 토큰, 유효하지 않은 토픽 ID. self.make_note() self.make_topic() From 322339515ea0e6a2ab4b3c800fd96401eee4a771 Mon Sep 17 00:00:00 2001 From: jrhong95 Date: Sat, 4 Sep 2021 00:34:22 +0900 Subject: [PATCH 7/7] SH-128 page create api rename swagger --- v2/src/ctrlfbe/swagger.py | 9 +++++++++ v2/src/ctrlfbe/views.py | 2 ++ 2 files changed, 11 insertions(+) diff --git a/v2/src/ctrlfbe/swagger.py b/v2/src/ctrlfbe/swagger.py index 39958b1..ee0fe6c 100644 --- a/v2/src/ctrlfbe/swagger.py +++ b/v2/src/ctrlfbe/swagger.py @@ -2,6 +2,7 @@ NoteCreateRequestBodySerializer, NoteListQuerySerializer, NoteSerializer, + PageCreateSerializer, PageSerializer, TopicCreateSerializer, TopicSerializer, @@ -63,3 +64,11 @@ "operation_description": "미승인 토픽을 생성하고 토픽 생성 이슈를 등록합니다.", "tags": ["디테일 화면"], } + +SWAGGER_PAGE_CREATE_VIEW = { + "request_body": PageCreateSerializer, + "responses": {201: ""}, + "operation_summary": "Page Create API", + "operation_description": "미승인 페이지를 생성하고 페이지 생성 이슈를 등록합니다.", + "tags": ["디테일 화면"], +} diff --git a/v2/src/ctrlfbe/views.py b/v2/src/ctrlfbe/views.py index 6d77b77..f0a5667 100644 --- a/v2/src/ctrlfbe/views.py +++ b/v2/src/ctrlfbe/views.py @@ -5,6 +5,7 @@ SWAGGER_NOTE_CREATE_VIEW, SWAGGER_NOTE_DETAIL_VIEW, SWAGGER_NOTE_LIST_VIEW, + SWAGGER_PAGE_CREATE_VIEW, SWAGGER_PAGE_DETAIL_VIEW, SWAGGER_PAGE_LIST_VIEW, SWAGGER_TOPIC_CREATE_VIEW, @@ -163,6 +164,7 @@ def get(self, request, *args, **kwargs): class PageCreateView(CtrlfAuthenticationMixin, APIView): + @swagger_auto_schema(**SWAGGER_PAGE_CREATE_VIEW) def post(self, request, *args, **kwargs): ctrlf_user = self._ctrlf_authentication(request) serializer = PageCreateSerializer(data=request.data)