diff --git a/.github/prlint.json b/.github/prlint.json index 98f52b5..f4fa4e0 100644 --- a/.github/prlint.json +++ b/.github/prlint.json @@ -1,8 +1,6 @@ { - "title": [ - { - "pattern": "^(TH-|JH-|SH-|JG-)\\d+: .+$", - "message": "{personal initial above}-{issue number}: {pr title} - ex) TH-150: add test prlint.json" - } - ] + "title": [{ + "pattern": "^(TH-|JH-|SH-|JG-)\\d+: .+$", + "message": "{personal initial above}-{issue number}: {pr title} - ex) TH-150: add test prlint.json" + }] } diff --git a/v2/src/config/urls.py b/v2/src/config/urls.py index 535fd02..b6963bb 100644 --- a/v2/src/config/urls.py +++ b/v2/src/config/urls.py @@ -25,5 +25,6 @@ path("api/auth/", include("ctrlf_auth.urls"), name="auth"), path("api/notes/", include("ctrlfbe.note_urls"), name="notes"), path("api/topics/", include("ctrlfbe.topic_urls"), name="topics"), + path("api/issues/", include("ctrlfbe.issue_urls"), name="issues"), path("api/pages/", include("ctrlfbe.page_urls"), name="pages"), ] diff --git a/v2/src/ctrlfbe/constants.py b/v2/src/ctrlfbe/constants.py index f14fd14..36e42f9 100644 --- a/v2/src/ctrlfbe/constants.py +++ b/v2/src/ctrlfbe/constants.py @@ -1,4 +1,5 @@ MAX_PRINTABLE_NOTE_COUNT = 30 +MAX_PRINTABLE_ISSUE_COUNT = 30 ERR_NOTE_NOT_FOUND = "노트를 찾을 수 없습니다." ERR_TOPIC_NOT_FOUND = "토픽을 찾을 수 없습니다." ERR_PAGE_NOT_FOUND = "페이지를 찾을 수 없습니다." diff --git a/v2/src/ctrlfbe/issue_urls.py b/v2/src/ctrlfbe/issue_urls.py new file mode 100644 index 0000000..47f28d1 --- /dev/null +++ b/v2/src/ctrlfbe/issue_urls.py @@ -0,0 +1,9 @@ +from django.urls import path + +from .views import IssueListView + +app_name = "issues" + +urlpatterns = [ + path("", IssueListView.as_view(), name="issue_list"), +] diff --git a/v2/src/ctrlfbe/migrations/0006_auto_20210901_1507.py b/v2/src/ctrlfbe/migrations/0006_auto_20210901_1507.py new file mode 100644 index 0000000..9bda3f5 --- /dev/null +++ b/v2/src/ctrlfbe/migrations/0006_auto_20210901_1507.py @@ -0,0 +1,30 @@ +# Generated by Django 3.2.5 on 2021-09-01 06:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("ctrlfbe", "0005_page_is_approved"), + ] + + operations = [ + migrations.AddField( + model_name="contentrequest", + name="status", + field=models.CharField( + choices=[("PENDING", "보류"), ("REJECTED", "거절"), ("ACCEPTED", "승인")], + default="PENDING", + help_text="Content 상태들", + max_length=30, + ), + ), + migrations.AlterField( + model_name="issue", + name="status", + field=models.CharField( + choices=[("REQUESTED", "요청"), ("CLOSED", "닫힘")], help_text="Issue 상태들", max_length=30 + ), + ), + ] diff --git a/v2/src/ctrlfbe/models.py b/v2/src/ctrlfbe/models.py index 9c60933..cf6d307 100644 --- a/v2/src/ctrlfbe/models.py +++ b/v2/src/ctrlfbe/models.py @@ -17,16 +17,23 @@ class CtrlfActionType(models.TextChoices): class CtrlfIssueStatus(models.TextChoices): REQUESTED = "REQUESTED", "요청" - REJECTED = "REJECTED", "거절" - APPROVED = "APPROVED", "승인" CLOSED = "CLOSED", "닫힘" +class CtrlfContentStatus(models.TextChoices): + PENDING = "PENDING", "보류" + REJECTED = "REJECTED", "거절" + ACCEPTED = "ACCEPTED", "승인" + + class ContentRequest(CommonTimestamp): user = models.ForeignKey(CtrlfUser, on_delete=models.CASCADE, help_text="수정 혹은 삭제의 주체자") sub_id = models.IntegerField(help_text="type에 대한 id") type = models.CharField(max_length=30, choices=CtrlfContentType.choices, help_text="NOTE, TOPIC, PAGE") action = models.CharField(max_length=30, choices=CtrlfActionType.choices, help_text="CRUD") + status = models.CharField( + max_length=30, choices=CtrlfContentStatus.choices, default=CtrlfContentStatus.PENDING, help_text="Content 상태들" + ) reason = models.TextField(default="", help_text="수정 혹은 삭제 이유") is_active = models.BooleanField(default=False) diff --git a/v2/src/ctrlfbe/serializers.py b/v2/src/ctrlfbe/serializers.py index c04a13c..3fc2b44 100644 --- a/v2/src/ctrlfbe/serializers.py +++ b/v2/src/ctrlfbe/serializers.py @@ -3,6 +3,7 @@ from .models import ( ContentRequest, CtrlfActionType, + CtrlfContentStatus, CtrlfContentType, Issue, Note, @@ -11,6 +12,75 @@ ) +class ContentRequestSerializer(serializers.ModelSerializer): + class Meta: + model = ContentRequest + fields = ["user", "sub_id", "type", "action", "reason", "status"] + + +class IssueSerializer(serializers.ModelSerializer): + content_request = ContentRequestSerializer() + + class Meta: + model = Issue + fields = ["id", "owner", "title", "content", "status", "content_request"] + + def to_representation(self, instance): + def get_note_owners(note_id, creator): + note = Note.objects.get(id=note_id) + serializer = NoteSerializer(note) + serializered_note = serializer.data + + creator["note"] = serializered_note["owners"] + return creator + + def get_topic_owners(topic_id, creator): + topic = Topic.objects.get(id=topic_id) + serializer = TopicSerializer(topic) + serializered_topic = serializer.data + creator["topic"] = serializered_topic["owners"] + return get_note_owners(serializered_topic["note"], creator) + + def get_page_owners(page_id, creator): + page = Page.objects.get(id=page_id) + serializer = PageSerializer(page) + serializered_page = serializer.data + creator["page"] = serializered_page["owners"] + return get_topic_owners(serializered_page["topic"], creator) + + def make_creator(type, target_id): + creator = { + "note": None, + "topic": None, + "page": None, + } + + if type == "NOTE": + creator = get_note_owners(target_id, creator) + elif type == "TOPIC": + creator = get_topic_owners(target_id, creator) + elif type == "PAGE": + creator = get_page_owners(target_id, creator) + + return creator + + issue = super().to_representation(instance) + creator = make_creator(issue["content_request"]["type"], issue["content_request"]["sub_id"]) + + return { + "id": issue["id"], + "title": issue["title"], + "content": issue["content"], + "action": issue["content_request"]["action"], + "content_id": issue["content_request"]["sub_id"], + "content_type": issue["content_request"]["type"], + "content_status": issue["content_request"]["status"], + "issue_status": issue["status"], + "reason": issue["content_request"]["reason"], + "creator": creator, + } + + class NoteListSerializer(serializers.ListSerializer): pass @@ -42,6 +112,7 @@ def create(self, validated_data): "sub_id": note.id, "type": CtrlfContentType.NOTE, "action": CtrlfActionType.CREATE, + "status": CtrlfContentStatus.PENDING, "reason": "create note", } content_request = ContentRequest.objects.create(**content_request_data) diff --git a/v2/src/ctrlfbe/swagger.py b/v2/src/ctrlfbe/swagger.py index 2c1c223..6d1d0b5 100644 --- a/v2/src/ctrlfbe/swagger.py +++ b/v2/src/ctrlfbe/swagger.py @@ -1,4 +1,5 @@ from ctrlfbe.serializers import ( + IssueSerializer, NoteCreateRequestBodySerializer, NoteListQuerySerializer, NoteSerializer, @@ -34,6 +35,13 @@ "tags": ["메인 화면"], } +SWAGGER_ISSUE_LIST_VIEW = { + "responses": {200: IssueSerializer(many=True)}, + "operation_summary": "Issue List API", + "operation_description": "모든 issue들의 list를 리턴해줍니다", + "tags": ["이슈 화면"], +} + SWAGGER_NOTE_CREATE_VIEW = { "operation_summary": "Note Create API", "operation_description": "비활성화된 Note와 이슈를 생성 합니다.", diff --git a/v2/src/ctrlfbe/views.py b/v2/src/ctrlfbe/views.py index f3069e9..f5f9746 100644 --- a/v2/src/ctrlfbe/views.py +++ b/v2/src/ctrlfbe/views.py @@ -1,7 +1,9 @@ -from typing import Optional +import json +from typing import List, Optional from ctrlfbe.mixins import CtrlfAuthenticationMixin from ctrlfbe.swagger import ( + SWAGGER_ISSUE_LIST_VIEW, SWAGGER_NOTE_CREATE_VIEW, SWAGGER_NOTE_DETAIL_VIEW, SWAGGER_NOTE_LIST_VIEW, @@ -16,10 +18,16 @@ 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 .models import CtrlfIssueStatus, Note, Page, Topic +from .constants import ( + ERR_NOT_FOUND_MSG_MAP, + ERR_UNEXPECTED, + MAX_PRINTABLE_ISSUE_COUNT, + MAX_PRINTABLE_NOTE_COUNT, +) +from .models import CtrlfIssueStatus, Issue, Note, Page, Topic from .serializers import ( IssueCreateSerializer, + IssueSerializer, NoteSerializer, PageSerializer, TopicSerializer, @@ -128,6 +136,48 @@ def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) +class IssueListView(CtrlfAuthenticationMixin, APIView): + authentication_classes: List[str] = [] + + @swagger_auto_schema(**SWAGGER_ISSUE_LIST_VIEW) + def get(self, request): + ctrlf_user = self._ctrlf_authentication(request) + + current_cursor = int(request.query_params["cursor"]) + typeList = json.loads(request.query_params["type"]) + mine = request.query_params["mine"] + + issues = Issue.objects.all() + filtered_issues = issues + + if mine == "true": + temp_list = [] + for issue in filtered_issues: + if ctrlf_user.id == issue["owner_id"]: + temp_list.append(issue) + filtered_issues = temp_list + + if len(typeList) > 0: + temp_list = [] + for issue in filtered_issues: + if typeList in issue["content_type"]: + temp_list.append(issue) + filtered_issues = temp_list + + if current_cursor >= len(issues): + return Response({"next_cursor": len(issues), "issues": []}, status.HTTP_200_OK) + elif current_cursor + MAX_PRINTABLE_ISSUE_COUNT > len(issues): + sliced_issues = issues[current_cursor : len(issues)] + next_cursor = len(issues) + else: + sliced_issues = issues[current_cursor : current_cursor + MAX_PRINTABLE_ISSUE_COUNT] + next_cursor = current_cursor + MAX_PRINTABLE_ISSUE_COUNT + serializer = IssueSerializer(data=sliced_issues, many=True) + serializer.is_valid() + serialized_issues = serializer.data + return Response(data={"next_cursor": next_cursor, "issues": serialized_issues}, status=status.HTTP_200_OK) + + class PageDetailUpdateDeleteView(BaseContentView): parent_model = Page serializer = PageSerializer diff --git a/v2/src/tests/test_content_list_detail.py b/v2/src/tests/test_content_list_detail.py index d1a393c..39d0f7f 100644 --- a/v2/src/tests/test_content_list_detail.py +++ b/v2/src/tests/test_content_list_detail.py @@ -151,7 +151,7 @@ def test_page_list_should_return_404_by_invalid_topic_id(self): self.assertEqual(response["message"], "토픽을 찾을 수 없습니다.") -class TestTopicDetail(TestCase): +class TestPageDetail(TestCase): def setUp(self): self.c = Client() self.user = CtrlfUser.objects.create_user(email="test@test.com", password="12345") @@ -159,32 +159,36 @@ def setUp(self): self.note.owners.add(self.user) self.topic = Topic.objects.create(note=self.note, title="test topic") self.topic.owners.add(self.user) + page_data = {"topic": self.topic, "title": "test page", "content": "test content"} + self.page = Page.objects.create(**page_data) + self.page.owners.add(self.user) - def test_topic_detail_should_return_200(self): - # Given : 유효한 topic id, 이미 저장된 topic - topic_id = self.topic.id + def test_page_detail_should_return_200(self): + # Given : 유효한 page id, 이미 저장된 page + page_id = self.page.id # When : API 실행 - response = self.c.get(reverse("topics:topic_detail", kwargs={"topic_id": topic_id})) + response = self.c.get(reverse("pages:page_detail", kwargs={"page_id": page_id})) # Then : 상태코드 200 self.assertEqual(response.status_code, status.HTTP_200_OK) # And : 불러온 정보가 저장된 정보와 일치해야 한다. response = response.data - self.assertEqual(response["title"], "test topic") - self.assertEqual(response["note"], self.note.id) + self.assertEqual(response["title"], "test page") + self.assertEqual(response["content"], "test content") + self.assertEqual(response["topic"], self.topic.id) - def test_topic_detail_should_return_404_by_invalid_topic_id(self): - # Given : 유효하지 않은 topic id, 이미 저장된 topic - invalid_topic_id = 1234 + def test_page_detail_should_return_404_by_invalid_page_id(self): + # Given : 유효하지 않은 page id, 이미 저장된 page + invalid_page_id = 1234 # When : API 실행 - response = self.c.get(reverse("topics:topic_detail", kwargs={"topic_id": invalid_topic_id})) + response = self.c.get(reverse("pages:page_detail", kwargs={"page_id": invalid_page_id})) # Then : 상태코드 404 self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) - # And : 메세지는 "토픽을 찾을 수 없습니다." 이어야 한다. + # And : 메세지는 "페이지를 찾을 수 없습니다." 이어야 한다. response = response.data - self.assertEqual(response["message"], "토픽을 찾을 수 없습니다.") + self.assertEqual(response["message"], "페이지를 찾을 수 없습니다.") -class TestPageDetail(TestCase): +class TestTopicDetail(TestCase): def setUp(self): self.c = Client() self.user = CtrlfUser.objects.create_user(email="test@test.com", password="12345") @@ -192,30 +196,26 @@ def setUp(self): self.note.owners.add(self.user) self.topic = Topic.objects.create(note=self.note, title="test topic") self.topic.owners.add(self.user) - page_data = {"topic": self.topic, "title": "test page", "content": "test content"} - self.page = Page.objects.create(**page_data) - self.page.owners.add(self.user) - def test_page_detail_should_return_200(self): - # Given : 유효한 page id, 이미 저장된 page - page_id = self.page.id + def test_topic_detail_should_return_200(self): + # Given : 유효한 topic id, 이미 저장된 topic + topic_id = self.topic.id # When : API 실행 - response = self.c.get(reverse("pages:page_detail", kwargs={"page_id": page_id})) + response = self.c.get(reverse("topics:topic_detail", kwargs={"topic_id": topic_id})) # Then : 상태코드 200 self.assertEqual(response.status_code, status.HTTP_200_OK) # And : 불러온 정보가 저장된 정보와 일치해야 한다. response = response.data - self.assertEqual(response["title"], "test page") - self.assertEqual(response["content"], "test content") - self.assertEqual(response["topic"], self.topic.id) + self.assertEqual(response["title"], "test topic") + self.assertEqual(response["note"], self.note.id) - def test_page_detail_should_return_404_by_invalid_page_id(self): - # Given : 유효하지 않은 page id, 이미 저장된 page - invalid_page_id = 1234 + def test_topic_detail_should_return_404_by_invalid_topic_id(self): + # Given : 유효하지 않은 topic id, 이미 저장된 topic + invalid_topic_id = 1234 # When : API 실행 - response = self.c.get(reverse("pages:page_detail", kwargs={"page_id": invalid_page_id})) + response = self.c.get(reverse("topics:topic_detail", kwargs={"topic_id": invalid_topic_id})) # Then : 상태코드 404 self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) - # And : 메세지는 "페이지를 찾을 수 없습니다." 이어야 한다. + # And : 메세지는 "토픽을 찾을 수 없습니다." 이어야 한다. response = response.data - self.assertEqual(response["message"], "페이지를 찾을 수 없습니다.") + self.assertEqual(response["message"], "토픽을 찾을 수 없습니다.") diff --git a/v2/src/tests/test_issue.py b/v2/src/tests/test_issue.py new file mode 100644 index 0000000..750fd62 --- /dev/null +++ b/v2/src/tests/test_issue.py @@ -0,0 +1,270 @@ +from ctrlf_auth.models import CtrlfUser +from ctrlf_auth.serializers import LoginSerializer +from ctrlfbe.models import ( + ContentRequest, + CtrlfActionType, + CtrlfContentStatus, + CtrlfContentType, + CtrlfIssueStatus, + Issue, + Note, + Page, + Topic, +) +from django.test import Client, TestCase +from django.urls import reverse +from rest_framework import status + + +class TestIssueList(TestCase): + def setUp(self): + self.c = Client() + self.user_data = { + "email": "note_creator1@test.com", + "password": "12345", + } + self.note_creator1 = CtrlfUser.objects.create_user(**self.user_data) + self.note_creator2 = CtrlfUser.objects.create_user(email="note_creator2@test.com", password="12345") + self.topic_creator = CtrlfUser.objects.create_user(email="topic_creator@test.com", password="12345") + self.page_creator1 = CtrlfUser.objects.create_user(email="page_creator1@test.com", password="12345") + self.page_creator2 = CtrlfUser.objects.create_user(email="page_creator2@test.com", password="12345") + self.note = Note.objects.create(title="test note") + self.note.owners.add(self.note_creator1) + self.note.owners.add(self.note_creator2) + topic_data = {"note": self.note, "title": "test topic"} + self.topic = Topic.objects.create(**topic_data) + self.topic.owners.add(self.topic_creator) + page_data = {"topic": self.topic, "title": "test page"} + self.page = Page.objects.create(**page_data) + self.page.owners.add(self.page_creator1) + self.page.owners.add(self.page_creator2) + self.owner = CtrlfUser.objects.create_user(email="owner@test.com", password="12345") + + def _add_issues(self, count): + issue_list = [] + for i in range(0, count): + content_request_data = { + "user": self.note_creator1, + "sub_id": self.note.id, + "type": CtrlfContentType.NOTE, + "action": CtrlfActionType.CREATE, + "status": CtrlfContentStatus.PENDING, + "reason": "test reason{}".format(i + 1), + "is_active": True, + } + content_request = ContentRequest.objects.create(**content_request_data) + issue_data = { + "owner": self.owner, + "title": "test issue{}".format(i + 1), + "content": "test content{}".format(i + 1), + "status": CtrlfIssueStatus.REQUESTED, + "content_request": content_request, + } + issue = Issue.objects.create(**issue_data) + issue_list.append(issue) + return issue_list + + def _add_topic_issue(self): + content_request_data = { + "user": self.note_creator1, + "sub_id": self.topic.id, + "type": CtrlfContentType.TOPIC, + "action": CtrlfActionType.CREATE, + "status": CtrlfContentStatus.PENDING, + "reason": "test reason", + "is_active": True, + } + content_request = ContentRequest.objects.create(**content_request_data) + issue_data = { + "owner": self.owner, + "title": "test issue", + "content": "test content", + "status": CtrlfIssueStatus.REQUESTED, + "content_request": content_request, + } + issue = Issue.objects.create(**issue_data) + return issue + + def _add_page_issue(self): + content_request_data = { + "user": self.note_creator1, + "sub_id": self.page.id, + "type": CtrlfContentType.PAGE, + "action": CtrlfActionType.CREATE, + "status": CtrlfContentStatus.PENDING, + "reason": "test reason", + "is_active": True, + } + content_request = ContentRequest.objects.create(**content_request_data) + issue_data = { + "owner": self.owner, + "title": "test issue", + "content": "test content", + "status": CtrlfIssueStatus.REQUESTED, + "content_request": content_request, + } + issue = Issue.objects.create(**issue_data) + return issue + + def _call_api(self, cursor, type, mine, token=None): + if token: + header = {"HTTP_AUTHORIZATION": f"Bearer {token}"} + else: + header = {} + return self.c.get(reverse("issues:issue_list"), {"cursor": cursor, "type": type, "mine": mine}, **header) + + def _login(self): + serializer = LoginSerializer() + return serializer.validate(self.user_data)["token"] + + def test_issue_list_should_return_200(self): + # Given: 2개의 이슈를 생성하고, cursor는 0, type은 [], mine은 false로 주어진다. + self._add_issues(2) + given_cursor = 0 + given_type = "[]" + given_mine = "false" + + # And: 로그인해서 토큰을 발급받은 상황이다. + token = self._login() + + # When : API 실행 + response = self._call_api(given_cursor, given_type, given_mine, token) + # Then : 상태코드 200 + self.assertEqual(response.status_code, status.HTTP_200_OK) + # And : 첫번째 이슈의 title은 "test issue1" 이어야 한다. + self.assertEqual(response.data["issues"][0]["title"], "test issue1") + # And : 두번째 이슈의 title은 "test issue2" 이어야 한다. + self.assertEqual(response.data["issues"][1]["title"], "test issue2") + + def test_issue_list_shoud_return_200_and_note_owner_is_list(self): + # Given: 1개의 이슈를 생성하고, cursor는 0, type은 [], mine은 false로 주어진다. + self._add_issues(1) + given_cursor = 0 + given_type = "[]" + given_mine = "false" + + # And: 로그인해서 토큰을 발급받은 상황이다. + token = self._login() + + # When : API 실행 + response = self._call_api(given_cursor, given_type, given_mine, token) + # Then : 상태코드 200 + self.assertEqual(response.status_code, status.HTTP_200_OK) + # And : 이슈의 creator의 노트의 값은 [1, 2] 이어야 한다. + self.assertEqual(response.data["issues"][0]["creator"]["note"], [1, 2]) + + def test_issue_list_shoud_return_200_and_topic_owner_is_list(self): + # Given: 1개의 콘텐츠 타입이 토픽인 이슈를 생성하고, cursor는 0, type은 [], mine은 false로 주어진다. + self._add_topic_issue() + given_cursor = 0 + given_type = "[]" + given_mine = "false" + + # And: 로그인해서 토큰을 발급받은 상황이다. + token = self._login() + + # When : API 실행 + response = self._call_api(given_cursor, given_type, given_mine, token) + # Then : 상태코드 200 + self.assertEqual(response.status_code, status.HTTP_200_OK) + # And : 이슈의 creator의 노트의 값은 [1, 2] 이어야 한다. + self.assertEqual(response.data["issues"][0]["creator"]["note"], [1, 2]) + # And : 이슈의 creator의 토픽의 값은 [1] 이어야 한다. + self.assertEqual(response.data["issues"][0]["creator"]["topic"], [3]) + + def test_issue_list_shoud_return_200_and_page_owner_is_list(self): + # Given: 1개의 콘텐츠 타입이 페이지인 이슈를 생성하고, cursor는 0, type은 [], mine은 false로 주어진다. + self._add_page_issue() + given_cursor = 0 + given_type = "[]" + given_mine = "false" + + # And: 로그인해서 토큰을 발급받은 상황이다. + token = self._login() + + # When : API 실행 + response = self._call_api(given_cursor, given_type, given_mine, token) + # Then : 상태코드 200 + self.assertEqual(response.status_code, status.HTTP_200_OK) + # And : 이슈의 creator의 노트의 값은 [1, 2] 이어야 한다. + self.assertEqual(response.data["issues"][0]["creator"]["note"], [1, 2]) + # And : 이슈의 creator의 토픽의 값은 [1] 이어야 한다. + self.assertEqual(response.data["issues"][0]["creator"]["topic"], [3]) + # And : 이슈의 creator의 페이지의 값은 [1, 2] 이어야 한다. + self.assertEqual(response.data["issues"][0]["creator"]["page"], [4, 5]) + + def test_issue_list_should_return_200_by_thirty_issue_list(self): + + # Given: 30개의 이슈를 생성하고, cursor는 0, type은 [], mine은 false로 주어진다. + self._add_issues(30) + given_cursor = 0 + given_type = "[]" + given_mine = "false" + + # And: 로그인해서 토큰을 발급받은 상황이다. + token = self._login() + + # When : API 실행 + response = self._call_api(given_cursor, given_type, given_mine, token) + # Then : 상태코드 200 + self.assertEqual(response.status_code, status.HTTP_200_OK) + # And : next_cursor는 30을 리턴한다. + self.assertEqual(response.data["next_cursor"], 30) + # And : 시작 cursor부터 30개의 이슈 리스트를 return 해야함. + self.assertEqual(len(response.data["issues"]), 30) + + def test_issue_list_should_return_200_by_ten_issue_list(self): + # Given: 10개의 이슈를 생성하고, cursor는 0, type은 [], mine은 false로 주어진다. + self._add_issues(10) + given_cursor = 5 + given_type = "[]" + given_mine = "false" + + # And: 로그인해서 토큰을 발급받은 상황이다. + token = self._login() + + # When : API 실행 + response = self._call_api(given_cursor, given_type, given_mine, token) + # Then : 상태코드 200 + self.assertEqual(response.status_code, status.HTTP_200_OK) + # And : next_cursor는 10을 리턴한다. + self.assertEqual(response.data["next_cursor"], 10) + # And : 시작 cursor부터 5개의 이슈 리스트를 return 해야함. + self.assertEqual(len(response.data["issues"]), 5) + + def test_issue_list_should_return_200_by_ten_issue_list_and_cursor_fifteen(self): + # Given: 10개의 이슈를 생성하고, cursor는 15로 주어진다. + self._add_issues(10) + given_cursor = 15 + given_type = "[]" + given_mine = "false" + + # And: 로그인해서 토큰을 발급받은 상황이다. + token = self._login() + + # When : API 실행 + response = self._call_api(given_cursor, given_type, given_mine, token) + # Then : 상태코드 200 + self.assertEqual(response.status_code, status.HTTP_200_OK) + # And : next_cursor는 10을 리턴한다. + self.assertEqual(response.data["next_cursor"], 10) + # And : 빈 배열을 return 해야함. + self.assertEqual(response.data["issues"], []) + + def test_issue_list_should_return_200_by_empty_issue_list(self): + # Given: 이슈 생성 없이, cursor는 0, type은 [], mine은 false로 주어진다. + given_cursor = 0 + given_type = "[]" + given_mine = "false" + + # And: 로그인해서 토큰을 발급받은 상황이다. + token = self._login() + + # When : API 실행 + response = self._call_api(given_cursor, given_type, given_mine, token) + # Then : 상태코드 200 + self.assertEqual(response.status_code, status.HTTP_200_OK) + # And : next_cursor는 0, type은 [], mine은 false 리턴한다. + self.assertEqual(response.data["next_cursor"], 0) + # And : 빈 배열을 return 해야함. + self.assertEqual(response.data["issues"], [])