From 289d980dadd36ad8bd97417e66d19f1329e7a1e7 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: May 09 2017 02:13:15 +0000 Subject: [PATCH 1/6] Some more checks in the API regarding who is allowed to do what. Rename _check_issue_access_repo_commiter to _check_private_issue_access since this is what the method does, it checks only for private issue if the user has enough rights to access it. Create a _check_ticket_access which is used in some of the endpoints to ensure the user either has commit access if the ticket is private or has ticket access if the ticket is public. Signed-off-by: Pierre-Yves Chibon --- diff --git a/pagure/api/issue.py b/pagure/api/issue.py index 58f934e..865856b 100644 --- a/pagure/api/issue.py +++ b/pagure/api/issue.py @@ -18,7 +18,8 @@ import pagure.exceptions import pagure.lib from pagure import ( - APP, SESSION, is_repo_committer, api_authenticated, urlpattern + APP, SESSION, is_repo_committer, api_authenticated, + urlpattern, is_repo_user ) from pagure.api import ( API, api_method, api_login_required, api_login_optional, APIERROR @@ -87,7 +88,7 @@ def _get_issue(repo, issueid, issueuid=None): return issue -def _check_issue_access_repo_commiter(issue): +def _check_private_issue_access(issue): """Check if user can access issue. Must be repo commiter or author to see private issues. :param issue: issue object @@ -105,6 +106,20 @@ def _check_issue_access_repo_commiter(issue): 403, error_code=APIERROR.EISSUENOTALLOWED) +def _check_ticket_access(issue): + """Check if user can access issue. Must be repo commiter + or author to see private issues. + :param issue: issue object + :raises pagure.exceptions.APIError: when access denied + """ + # Private tickets require commit access + _check_private_issue_access(issue) + # Public tickets require ticket access + if not is_repo_user(issue.project): + raise pagure.exceptions.APIError( + 403, error_code=APIERROR.EISSUENOTALLOWED) + + @API.route('//new_issue', methods=['POST']) @API.route('///new_issue', methods=['POST']) @API.route('/fork///new_issue', methods=['POST']) @@ -526,7 +541,7 @@ def api_view_issue(repo, issueid, username=None, namespace=None): issue_uid = issueid issue = _get_issue(repo, issue_id, issueuid=issue_uid) - _check_issue_access_repo_commiter(issue) + _check_private_issue_access(issue) jsonout = flask.jsonify( issue.to_json(public=True, with_comments=comments)) @@ -593,7 +608,7 @@ def api_view_issue_comment( issue_uid = issueid issue = _get_issue(repo, issue_id, issueuid=issue_uid) - _check_issue_access_repo_commiter(issue) + _check_private_issue_access(issue) comment = pagure.lib.get_issue_comment(SESSION, issue.uid, commentid) if not comment: @@ -665,7 +680,7 @@ def api_change_status_issue(repo, issueid, username=None, namespace=None): _check_token(repo) issue = _get_issue(repo, issueid) - _check_issue_access_repo_commiter(issue) + _check_ticket_access(issue) status = pagure.lib.get_issue_statuses(SESSION) form = pagure.forms.StatusForm( @@ -673,6 +688,11 @@ def api_change_status_issue(repo, issueid, username=None, namespace=None): close_status=repo.close_status, csrf_enabled=False) + if not pagure.is_repo_user(repo) \ + and flask.g.fas_user.username != issue.user.user: + raise pagure.exceptions.APIError( + 403, error_code=APIERROR.EISSUENOTALLOWED) + close_status = None if form.close_status.raw_data: close_status = form.close_status.data @@ -778,7 +798,7 @@ def api_change_milestone_issue(repo, issueid, username=None, namespace=None): _check_token(repo) issue = _get_issue(repo, issueid) - _check_issue_access_repo_commiter(issue) + _check_ticket_access(issue) form = pagure.forms.MilestoneForm( milestones=repo.milestones.keys(), @@ -877,7 +897,7 @@ def api_comment_issue(repo, issueid, username=None, namespace=None): _check_token(repo, project_token=False) issue = _get_issue(repo, issueid) - _check_issue_access_repo_commiter(issue) + _check_private_issue_access(issue) form = pagure.forms.CommentForm(csrf_enabled=False) if form.validate_on_submit(): @@ -957,7 +977,7 @@ def api_assign_issue(repo, issueid, username=None, namespace=None): _check_token(repo) issue = _get_issue(repo, issueid) - _check_issue_access_repo_commiter(issue) + _check_ticket_access(issue) form = pagure.forms.AssignIssueForm(csrf_enabled=False) if form.validate_on_submit(): @@ -1055,7 +1075,7 @@ def api_subscribe_issue(repo, issueid, username=None, namespace=None): _check_token(repo) issue = _get_issue(repo, issueid) - _check_issue_access_repo_commiter(issue) + _check_private_issue_access(issue) form = pagure.forms.SubscribtionForm(csrf_enabled=False) if form.validate_on_submit(): @@ -1138,7 +1158,7 @@ def api_update_custom_field( _check_token(repo) issue = _get_issue(repo, issueid) - _check_issue_access_repo_commiter(issue) + _check_ticket_access(issue) fields = {k.name: k for k in repo.issue_keys} if field not in fields: From 929a2a220cce6b9f5ab7777e4288188473497e20 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: May 09 2017 02:13:15 +0000 Subject: [PATCH 2/6] Move the tests for the API to change the status of issues to their own file Signed-off-by: Pierre-Yves Chibon --- diff --git a/tests/test_pagure_flask_api_issue.py b/tests/test_pagure_flask_api_issue.py index adbb43b..9269aa0 100644 --- a/tests/test_pagure_flask_api_issue.py +++ b/tests/test_pagure_flask_api_issue.py @@ -1845,180 +1845,6 @@ class PagureFlaskApiIssuetests(tests.Modeltests): } ) - def test_api_change_status_issue(self): - """ Test the api_change_status_issue method of the flask api. """ - tests.create_projects(self.session) - tests.create_projects_git(os.path.join(self.path, 'tickets')) - tests.create_tokens(self.session) - tests.create_tokens_acl(self.session) - - headers = {'Authorization': 'token aaabbbcccddd'} - - # Invalid project - output = self.app.post('/api/0/foo/issue/1/status', headers=headers) - self.assertEqual(output.status_code, 404) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Project not found", - "error_code": "ENOPROJECT", - } - ) - - # Valid token, wrong project - output = self.app.post('/api/0/test2/issue/1/status', headers=headers) - self.assertEqual(output.status_code, 401) - data = json.loads(output.data) - self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name, - data['error_code']) - self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error']) - - # No issue - output = self.app.post('/api/0/test/issue/1/status', headers=headers) - self.assertEqual(output.status_code, 404) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Issue not found", - "error_code": "ENOISSUE", - } - ) - - # Create normal issue - repo = pagure.get_authorized_project(self.session, 'test') - msg = pagure.lib.new_issue( - session=self.session, - repo=repo, - title='Test issue #1', - content='We should work on this', - user='pingou', - ticketfolder=None, - private=False, - ) - self.session.commit() - self.assertEqual(msg.title, 'Test issue #1') - - # Create another project - item = pagure.lib.model.Project( - user_id=2, # pingou - name='foo', - description='test project #3', - hook_token='aaabbbdddeee', - ) - self.session.add(item) - self.session.commit() - - # Create a token for pingou for this project - item = pagure.lib.model.Token( - id='pingou_foo', - user_id=1, - project_id=4, - expiration=datetime.datetime.utcnow() + datetime.timedelta( - days=30) - ) - self.session.add(item) - self.session.commit() - - # Give `change_status_issue` to this token - item = pagure.lib.model.TokenAcl( - token_id='pingou_foo', - acl_id=6, - ) - self.session.add(item) - self.session.commit() - - repo = pagure.get_authorized_project(self.session, 'foo') - # Create private issue - msg = pagure.lib.new_issue( - session=self.session, - repo=repo, - title='Test issue', - content='We should work on this', - user='foo', - ticketfolder=None, - private=True, - ) - self.session.commit() - self.assertEqual(msg.title, 'Test issue') - - # Check status before - repo = pagure.get_authorized_project(self.session, 'test') - issue = pagure.lib.search_issues(self.session, repo, issueid=1) - self.assertEqual(issue.status, 'Open') - - data = { - 'title': 'test issue', - } - - # Incomplete request - output = self.app.post( - '/api/0/test/issue/1/status', data=data, headers=headers) - self.assertEqual(output.status_code, 400) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Invalid or incomplete input submited", - "error_code": "EINVALIDREQ", - "errors": {"status": ["Not a valid choice"]} - } - ) - - # No change - repo = pagure.get_authorized_project(self.session, 'test') - issue = pagure.lib.search_issues(self.session, repo, issueid=1) - self.assertEqual(issue.status, 'Open') - - data = { - 'status': 'Open', - } - - # Valid request but no change - output = self.app.post( - '/api/0/test/issue/1/status', data=data, headers=headers) - self.assertEqual(output.status_code, 200) - data = json.loads(output.data) - self.assertDictEqual( - data, - {'message': 'No changes'} - ) - - # No change - repo = pagure.get_authorized_project(self.session, 'test') - issue = pagure.lib.search_issues(self.session, repo, issueid=1) - self.assertEqual(issue.status, 'Open') - - data = { - 'status': 'Fixed', - } - - # Valid request - output = self.app.post( - '/api/0/test/issue/1/status', data=data, headers=headers) - self.assertEqual(output.status_code, 200) - data = json.loads(output.data) - - self.assertDictEqual( - data, - {'message':[ - 'Issue status updated to: Closed (was: Open)', - 'Issue close_status updated to: Fixed' - ]} - ) - - headers = {'Authorization': 'token pingou_foo'} - - # Un-authorized issue - output = self.app.post( - '/api/0/foo/issue/1/status', data=data, headers=headers) - self.assertEqual(output.status_code, 401) - data = json.loads(output.data) - self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name, - data['error_code']) - self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error']) - def test_api_change_milestone_issue(self): """ Test the api_change_milestone_issue method of the flask api. """ tests.create_projects(self.session) @@ -2219,7 +2045,6 @@ class PagureFlaskApiIssuetests(tests.Modeltests): data['error_code']) self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error']) - @patch('pagure.lib.git.update_git') @patch('pagure.lib.notify.send_email') def test_api_comment_issue(self, p_send_email, p_ugt): diff --git a/tests/test_pagure_flask_api_issue_change_status.py b/tests/test_pagure_flask_api_issue_change_status.py new file mode 100644 index 0000000..536d85b --- /dev/null +++ b/tests/test_pagure_flask_api_issue_change_status.py @@ -0,0 +1,227 @@ +# -*- coding: utf-8 -*- + +""" + (c) 2015-2017 - Copyright Red Hat Inc + + Authors: + Pierre-Yves Chibon + +""" + +__requires__ = ['SQLAlchemy >= 0.8'] +import pkg_resources + +import copy +import datetime +import unittest +import shutil +import sys +import time +import os + +import json +from mock import patch, MagicMock + +sys.path.insert(0, os.path.join(os.path.dirname( + os.path.abspath(__file__)), '..')) + +import pagure +import pagure.lib +import tests + + +class PagureFlaskApiIssueChangeStatustests(tests.Modeltests): + """ Tests for the flask API of pagure for changing the status of an + issue + """ + + @patch('pagure.lib.notify.send_email', MagicMock(return_value=True)) + def setUp(self): + """ Set up the environnment, ran before every tests. """ + super(PagureFlaskApiIssueChangeStatustests, self).setUp() + + pagure.APP.config['TESTING'] = True + pagure.SESSION = self.session + pagure.api.SESSION = self.session + pagure.api.issue.SESSION = self.session + pagure.lib.SESSION = self.session + + pagure.APP.config['TICKETS_FOLDER'] = None + + self.app = pagure.APP.test_client() + + tests.create_projects(self.session) + tests.create_projects_git(os.path.join(self.path, 'tickets')) + tests.create_tokens(self.session) + tests.create_tokens_acl(self.session) + + # Create normal issue + repo = pagure.get_authorized_project(self.session, 'test') + msg = pagure.lib.new_issue( + session=self.session, + repo=repo, + title='Test issue #1', + content='We should work on this', + user='pingou', + ticketfolder=None, + private=False, + ) + self.session.commit() + self.assertEqual(msg.title, 'Test issue #1') + + # Create private issue + msg = pagure.lib.new_issue( + session=self.session, + repo=repo, + title='Test issue #2', + content='We should work on this', + user='foo', + ticketfolder=None, + private=True, + ) + self.session.commit() + self.assertEqual(msg.title, 'Test issue #2') + + def test_api_change_status_issue_invalid_project(self): + """ Test the api_change_status_issue method of the flask api. """ + + headers = {'Authorization': 'token aaabbbcccddd'} + + # Invalid project + output = self.app.post( + '/api/0/foobar/issue/1/status', headers=headers) + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Project not found", + "error_code": "ENOPROJECT", + } + ) + + def test_api_change_status_issue_token_not_for_project(self): + """ Test the api_change_status_issue method of the flask api. """ + + headers = {'Authorization': 'token aaabbbcccddd'} + + # Valid token, wrong project + output = self.app.post('/api/0/test2/issue/1/status', headers=headers) + self.assertEqual(output.status_code, 401) + data = json.loads(output.data) + self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name, + data['error_code']) + self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error']) + + def test_api_change_status_issue_invalid_issue(self): + """ Test the api_change_status_issue method of the flask api. """ + + headers = {'Authorization': 'token aaabbbcccddd'} + + # No issue + output = self.app.post('/api/0/test/issue/42/status', headers=headers) + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Issue not found", + "error_code": "ENOISSUE", + } + ) + + def test_api_change_status_issue_incomplete(self): + """ Test the api_change_status_issue method of the flask api. """ + + headers = {'Authorization': 'token aaabbbcccddd'} + + # Check status before + repo = pagure.get_authorized_project(self.session, 'test') + issue = pagure.lib.search_issues(self.session, repo, issueid=1) + self.assertEqual(issue.status, 'Open') + + data = { + 'title': 'test issue', + } + + # Incomplete request + output = self.app.post( + '/api/0/test/issue/1/status', data=data, headers=headers) + self.assertEqual(output.status_code, 400) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Invalid or incomplete input submited", + "error_code": "EINVALIDREQ", + "errors": {"status": ["Not a valid choice"]} + } + ) + + # No change + repo = pagure.get_authorized_project(self.session, 'test') + issue = pagure.lib.search_issues(self.session, repo, issueid=1) + self.assertEqual(issue.status, 'Open') + + def test_api_change_status_issue_no_change(self): + """ Test the api_change_status_issue method of the flask api. """ + + headers = {'Authorization': 'token aaabbbcccddd'} + + data = { + 'status': 'Open', + } + + # Valid request but no change + output = self.app.post( + '/api/0/test/issue/1/status', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertDictEqual( + data, + {'message': 'No changes'} + ) + + # No change + repo = pagure.get_authorized_project(self.session, 'test') + issue = pagure.lib.search_issues(self.session, repo, issueid=1) + self.assertEqual(issue.status, 'Open') + + @patch('pagure.lib.notify.send_email', MagicMock(return_value=True)) + def test_api_change_status_issue(self): + """ Test the api_change_status_issue method of the flask api. """ + + headers = {'Authorization': 'token aaabbbcccddd'} + + data = { + 'status': 'Fixed', + } + + # Valid request + output = self.app.post( + '/api/0/test/issue/1/status', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + + self.assertDictEqual( + data, + {'message':[ + 'Issue status updated to: Closed (was: Open)', + 'Issue close_status updated to: Fixed' + ]} + ) + + headers = {'Authorization': 'token pingou_foo'} + + # Un-authorized issue + output = self.app.post( + '/api/0/foo/issue/1/status', data=data, headers=headers) + self.assertEqual(output.status_code, 401) + data = json.loads(output.data) + self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name, + data['error_code']) + self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error']) + + +if __name__ == '__main__': + unittest.main(verbosity=2) From 06b85067819dbb2fed048add0964e8a2d9e4641c Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: May 09 2017 02:13:15 +0000 Subject: [PATCH 3/6] Fix the logic around checking the project restriction of API tokens Signed-off-by: Pierre-Yves Chibon --- diff --git a/pagure/api/issue.py b/pagure/api/issue.py index 865856b..284de20 100644 --- a/pagure/api/issue.py +++ b/pagure/api/issue.py @@ -63,10 +63,11 @@ def _check_token(repo, project_token=True): :raises pagure.exceptions.APIError: when token is not valid for repo """ if api_authenticated(): - if ( - (project_token or flask.g.token.project) and - repo != flask.g.token.project - ): + # if there is a project associated with the token, check it + # if there is no project associated, check if it is required + if (flask.g.token.project is not None + and repo != flask.g.token.project) \ + or (flask.g.token.project is None and project_token): raise pagure.exceptions.APIError( 401, error_code=APIERROR.EINVALIDTOK) From 91e0448be04c047cff39e69f7d0fd3967c3ef2f1 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: May 09 2017 02:13:15 +0000 Subject: [PATCH 4/6] Move the unit-tests to check adding a comment to an issue to their own file Signed-off-by: Pierre-Yves Chibon --- diff --git a/tests/test_pagure_flask_api_issue.py b/tests/test_pagure_flask_api_issue.py index 9269aa0..bea5fbc 100644 --- a/tests/test_pagure_flask_api_issue.py +++ b/tests/test_pagure_flask_api_issue.py @@ -2047,50 +2047,17 @@ class PagureFlaskApiIssuetests(tests.Modeltests): @patch('pagure.lib.git.update_git') @patch('pagure.lib.notify.send_email') - def test_api_comment_issue(self, p_send_email, p_ugt): - """ Test the api_comment_issue method of the flask api. """ + def test_api_view_issue_comment(self, p_send_email, p_ugt): + """ Test the api_view_issue_comment endpoint. """ p_send_email.return_value = True p_ugt.return_value = True tests.create_projects(self.session) + tests.create_projects_git(os.path.join(self.path, 'tickets')) tests.create_tokens(self.session) tests.create_tokens_acl(self.session) - headers = {'Authorization': 'token aaabbbcccddd'} - - # Invalid project - output = self.app.post('/api/0/foo/issue/1/comment', headers=headers) - self.assertEqual(output.status_code, 404) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Project not found", - "error_code": "ENOPROJECT", - } - ) - - # Valid token, wrong project - output = self.app.post('/api/0/test2/issue/1/comment', headers=headers) - self.assertEqual(output.status_code, 401) - data = json.loads(output.data) - self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name, - data['error_code']) - self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error']) - - # No input - output = self.app.post('/api/0/test/issue/1/comment', headers=headers) - self.assertEqual(output.status_code, 404) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Issue not found", - "error_code": "ENOISSUE", - } - ) - - # Create normal issue + # Create normal issue in test repo = pagure.get_authorized_project(self.session, 'test') msg = pagure.lib.new_issue( session=self.session, @@ -2105,240 +2072,9 @@ class PagureFlaskApiIssuetests(tests.Modeltests): self.session.commit() self.assertEqual(msg.title, 'Test issue #1') - # Check comments before - repo = pagure.get_authorized_project(self.session, 'test') - issue = pagure.lib.search_issues(self.session, repo, issueid=1) - self.assertEqual(len(issue.comments), 0) - - data = { - 'title': 'test issue', - } - - # Incomplete request - output = self.app.post( - '/api/0/test/issue/1/comment', data=data, headers=headers) - self.assertEqual(output.status_code, 400) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Invalid or incomplete input submited", - "error_code": "EINVALIDREQ", - "errors": {"comment": ["This field is required."]} - } - ) - - # No change - repo = pagure.get_authorized_project(self.session, 'test') - issue = pagure.lib.search_issues(self.session, repo, issueid=1) - self.assertEqual(issue.status, 'Open') - - data = { - 'comment': 'This is a very interesting question', - } - - # Valid request - output = self.app.post( - '/api/0/test/issue/1/comment', data=data, headers=headers) - self.assertEqual(output.status_code, 200) - data = json.loads(output.data) - self.assertDictEqual( - data, - {'message': 'Comment added'} - ) - - # One comment added - repo = pagure.get_authorized_project(self.session, 'test') - issue = pagure.lib.search_issues(self.session, repo, issueid=1) - self.assertEqual(len(issue.comments), 1) - - # Create another project - item = pagure.lib.model.Project( - user_id=2, # foo - name='foo', - description='test project #3', - hook_token='aaabbbdddeee', - ) - self.session.add(item) - self.session.commit() - - # Create a token for pingou for this project - item = pagure.lib.model.Token( - id='pingou_foo', - user_id=1, - project_id=4, - expiration=datetime.datetime.utcnow() + datetime.timedelta( - days=30) - ) - self.session.add(item) - self.session.commit() - - # Give `issue_change_status` to this token when `issue_comment` - # is required - item = pagure.lib.model.TokenAcl( - token_id='pingou_foo', - acl_id=2, - ) - self.session.add(item) - self.session.commit() - - repo = pagure.get_authorized_project(self.session, 'foo') - # Create private issue - msg = pagure.lib.new_issue( - session=self.session, - repo=repo, - title='Test issue', - content='We should work on this', - user='foo', - ticketfolder=None, - private=True, - issue_uid='aaabbbccc#2', - ) - self.session.commit() - self.assertEqual(msg.title, 'Test issue') - - # Check before - repo = pagure.get_authorized_project(self.session, 'foo') - issue = pagure.lib.search_issues(self.session, repo, issueid=1) - self.assertEqual(len(issue.comments), 0) - - data = { - 'comment': 'This is a very interesting question', - } - headers = {'Authorization': 'token pingou_foo'} - - # Valid request but un-authorized - output = self.app.post( - '/api/0/foo/issue/1/comment', data=data, headers=headers) - self.assertEqual(output.status_code, 401) - data = json.loads(output.data) - self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name, - data['error_code']) - self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error']) - - # No comment added - repo = pagure.get_authorized_project(self.session, 'foo') - issue = pagure.lib.search_issues(self.session, repo, issueid=1) - self.assertEqual(len(issue.comments), 0) - - # Create token for user foo - item = pagure.lib.model.Token( - id='foo_token2', - user_id=2, - project_id=4, - expiration=datetime.datetime.utcnow() + datetime.timedelta(days=30) - ) - self.session.add(item) - self.session.commit() - tests.create_tokens_acl(self.session, token_id='foo_token2') - - data = { - 'comment': 'This is a very interesting question', - } - headers = {'Authorization': 'token foo_token2'} - - # Valid request and authorized - output = self.app.post( - '/api/0/foo/issue/1/comment', data=data, headers=headers) - self.assertEqual(output.status_code, 200) - data = json.loads(output.data) - self.assertDictEqual( - data, - {'message': 'Comment added'} - ) - - @patch('pagure.lib.git.update_git') - @patch('pagure.lib.notify.send_email') - def test_api_comment_issue_user_token(self, p_send_email, p_ugt): - """ Test the api_comment_issue method of the flask api. """ - p_send_email.return_value = True - p_ugt.return_value = True - - tests.create_projects(self.session) - tests.create_tokens(self.session, project_id=None) - tests.create_tokens_acl(self.session) headers = {'Authorization': 'token aaabbbcccddd'} - # Invalid project - output = self.app.post('/api/0/foo/issue/1/comment', headers=headers) - self.assertEqual(output.status_code, 404) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Project not found", - "error_code": "ENOPROJECT", - } - ) - - # Valid token, no issue on the project - output = self.app.post('/api/0/test2/issue/1/comment', headers=headers) - self.assertEqual(output.status_code, 404) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Issue not found", - "error_code": "ENOISSUE", - } - ) - - # Valid token, still no issue on this other project - output = self.app.post('/api/0/test/issue/1/comment', headers=headers) - self.assertEqual(output.status_code, 404) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Issue not found", - "error_code": "ENOISSUE", - } - ) - - # Create normal issue - repo = pagure.get_authorized_project(self.session, 'test') - msg = pagure.lib.new_issue( - session=self.session, - repo=repo, - title='Test issue #1', - content='We should work on this', - user='pingou', - ticketfolder=None, - private=False, - issue_uid='aaabbbccc#1', - ) - self.session.commit() - self.assertEqual(msg.title, 'Test issue #1') - - # Check comments before - repo = pagure.get_authorized_project(self.session, 'test') - issue = pagure.lib.search_issues(self.session, repo, issueid=1) - self.assertEqual(len(issue.comments), 0) - - data = { - 'title': 'test issue', - } - - # Incomplete request - output = self.app.post( - '/api/0/test/issue/1/comment', data=data, headers=headers) - self.assertEqual(output.status_code, 400) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Invalid or incomplete input submited", - "error_code": "EINVALIDREQ", - "errors": {"comment": ["This field is required."]} - } - ) - - # No change - repo = pagure.get_authorized_project(self.session, 'test') - issue = pagure.lib.search_issues(self.session, repo, issueid=1) - self.assertEqual(issue.status, 'Open') - data = { 'comment': 'This is a very interesting question', } @@ -2358,110 +2094,6 @@ class PagureFlaskApiIssuetests(tests.Modeltests): issue = pagure.lib.search_issues(self.session, repo, issueid=1) self.assertEqual(len(issue.comments), 1) - # Create another project - item = pagure.lib.model.Project( - user_id=2, # foo - name='foo', - description='test project #3', - hook_token='aaabbbdddeee', - ) - self.session.add(item) - self.session.commit() - - # Create a token for pingou for this project - item = pagure.lib.model.Token( - id='pingou_foo', - user_id=1, - project_id=4, - expiration=datetime.datetime.utcnow() + datetime.timedelta( - days=30) - ) - self.session.add(item) - self.session.commit() - - # Give `issue_change_status` to this token when `issue_comment` - # is required - item = pagure.lib.model.TokenAcl( - token_id='pingou_foo', - acl_id=2, - ) - self.session.add(item) - self.session.commit() - - repo = pagure.get_authorized_project(self.session, 'foo') - # Create private issue - msg = pagure.lib.new_issue( - session=self.session, - repo=repo, - title='Test issue', - content='We should work on this', - user='foo', - ticketfolder=None, - private=True, - issue_uid='aaabbbccc#2', - ) - self.session.commit() - self.assertEqual(msg.title, 'Test issue') - - # Check before - repo = pagure.get_authorized_project(self.session, 'foo') - issue = pagure.lib.search_issues(self.session, repo, issueid=1) - self.assertEqual(len(issue.comments), 0) - - data = { - 'comment': 'This is a very interesting question', - } - headers = {'Authorization': 'token pingou_foo'} - - # Valid request but un-authorized - output = self.app.post( - '/api/0/foo/issue/1/comment', data=data, headers=headers) - self.assertEqual(output.status_code, 401) - data = json.loads(output.data) - self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name, - data['error_code']) - self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error']) - - # No comment added - repo = pagure.get_authorized_project(self.session, 'foo') - issue = pagure.lib.search_issues(self.session, repo, issueid=1) - self.assertEqual(len(issue.comments), 0) - - # Create token for user foo - item = pagure.lib.model.Token( - id='foo_token2', - user_id=2, - project_id=4, - expiration=datetime.datetime.utcnow() + datetime.timedelta(days=30) - ) - self.session.add(item) - self.session.commit() - tests.create_tokens_acl(self.session, token_id='foo_token2') - - data = { - 'comment': 'This is a very interesting question', - } - headers = {'Authorization': 'token foo_token2'} - - # Valid request and authorized - output = self.app.post( - '/api/0/foo/issue/1/comment', data=data, headers=headers) - self.assertEqual(output.status_code, 200) - data = json.loads(output.data) - self.assertDictEqual( - data, - {'message': 'Comment added'} - ) - - @patch('pagure.lib.git.update_git') - @patch('pagure.lib.notify.send_email') - def test_api_view_issue_comment(self, p_send_email, p_ugt): - """ Test the api_view_issue_comment endpoint. """ - p_send_email.return_value = True - p_ugt.return_value = True - - self.test_api_comment_issue() - # View a comment that does not exist output = self.app.get('/api/0/foo/issue/100/comment/2') self.assertEqual(output.status_code, 404) @@ -2522,28 +2154,76 @@ class PagureFlaskApiIssuetests(tests.Modeltests): } ) - # Private issue - output = self.app.get('/api/0/foo/issue/1/comment/2') - self.assertEqual(output.status_code, 403) + @patch('pagure.lib.git.update_git') + @patch('pagure.lib.notify.send_email') + def test_api_view_issue_comment_private(self, p_send_email, p_ugt): + """ Test the api_view_issue_comment endpoint. """ + p_send_email.return_value = True + p_ugt.return_value = True - # Private issue - Auth - wrong token - headers = {'Authorization': 'token pingou_foo'} - output = self.app.get('/api/0/foo/issue/1/comment/2', headers=headers) + tests.create_projects(self.session) + tests.create_projects_git(os.path.join(self.path, 'tickets')) + tests.create_tokens(self.session) + tests.create_tokens_acl(self.session) + + # Create normal issue in test + repo = pagure.get_authorized_project(self.session, 'test') + msg = pagure.lib.new_issue( + session=self.session, + repo=repo, + title='Test issue #1', + content='We should work on this', + user='foo', + ticketfolder=None, + private=True, + issue_uid='aaabbbccc#1', + ) + self.session.commit() + self.assertEqual(msg.title, 'Test issue #1') + + # Create a token for another user + item = pagure.lib.model.Token( + id='foo_token_2', + user_id=2, + project_id=1, + expiration=datetime.datetime.utcnow() + + datetime.timedelta(days=30) + ) + self.session.add(item) + self.session.commit() + tests.create_tokens_acl(self.session, token_id='foo_token_2') + + # Add a comment to that issue + data = { + 'comment': 'This is a very interesting question', + } + headers = {'Authorization': 'token foo_token_2'} + output = self.app.post( + '/api/0/test/issue/1/comment', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertDictEqual( + data, + {'message': 'Comment added'} + ) + + # Private issue - no auth + output = self.app.get('/api/0/test/issue/1/comment/2') self.assertEqual(output.status_code, 403) # Private issue - Auth - Invalid token - headers = {'Authorization': 'token aaabbbcccddd'} - output = self.app.get('/api/0/foo/issue/1/comment/2', headers=headers) + headers = {'Authorization': 'token aaabbbcccdddee'} + output = self.app.get('/api/0/test/issue/1/comment/2', headers=headers) self.assertEqual(output.status_code, 401) # Private issue - Auth - valid token - unknown comment - headers = {'Authorization': 'token foo_token2'} - output = self.app.get('/api/0/foo/issue/1/comment/3', headers=headers) + headers = {'Authorization': 'token foo_token_2'} + output = self.app.get('/api/0/test/issue/1/comment/3', headers=headers) self.assertEqual(output.status_code, 404) # Private issue - Auth - valid token - known comment - headers = {'Authorization': 'token foo_token2'} - output = self.app.get('/api/0/foo/issue/1/comment/2', headers=headers) + headers = {'Authorization': 'token foo_token_2'} + output = self.app.get('/api/0/test/issue/1/comment/1', headers=headers) self.assertEqual(output.status_code, 200) data = json.loads(output.data) data['date_created'] = '1435821770' @@ -2559,7 +2239,7 @@ class PagureFlaskApiIssuetests(tests.Modeltests): "edited_on": None, "editor": None, "notification": False, - "id": 2, + "id": 1, "parent": None, "user": { "fullname": "foo bar", diff --git a/tests/test_pagure_flask_api_issue_comment.py b/tests/test_pagure_flask_api_issue_comment.py new file mode 100644 index 0000000..123812c --- /dev/null +++ b/tests/test_pagure_flask_api_issue_comment.py @@ -0,0 +1,417 @@ +# -*- coding: utf-8 -*- + +""" + (c) 2015-2017 - Copyright Red Hat Inc + + Authors: + Pierre-Yves Chibon + +""" + + +import datetime +import unittest +import sys +import os + +import json +from mock import patch, MagicMock + +sys.path.insert(0, os.path.join(os.path.dirname( + os.path.abspath(__file__)), '..')) + +import pagure # noqa: E402 +import pagure.lib # noqa: E402 +import tests # noqa: E402 + + +class PagureFlaskApiIssueCommenttests(tests.Modeltests): + """ Tests for the flask API of pagure for changing the status of an + issue + """ + + @patch('pagure.lib.notify.send_email', MagicMock(return_value=True)) + def setUp(self): + """ Set up the environnment, ran before every tests. """ + super(PagureFlaskApiIssueCommenttests, self).setUp() + + pagure.APP.config['TESTING'] = True + pagure.SESSION = self.session + pagure.api.SESSION = self.session + pagure.api.issue.SESSION = self.session + pagure.lib.SESSION = self.session + + pagure.APP.config['TICKETS_FOLDER'] = None + + self.app = pagure.APP.test_client() + + tests.create_projects(self.session) + tests.create_projects_git(os.path.join(self.path, 'tickets')) + tests.create_tokens(self.session) + tests.create_tokens_acl(self.session) + + # Create normal issue + repo = pagure.get_authorized_project(self.session, 'test') + msg = pagure.lib.new_issue( + session=self.session, + repo=repo, + title='Test issue #1', + content='We should work on this', + user='pingou', + ticketfolder=None, + private=False, + ) + self.session.commit() + self.assertEqual(msg.title, 'Test issue #1') + + # Create private issue + msg = pagure.lib.new_issue( + session=self.session, + repo=repo, + title='Test issue #2', + content='We should work on this', + user='foo', + ticketfolder=None, + private=True, + ) + self.session.commit() + self.assertEqual(msg.title, 'Test issue #2') + + # Create project-less token for user foo + item = pagure.lib.model.Token( + id='project-less-foo', + user_id=2, + project_id=None, + expiration=datetime.datetime.utcnow() + + datetime.timedelta(days=30) + ) + self.session.add(item) + self.session.commit() + tests.create_tokens_acl(self.session, token_id='project-less-foo') + + def test_api_comment_issue_invalid_project(self): + """ Test the api_comment_issue method of the flask api. """ + + headers = {'Authorization': 'token aaabbbcccddd'} + + # Invalid project + output = self.app.post('/api/0/foo/issue/1/comment', headers=headers) + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Project not found", + "error_code": "ENOPROJECT", + } + ) + + def test_api_comment_issue_invalid_project_token(self): + """ Test the api_comment_issue method of the flask api. """ + + headers = {'Authorization': 'token aaabbbcccddd'} + + # Valid token, wrong project + output = self.app.post('/api/0/test2/issue/1/comment', headers=headers) + self.assertEqual(output.status_code, 401) + data = json.loads(output.data) + self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name, + data['error_code']) + self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error']) + + def test_api_comment_issue_invalid_issue(self): + """ Test the api_comment_issue method of the flask api. """ + + headers = {'Authorization': 'token aaabbbcccddd'} + # Invalid issue + output = self.app.post('/api/0/test/issue/10/comment', headers=headers) + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Issue not found", + "error_code": "ENOISSUE", + } + ) + + def test_api_comment_issue_incomplete_request(self): + """ Test the api_comment_issue method of the flask api. """ + + headers = {'Authorization': 'token aaabbbcccddd'} + # Check comments before + repo = pagure.get_authorized_project(self.session, 'test') + issue = pagure.lib.search_issues(self.session, repo, issueid=1) + self.assertEqual(len(issue.comments), 0) + + data = { + 'title': 'test issue', + } + + # Incomplete request + output = self.app.post( + '/api/0/test/issue/1/comment', data=data, headers=headers) + self.assertEqual(output.status_code, 400) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Invalid or incomplete input submited", + "error_code": "EINVALIDREQ", + "errors": {"comment": ["This field is required."]} + } + ) + + # No change + repo = pagure.get_authorized_project(self.session, 'test') + issue = pagure.lib.search_issues(self.session, repo, issueid=1) + self.assertEqual(issue.status, 'Open') + + def test_api_comment_issue(self): + """ Test the api_comment_issue method of the flask api. """ + + headers = {'Authorization': 'token aaabbbcccddd'} + + data = { + 'comment': 'This is a very interesting question', + } + + # Valid request + output = self.app.post( + '/api/0/test/issue/1/comment', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertDictEqual( + data, + {'message': 'Comment added'} + ) + + # One comment added + repo = pagure.get_authorized_project(self.session, 'test') + issue = pagure.lib.search_issues(self.session, repo, issueid=1) + self.assertEqual(len(issue.comments), 1) + + def test_api_comment_issue_private_un_authorized(self): + """ Test the api_comment_issue method of the flask api. """ + + # Check before + repo = pagure.get_authorized_project(self.session, 'test') + issue = pagure.lib.search_issues(self.session, repo, issueid=2) + self.assertEqual(len(issue.comments), 0) + + data = { + 'comment': 'This is a very interesting question', + } + headers = {'Authorization': 'token pingou_foo'} + + # Valid request but un-authorized + output = self.app.post( + '/api/0/test/issue/2/comment', data=data, headers=headers) + self.assertEqual(output.status_code, 401) + data = json.loads(output.data) + self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name, + data['error_code']) + self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error']) + + # No comment added + repo = pagure.get_authorized_project(self.session, 'test') + issue = pagure.lib.search_issues(self.session, repo, issueid=2) + self.assertEqual(len(issue.comments), 0) + + @patch('pagure.lib.notify.send_email', MagicMock(return_value=True)) + def test_api_comment_issue_private(self): + """ Test the api_comment_issue method of the flask api. """ + + # Create token for user foo + item = pagure.lib.model.Token( + id='foo_token2', + user_id=2, + project_id=1, + expiration=datetime.datetime.utcnow() + datetime.timedelta(days=30) + ) + self.session.add(item) + self.session.commit() + tests.create_tokens_acl(self.session, token_id='foo_token2') + + data = { + 'comment': 'This is a very interesting question', + } + headers = {'Authorization': 'token foo_token2'} + + # Valid request and authorized + output = self.app.post( + '/api/0/test/issue/2/comment', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertDictEqual( + data, + {'message': 'Comment added'} + ) + + def test_api_comment_issue_invalid_project_project_less(self): + """ Test the api_comment_issue method of the flask api. """ + + headers = {'Authorization': 'token project-less-foo'} + + # Invalid project + output = self.app.post('/api/0/foo/issue/1/comment', headers=headers) + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Project not found", + "error_code": "ENOPROJECT", + } + ) + + def test_api_comment_issue_invalid_project_token_project_less(self): + """ Test the api_comment_issue method of the flask api. """ + + headers = {'Authorization': 'token project-less-foo'} + + # Valid token, no such issue, project-less token so different failure + output = self.app.post('/api/0/test2/issue/1/comment', headers=headers) + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Issue not found", + "error_code": "ENOISSUE", + } + ) + + def test_api_comment_issue_invalid_issue_project_less(self): + """ Test the api_comment_issue method of the flask api. """ + + headers = {'Authorization': 'token project-less-foo'} + # Invalid issue + output = self.app.post('/api/0/test/issue/10/comment', headers=headers) + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Issue not found", + "error_code": "ENOISSUE", + } + ) + + def test_api_comment_issue_incomplete_request_project_less(self): + """ Test the api_comment_issue method of the flask api. """ + + headers = {'Authorization': 'token project-less-foo'} + # Check comments before + repo = pagure.get_authorized_project(self.session, 'test') + issue = pagure.lib.search_issues(self.session, repo, issueid=1) + self.assertEqual(len(issue.comments), 0) + + data = { + 'title': 'test issue', + } + + # Incomplete request + output = self.app.post( + '/api/0/test/issue/1/comment', data=data, headers=headers) + self.assertEqual(output.status_code, 400) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Invalid or incomplete input submited", + "error_code": "EINVALIDREQ", + "errors": {"comment": ["This field is required."]} + } + ) + + # No change + repo = pagure.get_authorized_project(self.session, 'test') + issue = pagure.lib.search_issues(self.session, repo, issueid=1) + self.assertEqual(issue.status, 'Open') + + @patch('pagure.lib.notify.send_email', MagicMock(return_value=True)) + def test_api_comment_issue_project_less(self): + """ Test the api_comment_issue method of the flask api. """ + + headers = {'Authorization': 'token project-less-foo'} + + data = { + 'comment': 'This is a very interesting question', + } + + # Valid request + output = self.app.post( + '/api/0/test/issue/1/comment', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertDictEqual( + data, + {'message': 'Comment added'} + ) + + # One comment added + repo = pagure.get_authorized_project(self.session, 'test') + issue = pagure.lib.search_issues(self.session, repo, issueid=1) + self.assertEqual(len(issue.comments), 1) + + def test_api_comment_issue_private_un_authorized_project_less(self): + """ Test the api_comment_issue method of the flask api. """ + + # Check before + repo = pagure.get_authorized_project(self.session, 'test') + issue = pagure.lib.search_issues(self.session, repo, issueid=2) + self.assertEqual(len(issue.comments), 0) + + data = { + 'comment': 'This is a very interesting question', + } + headers = {'Authorization': 'token pingou_foo'} + + # Valid request but un-authorized + output = self.app.post( + '/api/0/test/issue/2/comment', data=data, headers=headers) + self.assertEqual(output.status_code, 401) + data = json.loads(output.data) + self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name, + data['error_code']) + self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error']) + + # No comment added + repo = pagure.get_authorized_project(self.session, 'test') + issue = pagure.lib.search_issues(self.session, repo, issueid=2) + self.assertEqual(len(issue.comments), 0) + + @patch('pagure.lib.notify.send_email', MagicMock(return_value=True)) + def test_api_comment_issue_private_project_less(self): + """ Test the api_comment_issue method of the flask api. """ + + # Create token for user foo + item = pagure.lib.model.Token( + id='foo_token2', + user_id=2, + project_id=None, + expiration=datetime.datetime.utcnow() + datetime.timedelta(days=30) + ) + self.session.add(item) + self.session.commit() + tests.create_tokens_acl(self.session, token_id='foo_token2') + + data = { + 'comment': 'This is a very interesting question', + } + headers = {'Authorization': 'token foo_token2'} + + # Valid request and authorized + output = self.app.post( + '/api/0/test/issue/2/comment', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertDictEqual( + data, + {'message': 'Comment added'} + ) + + +if __name__ == '__main__': + unittest.main(verbosity=2) From 649607984b046b880fb5e4d47c2e97ab9a06c5e7 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: May 09 2017 02:13:15 +0000 Subject: [PATCH 5/6] Allow project-less token to change the status of an issue in the API Signed-off-by: Pierre-Yves Chibon --- diff --git a/pagure/api/issue.py b/pagure/api/issue.py index 284de20..5598e23 100644 --- a/pagure/api/issue.py +++ b/pagure/api/issue.py @@ -678,7 +678,7 @@ def api_change_status_issue(repo, issueid, username=None, namespace=None): repo = _get_repo(repo, username, namespace) _check_issue_tracker(repo) - _check_token(repo) + _check_token(repo, project_token=False) issue = _get_issue(repo, issueid) _check_ticket_access(issue) diff --git a/pagure/default_config.py b/pagure/default_config.py index b19c37c..d4e3dc5 100644 --- a/pagure/default_config.py +++ b/pagure/default_config.py @@ -239,6 +239,7 @@ CROSS_PROJECT_ACLS = [ ADMIN_API_ACLS = [ 'issue_comment', 'issue_create', + 'issue_change_status', 'pull_request_flag', 'pull_request_comment', 'pull_request_merge', diff --git a/tests/test_pagure_flask_api_issue_change_status.py b/tests/test_pagure_flask_api_issue_change_status.py index 536d85b..43265f9 100644 --- a/tests/test_pagure_flask_api_issue_change_status.py +++ b/tests/test_pagure_flask_api_issue_change_status.py @@ -82,6 +82,30 @@ class PagureFlaskApiIssueChangeStatustests(tests.Modeltests): self.session.commit() self.assertEqual(msg.title, 'Test issue #2') + # Create project-less token for user foo + item = pagure.lib.model.Token( + id='project-less-foo', + user_id=2, + project_id=None, + expiration=datetime.datetime.utcnow() + + datetime.timedelta(days=30) + ) + self.session.add(item) + self.session.commit() + tests.create_tokens_acl(self.session, token_id='project-less-foo') + + # Create project-less token for user pingou + item = pagure.lib.model.Token( + id='project-less-pingou', + user_id=1, + project_id=None, + expiration=datetime.datetime.utcnow() + + datetime.timedelta(days=30) + ) + self.session.add(item) + self.session.commit() + tests.create_tokens_acl(self.session, token_id='project-less-pingou') + def test_api_change_status_issue_invalid_project(self): """ Test the api_change_status_issue method of the flask api. """ @@ -222,6 +246,56 @@ class PagureFlaskApiIssueChangeStatustests(tests.Modeltests): data['error_code']) self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error']) + @patch('pagure.lib.notify.send_email', MagicMock(return_value=True)) + def test_api_change_status_issue_no_ticket_project_less(self): + """ Test the api_change_status_issue method of the flask api. """ + + headers = {'Authorization': 'token project-less-foo'} + + data = { + 'status': 'Fixed', + } + + # Valid request + output = self.app.post( + '/api/0/test/issue/1/status', data=data, headers=headers) + self.assertEqual(output.status_code, 403) + data = json.loads(output.data) + + self.assertDictEqual( + data, + { + "error": "You are not allowed to view this issue", + "error_code": "EISSUENOTALLOWED" + } + ) + + @patch('pagure.lib.notify.send_email', MagicMock(return_value=True)) + def test_api_change_status_issue_project_less(self): + """ Test the api_change_status_issue method of the flask api. """ + + headers = {'Authorization': 'token project-less-pingou'} + + data = { + 'status': 'Fixed', + } + + # Valid request + output = self.app.post( + '/api/0/test/issue/1/status', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + + self.assertDictEqual( + data, + { + "message": [ + "Issue status updated to: Closed (was: Open)", + "Issue close_status updated to: Fixed" + ] + } + ) + if __name__ == '__main__': unittest.main(verbosity=2) From e2218681babab83ed290577cf6e4871a05b33f2d Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: May 09 2017 02:13:15 +0000 Subject: [PATCH 6/6] Fix the tests due to the change in the ordering of the ACLs --- diff --git a/tests/test_pagure_admin.py b/tests/test_pagure_admin.py index 2454d2c..3b33249 100644 --- a/tests/test_pagure_admin.py +++ b/tests/test_pagure_admin.py @@ -345,7 +345,7 @@ class PagureAdminAdminTokentests(tests.Modeltests): """ Test the do_info_admin_token function of pagure-admin. """ # Create an admin token to use conf.return_value = True - rinp.return_value = '1,2,3' + rinp.return_value = '1,3,4' args = munch.Munch({'user': 'pingou'}) pagure.cli.admin.do_create_admin_token(args)