Example #1
0
 def setUp(self):
     # NOTE: these elements get modified by some testcases, so they should NOT be created in setUpTestData()
     self.project = Project(creator=self.user1, name_short='asdf')
     self.project.save()
     self.project.developer.add(self.user1)
     self.project.developer.add(self.user2)
     self.project.manager.add(self.user1)
     self.project2 = Project(creator=self.user2, name_short='asdg')
     self.project2.save()
     self.project2.manager.add(self.user2)
     self.issue = Issue(title='test', project=self.project)
     self.issue.save()
     self.issue2 = Issue(title='test', project=self.project2)
     self.issue2.save()
     self.comment = Comment(text='test', creator=self.user1, issue=self.issue)
     self.comment.save()
     self.comment2 = Comment(text='test', creator=self.user2, issue=self.issue2)
     self.comment2.save()
     self.log = Timelog(time=datetime.timedelta(hours=2), user=self.user1, issue=self.issue)
     self.log.save()
     self.log2 = Timelog(time=datetime.timedelta(hours=2), user=self.user2, issue=self.issue2)
     self.log2.save()
     self.user1_auth = 'Basic ' + base64.b64encode('user1:c'.encode()).decode()
     self.user2_auth = 'Basic ' + base64.b64encode('user2:c'.encode()).decode()
     self.client.credentials(HTTP_AUTHORIZATION=self.user1_auth)
Example #2
0
 def test_issue_detail_log_form(self):
     driver = self.selenium
     t = Timelog(user=self.user, issue=self.issue, time=timedelta(hours=3))
     t.save()
     driver.get('{}{}'.format(
         self.live_server_url,
         reverse('issue:detail',
                 kwargs={
                     'project': self.project.name_short,
                     'sqn_i': self.issue.number
                 })))
     entry = driver.find_element_by_id("issue_detail_log_1")
     self.assertIn('3 Hour', entry.text)
Example #3
0
 def test_get_timelogs(self):
     response = self.client.get(reverse('api:timelogs-list'))
     self.assertEqual(response.status_code, status.HTTP_200_OK)
     self.assertEqual(response.json().get('count'), 1)
     issue = Issue(title='asdf', project=self.project)
     issue.save()
     log = Timelog(issue=issue,
                   user=self.user1,
                   time=datetime.timedelta(hours=2))
     log.save()
     response = self.client.get(reverse('api:timelogs-list'))
     self.assertEqual(response.status_code, status.HTTP_200_OK)
     self.assertEqual(response.json().get('count'), 2)
Example #4
0
def test(request):
    user_id = 'U97G8HY69'
    user_profile = Profile.objects.get(slack_id=user_id)
    user = user_profile.user

    text = '140 this is taking forever'
    time_obj = TimeParse(text)
    timelog = Timelog()
    timelog.person = user
    timelog.logdate = today
    timelog.minutes = time_obj.minutes
    timelog.description = time_obj.description
    timelog.work_day = time_obj.day

    timelog.save()

    return "Did it work?"  #9
Example #5
0
    def test_delete_with_timelog(self):
        issue = Issue(title="foo")
        issue.project = self.project
        issue.save()
        Timelog(user=self.user, issue=issue, time=timedelta(1)).save()

        response = self.client.post(reverse('issue:delete',
                                            kwargs={
                                                'project':
                                                self.project.name_short,
                                                'sqn_i': issue.number
                                            }), {'delete': 'true'},
                                    follow=True)
        self.assertRedirects(
            response,
            reverse('issue:backlog',
                    kwargs={'project': self.project.name_short}))
        self.assertContains(response, "foo")
        self.assertContains(response, "logged time")
Example #6
0
class ApiPermissionTest(APITestCase):
    @classmethod
    def setUpTestData(cls):
        # NOTE: if you modify those elements they need to be created in setUp(), instead of here
        cls.user1 = get_user_model().objects.create_user('user1', 'mail', 'c')
        cls.user2 = get_user_model().objects.create_user('user2', 'othermail', 'c')

    def setUp(self):
        # NOTE: these elements get modified by some testcases, so they should NOT be created in setUpTestData()
        self.project = Project(creator=self.user1, name_short='asdf')
        self.project.save()
        self.project.developer.add(self.user1)
        self.project.developer.add(self.user2)
        self.project.manager.add(self.user1)
        self.project2 = Project(creator=self.user2, name_short='asdg')
        self.project2.save()
        self.project2.manager.add(self.user2)
        self.issue = Issue(title='test', project=self.project)
        self.issue.save()
        self.issue2 = Issue(title='test', project=self.project2)
        self.issue2.save()
        self.comment = Comment(text='test', creator=self.user1, issue=self.issue)
        self.comment.save()
        self.comment2 = Comment(text='test', creator=self.user2, issue=self.issue2)
        self.comment2.save()
        self.log = Timelog(time=datetime.timedelta(hours=2), user=self.user1, issue=self.issue)
        self.log.save()
        self.log2 = Timelog(time=datetime.timedelta(hours=2), user=self.user2, issue=self.issue2)
        self.log2.save()
        self.user1_auth = 'Basic ' + base64.b64encode('user1:c'.encode()).decode()
        self.user2_auth = 'Basic ' + base64.b64encode('user2:c'.encode()).decode()
        self.client.credentials(HTTP_AUTHORIZATION=self.user1_auth)

    def try_project_put_patch_delete(self, expected):
        project_data = {
            'name': 'yoflow',
        }
        response = self.client.patch(reverse('api:project-detail', kwargs={'name_short': self.project.name_short}),
                                     data=project_data)
        self.assertEqual(response.status_code, expected)
        response = self.client.put(reverse('api:project-detail', kwargs={'name_short': self.project.name_short}),
                                   data=project_data)
        self.assertEqual(response.status_code, expected)
        response = self.client.delete(reverse('api:project-detail', kwargs={'name_short': self.project.name_short}))
        self.assertEqual(response.status_code, expected)

    def test_project_permissions(self):
        # project1 granted
        response = self.client.get(reverse('api:project-detail', kwargs={'name_short': self.project.name_short}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        # project2 denied for user1
        response = self.client.get(reverse('api:project-detail', kwargs={'name_short': self.project2.name_short}))
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
        # project2 granted for user2
        self.client.credentials(HTTP_AUTHORIZATION=self.user2_auth)
        response = self.client.get(reverse('api:project-detail', kwargs={'name_short': self.project2.name_short}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        # project1 user2 put, patch, delete denied (no manager)
        self.try_project_put_patch_delete(status.HTTP_403_FORBIDDEN)

        # no credentials
        self.client.credentials()
        self.try_project_put_patch_delete(status.HTTP_401_UNAUTHORIZED)

    def test_project_issues_get_post_permissions(self):
        issue_data = {
                'title': 'laalalla'
                }
        # project1 granted
        response = self.client.get(reverse('api:project_issues-list', kwargs={'project': self.project.name_short}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        response = self.client.post(reverse('api:project_issues-list', kwargs={'project': self.project.name_short}),
                                    issue_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        # project2 denied for user1
        response = self.client.get(reverse('api:project_issues-list', kwargs={'project': self.project2.name_short}))
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
        response = self.client.post(reverse('api:project_issues-list', kwargs={'project': self.project2.name_short}),
                                    issue_data)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
        # project2 granted for user2
        self.client.credentials(HTTP_AUTHORIZATION=self.user2_auth)
        response = self.client.get(reverse('api:project_issues-list', kwargs={'project': self.project2.name_short}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        response = self.client.post(reverse('api:project_issues-list', kwargs={'project': self.project2.name_short}),
                                    issue_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # no credentials
        self.client.credentials()
        response = self.client.get(reverse('api:project_issues-list', kwargs={'project': self.project2.name_short}))
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
        response = self.client.post(reverse('api:project_issues-list', kwargs={'project': self.project2.name_short}),
                                    issue_data)
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    def try_issue_put_patch_delete(self, expected):
        issue_data = {
            'title': 'yoflow',
        }
        url = 'api:project_issues-detail'
        response = self.client.get(reverse(url, kwargs={'project': self.project2.name_short,
                                                        'number': self.issue2.number}))
        self.assertIn(response.status_code, expected)
        response = self.client.patch(reverse(url, kwargs={'project': self.project2.name_short,
                                                          'number': self.issue2.number}),
                                     data=issue_data)
        self.assertIn(response.status_code, expected)
        response = self.client.put(reverse(url, kwargs={'project': self.project2.name_short,
                                                        'number': self.issue2.number}),
                                   data=issue_data)
        self.assertIn(response.status_code, expected)
        response = self.client.delete(reverse(url, kwargs={'project': self.project2.name_short,
                                                           'number': self.issue2.number}))
        self.assertIn(response.status_code, expected)

    def test_project_issues_detail_put_patch_delete_permissions(self):

        # user1 not in project1
        self.try_issue_put_patch_delete([status.HTTP_403_FORBIDDEN])

        # user2 in project2
        self.client.credentials(HTTP_AUTHORIZATION=self.user2_auth)
        self.try_issue_put_patch_delete([status.HTTP_200_OK, status.HTTP_204_NO_CONTENT])

        # not credentials
        self.client.credentials()
        self.try_issue_put_patch_delete([status.HTTP_401_UNAUTHORIZED])

    def test_project_issue_comments_get_post_permissions(self):
        comment_data = {
                'text': 'laalalla'
                }
        # project1 granted
        response = self.client.get(reverse('api:project_issues_comments-list',
                                           kwargs={'project': self.project.name_short, 'issue': self.issue.number}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        response = self.client.post(reverse('api:project_issues_comments-list',
                                            kwargs={'project': self.project.name_short, 'issue': self.issue.number}),
                                    comment_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        # project2 denied for user1
        response = self.client.get(reverse('api:project_issues_comments-list',
                                           kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}))
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
        response = self.client.post(reverse('api:project_issues_comments-list',
                                            kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}),
                                    comment_data)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
        # project2 granted for user2
        self.client.credentials(HTTP_AUTHORIZATION=self.user2_auth)
        response = self.client.get(reverse('api:project_issues_comments-list',
                                           kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        response = self.client.post(reverse('api:project_issues_comments-list',
                                            kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}),
                                    comment_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # no credentials
        self.client.credentials()
        response = self.client.get(reverse('api:project_issues_comments-list',
                                           kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}))
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
        response = self.client.post(reverse('api:project_issues_comments-list',
                                            kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}),
                                    comment_data)
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    def try_issue_comments_put_patch_delete(self, expected):
        comment_data = {
            'text': 'lalala',
        }
        url = 'api:project_issues_comments-detail'
        response = self.client.get(reverse(url, kwargs={'project': self.project2.name_short,
                                                        'issue': self.issue2.number,
                                                        'seqnum': self.comment2.seqnum}))
        self.assertIn(response.status_code, expected)
        response = self.client.patch(reverse(url, kwargs={'project': self.project2.name_short,
                                                          'issue': self.issue2.number,
                                                          'seqnum': self.comment2.seqnum}),
                                     data=comment_data)
        self.assertIn(response.status_code, expected)
        response = self.client.put(reverse(url, kwargs={'project': self.project2.name_short,
                                                        'issue': self.issue2.number,
                                                        'seqnum': self.comment2.seqnum}),
                                   data=comment_data)
        self.assertIn(response.status_code, expected)
        response = self.client.delete(reverse(url, kwargs={'project': self.project2.name_short,
                                                           'issue': self.issue2.number,
                                                           'seqnum': self.comment2.seqnum}))
        self.assertIn(response.status_code, expected)

    def test_project_issues_comments_detail_put_patch_delete_permissions(self):
        # TODO TESTCASE difference manager/not manager

        # user1 not in project1
        self.try_issue_comments_put_patch_delete([status.HTTP_403_FORBIDDEN])

        self.client.credentials(HTTP_AUTHORIZATION=self.user2_auth)
        # user2 in project2
        self.try_issue_comments_put_patch_delete([status.HTTP_200_OK, status.HTTP_204_NO_CONTENT])
        self.client.credentials()
        self.try_issue_comments_put_patch_delete([status.HTTP_401_UNAUTHORIZED])

    def test_project_issue_timelogs_get_post_permissions(self):
        log_data = {
                'time': '2h5m'
                }
        # project1 granted
        response = self.client.get(reverse('api:project_issues_timelogs-list',
                                           kwargs={'project': self.project.name_short, 'issue': self.issue.number}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        response = self.client.post(reverse('api:project_issues_timelogs-list',
                                            kwargs={'project': self.project.name_short, 'issue': self.issue.number}),
                                    log_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        # project2 denied for user1
        response = self.client.get(reverse('api:project_issues_timelogs-list',
                                           kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}))
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
        response = self.client.post(reverse('api:project_issues_timelogs-list',
                                            kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}),
                                    log_data)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
        # project2 granted for user2
        self.client.credentials(HTTP_AUTHORIZATION=self.user2_auth)
        response = self.client.get(reverse('api:project_issues_timelogs-list',
                                           kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        response = self.client.post(reverse('api:project_issues_timelogs-list',
                                            kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}),
                                    log_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # no credentials
        self.client.credentials()
        response = self.client.get(reverse('api:project_issues_timelogs-list',
                                           kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}))
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
        response = self.client.post(reverse('api:project_issues_timelogs-list',
                                            kwargs={'project': self.project2.name_short, 'issue': self.issue2.number}),
                                    log_data)
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    # helper function
    def try_issue_timelogs_put_patch_delete(self, expected):
        log_data = {
            'time': '2h5m'
        }
        url = 'api:project_issues_timelogs-detail'
        response = self.client.get(reverse(url, kwargs={'project': self.project2.name_short,
                                                        'issue': self.issue2.number,
                                                        'number': self.log2.number}))
        self.assertIn(response.status_code, expected)
        response = self.client.patch(reverse(url, kwargs={'project': self.project2.name_short,
                                                          'issue': self.issue2.number,
                                                          'number': self.log2.number}),
                                     data=log_data)
        self.assertIn(response.status_code, expected)
        response = self.client.put(reverse(url, kwargs={'project': self.project2.name_short,
                                                        'issue': self.issue2.number,
                                                        'number': self.log2.number}),
                                   data=log_data)
        self.assertIn(response.status_code, expected)
        response = self.client.delete(reverse(url, kwargs={'project': self.project2.name_short,
                                                           'issue': self.issue2.number,
                                                           'number': self.log2.number}))
        self.assertIn(response.status_code, expected)

    def test_project_issues_timelogs_detail_put_patch_delete_permissions(self):
        # TODO TESTCASE difference manager/not manager
        # user1 not in project1
        self.try_issue_timelogs_put_patch_delete([status.HTTP_403_FORBIDDEN])

        self.client.credentials(HTTP_AUTHORIZATION=self.user2_auth)
        # user2 in project2
        self.try_issue_timelogs_put_patch_delete([status.HTTP_200_OK, status.HTTP_204_NO_CONTENT])
        self.client.credentials()
        self.try_issue_timelogs_put_patch_delete([status.HTTP_401_UNAUTHORIZED])
Example #7
0
def compile(expression, project, user):
    global attrs_to_set
    global issue_to_change
    global glob_project
    global glob_user
    global issue_created
    global cleanup
    global cleanup_asignee
    global timelogs
    global issue_changed
    issue_created = False
    issue_changed = False
    cleanup_asignee = True
    attrs_to_set = []
    timelogs = []
    issue_to_change = ""
    glob_project = project
    glob_user = user

    # check that user has write access to project
    if not project.developer_allowed(user):
        raise Exception(
            u"No user permissions to modify issues in this project")

    # parse expression
    lexer = lex.lex(module=issue.lexer)
    # writes to parsetab.py (this is closed internally) and parser.out (which seems to stay open)
    # I don't know why debuglog (parser.out) is still open if we provide our own PlyLogger with it's
    # own file descriptor in that case yacc should not open any files.
    parser = yacc.yacc()
    parser.parse(expression, lexer=lexer)
    # TODO BUG cleanup yacc - close and parser.out, Y TFH is there no destructor doing this for us?
    # NOTE ^this doesn't seem to be possible - s. comment above

    # create issue if necessary
    if issue_created:
        issue_to_change = Issue(title=issue_to_change,
                                project=glob_project,
                                kanbancol=glob_project.kanbancol.first(),
                                creator=glob_user)
        issue_to_change.save()

    if issue_changed:
        changed_data = signals.fields_to_changed_data(
            issue_to_change, [tup[0] for tup in attrs_to_set])

    # handle timelogging separately
    for tdiff in timelogs:
        timelog = Timelog(user=glob_user, issue=issue_to_change, time=tdiff)
        timelog.save()

    for attr in attrs_to_set:
        # process all parsed attributes to change
        field = issue_to_change.__getattribute__(attr[0])

        if str(type(field)).startswith("<class 'django.db.models"):
            # cleanup asignee before setting first new asignee
            if attr[0] == "assignee" and cleanup_asignee:
                cleanup_asignee = False
                field.clear()

            # we have a related field -> call add
            field.add(attr[1])
        else:
            # no db model field, simply assign value
            issue_to_change.__setattr__(attr[0], attr[1])
            issue_to_change.save()

    if issue_created:
        signals.create.send(sender=Issue, instance=issue_to_change, user=user)

    if not issue_created and issue_changed:
        signals.modify.send(sender=Issue,
                            instance=issue_to_change,
                            user=user,
                            changed_data=changed_data)
Example #8
0
class ApiTest(APITestCase):
    @classmethod
    def setUpTestData(cls):
        # NOTE: if you modify these elements they need to be created in setUp(), instead of here
        cls.user1 = get_user_model().objects.create_user('user1', 'mail', 'c')
        cls.user2 = get_user_model().objects.create_user(
            'user2', 'othermail', 'c')

    def setUp(self):
        # NOTE: these elements get modified by some testcases, so they should NOT be created in setUpTestData()
        self.project = Project(creator=self.user1, name_short='asdf')
        self.project.save()
        self.project.developer.add(self.user1)
        self.project.developer.add(self.user2)
        self.project.manager.add(self.user1)
        self.issue = Issue(title='test', project=self.project)
        self.issue.save()
        self.comment = Comment(text='test',
                               creator=self.user1,
                               issue=self.issue)
        self.comment.save()
        self.log = Timelog(time=datetime.timedelta(hours=2),
                           user=self.user1,
                           issue=self.issue)
        self.log.save()
        self.client.credentials(HTTP_AUTHORIZATION='Basic ' +
                                base64.b64encode('user1:c'.encode()).decode())

    def test_get_issues(self):
        response = self.client.get(reverse('api:issues-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json().get('count'), 0)
        issue = Issue(title='asdf', project=self.project)
        issue.save()
        issue.assignee.add(self.user1)
        response = self.client.get(reverse('api:issues-list'))
        self.assertEqual(response.json().get('count'), 1)
        issue = Issue(title='asdf2', project=self.project)
        issue.save()
        issue.assignee.add(self.user2)
        response = self.client.get(reverse('api:issues-list'))
        self.assertEqual(response.json().get('count'), 1)

    def test_get_projects(self):
        response = self.client.get(reverse('api:project-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json().get('count'), 1)

    def test_get_timelogs(self):
        response = self.client.get(reverse('api:timelogs-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json().get('count'), 1)
        issue = Issue(title='asdf', project=self.project)
        issue.save()
        log = Timelog(issue=issue,
                      user=self.user1,
                      time=datetime.timedelta(hours=2))
        log.save()
        response = self.client.get(reverse('api:timelogs-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json().get('count'), 2)

    def test_get_users(self):
        response = self.client.get(reverse('api:customuser-list'))
        self.assertEqual(response.json().get('count'), 2)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_get_users_detail(self):
        response = self.client.get(
            reverse('api:customuser-detail',
                    kwargs={'username': self.user1.username}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIn(self.user1.username, response.json().get('username'))

    def test_post_project(self):
        project_data = {'name': 'yoflow', 'name_short': 'nanu'}
        response = self.client.post(reverse('api:project-list'), project_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        response = self.client.get(reverse('api:project-list'))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json().get('count'), 2)

    def test_get_project_detail(self):
        response = self.client.get(
            reverse('api:project-detail',
                    kwargs={'name_short': self.project.name_short}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_patch_project_detail(self):
        project_data = {
            'name': 'yoflow',
        }
        response = self.client.patch(reverse(
            'api:project-detail',
            kwargs={'name_short': self.project.name_short}),
                                     data=project_data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json().get('name'), 'yoflow')
        self.assertEqual(response.json().get('name_short'), 'asdf')

        # assert - at least one project manager
        project_data.update({'manager': [], 'developer': []})
        response = self.client.patch(reverse(
            'api:project-detail',
            kwargs={'name_short': self.project.name_short}),
                                     data=project_data,
                                     format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_put_project_detail(self):
        project_data = {
            'manager': ['user1'],
            'name': 'yoflow',
        }
        response = self.client.put(reverse(
            'api:project-detail',
            kwargs={'name_short': self.project.name_short}),
                                   data=project_data,
                                   format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json().get('name'), 'yoflow')

    def test_delete_project_detail(self):
        response = self.client.delete(
            reverse('api:project-detail',
                    kwargs={'name_short': self.project.name_short}))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_get_project_issues(self):
        response = self.client.get(
            reverse('api:project_issues-list',
                    kwargs={'project': self.project.name_short}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_post_project_issues(self):
        issue_data = {
            'title': 'this is a issue',
        }
        response = self.client.post(reverse(
            'api:project_issues-list',
            kwargs={'project': self.project.name_short}),
                                    data=issue_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

    def test_get_project_timelogs(self):
        response = self.client.get(
            reverse('api:project_timelogs-list',
                    kwargs={'project': self.project.name_short}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_get_project_issue_detail(self):
        response = self.client.get(
            reverse('api:project_issues-detail',
                    kwargs={
                        'project': self.project.name_short,
                        'number': self.issue.number
                    }))
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        response = self.client.get(
            reverse('api:project_issues-list',
                    kwargs={'project': self.project.name_short}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_get_project_timelogs(self):
        response = self.client.get(
            reverse('api:project_timelogs-list',
                    kwargs={'project': self.project.name_short}))
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_get_project_issue_detail(self):
        response = self.client.get(
            reverse('api:project_issues-detail',
                    kwargs={
                        'project': self.project.name_short,
                        'number': self.issue.number
                    }))
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_put_project_issue_detail(self):
        issue_data = {
            'title': 'this is a issue',
        }
        response = self.client.put(
            reverse('api:project_issues-detail',
                    kwargs={
                        'project': self.project.name_short,
                        'number': self.issue.number
                    }), issue_data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json().get('title'), 'this is a issue')

    def test_patch_project_issue_detail(self):
        issue_data = {
            'title': 'this is a issue',
        }
        response = self.client.patch(
            reverse('api:project_issues-detail',
                    kwargs={
                        'project': self.project.name_short,
                        'number': self.issue.number
                    }), issue_data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json().get('title'), 'this is a issue')

    def test_delete_project_issue_detail(self):
        response = self.client.delete(
            reverse('api:project_issues-detail',
                    kwargs={
                        'project': self.project.name_short,
                        'number': self.issue.number
                    }))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_get_project_issue_comments(self):
        response = self.client.get(
            reverse('api:project_issues_comments-list',
                    kwargs={
                        'project': self.project.name_short,
                        'issue': self.issue.number
                    }))
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_post_project_issue_comments(self):
        comment_data = {'text': 'good evening'}
        response = self.client.post(
            reverse('api:project_issues_comments-list',
                    kwargs={
                        'project': self.project.name_short,
                        'issue': self.issue.number
                    }), comment_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

    def test_get_project_issue_timelogs(self):
        response = self.client.get(
            reverse('api:project_issues_timelogs-list',
                    kwargs={
                        'project': self.project.name_short,
                        'issue': self.issue.number
                    }))
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_post_project_issue_timelogs(self):
        timelog_data = {'time': '2h'}
        response = self.client.post(
            reverse('api:project_issues_timelogs-list',
                    kwargs={
                        'project': self.project.name_short,
                        'issue': self.issue.number
                    }), timelog_data)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

    def test_get_project_issue_comments_detail(self):
        response = self.client.get(
            reverse('api:project_issues_comments-detail',
                    kwargs={
                        'project': self.project.name_short,
                        'issue': self.issue.number,
                        'seqnum': self.comment.seqnum
                    }))
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_put_project_issue_comments_detail(self):
        comment_data = {'text': 'new content'}
        response = self.client.put(
            reverse('api:project_issues_comments-detail',
                    kwargs={
                        'project': self.project.name_short,
                        'issue': self.issue.number,
                        'seqnum': self.comment.seqnum
                    }), comment_data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json().get('text'), 'new content')

    def test_patch_project_issue_comments_detail(self):
        comment_data = {'text': 'new content'}
        response = self.client.patch(
            reverse('api:project_issues_comments-detail',
                    kwargs={
                        'project': self.project.name_short,
                        'issue': self.issue.number,
                        'seqnum': self.comment.seqnum
                    }), comment_data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json().get('text'), 'new content')

    def test_delete_project_issue_comments_detail(self):
        response = self.client.delete(
            reverse('api:project_issues_comments-detail',
                    kwargs={
                        'project': self.project.name_short,
                        'issue': self.issue.number,
                        'seqnum': self.comment.seqnum
                    }))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_get_project_issue_timelogs_detail(self):
        response = self.client.get(
            reverse('api:project_issues_timelogs-detail',
                    kwargs={
                        'project': self.project.name_short,
                        'issue': self.issue.number,
                        'number': self.log.number
                    }))
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_put_project_issue_timelogs_detail(self):
        log_data = {'time': '4h10m'}
        response = self.client.put(
            reverse('api:project_issues_timelogs-detail',
                    kwargs={
                        'project': self.project.name_short,
                        'issue': self.issue.number,
                        'number': self.log.number
                    }), log_data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json().get('time'), '4h 10m')

    def test_patch_project_issue_timelogs_detail(self):
        log_data = {'time': '4h10m'}
        response = self.client.patch(
            reverse('api:project_issues_timelogs-detail',
                    kwargs={
                        'project': self.project.name_short,
                        'issue': self.issue.number,
                        'number': self.log.number
                    }), log_data)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json().get('time'), '4h 10m')

    def test_delete_project_issue_timelogs_detail(self):
        response = self.client.delete(
            reverse('api:project_issues_timelogs-detail',
                    kwargs={
                        'project': self.project.name_short,
                        'issue': self.issue.number,
                        'number': self.log.number
                    }))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)