From c25173ed2cfdcd0d5d893d37608edddf14d10c8f Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Sep 21 2017 08:20:29 +0000 Subject: [PATCH 1/5] Add namespace support to the get_ticket_template endpoint in the internal API This will allow loading templates for namespaced project wanting to use that feature. Signed-off-by: Pierre-Yves Chibon --- diff --git a/pagure/internal/__init__.py b/pagure/internal/__init__.py index f092a68..40fc6ff 100644 --- a/pagure/internal/__init__.py +++ b/pagure/internal/__init__.py @@ -320,8 +320,10 @@ def get_pull_request_ready_branch(): @PV.route('//issue/template', methods=['POST']) +@PV.route('///issue/template', methods=['POST']) @PV.route('/fork///issue/template', methods=['POST']) -def get_ticket_template(repo, username=None): +@PV.route('/fork////issue/template', methods=['POST']) +def get_ticket_template(repo, namespace=None, username=None): """ Return the template asked for the specified project """ @@ -343,7 +345,8 @@ def get_ticket_template(repo, username=None): response.status_code = 400 return response - repo = pagure.get_authorized_project(pagure.SESSION, repo, user=username) + repo = pagure.get_authorized_project( + pagure.SESSION, repo, user=username, namespace=namespace) if repo is None: response = flask.jsonify({ From ce252c39f5e6bacc16d370311847fc81f66d2575 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Sep 21 2017 08:20:29 +0000 Subject: [PATCH 2/5] .rstrip() doesn't do what one would think it does, replace with .rsplit() .rstrip() will remove, from the right of the string, all the character it is given, so if you do .rstrip('foobar'), it will remove all 'f', 'o', 'b', 'a' and 'r' from the right hand side of the word. This is not what we want, we want to remove the `.md` part of the filename, so let's split on this and get what is in front of it. Fixes https://pagure.io/pagure/issue/2601 Signed-off-by: Pierre-Yves Chibon --- diff --git a/pagure/ui/issues.py b/pagure/ui/issues.py index 47a4ede..6259d75 100644 --- a/pagure/ui/issues.py +++ b/pagure/ui/issues.py @@ -958,7 +958,7 @@ def new_issue(repo, username=None, namespace=None): ticketrepo, commit.tree, ['templates'], bail_on_tree=True) if files: - types = [f.name.rstrip('.md') for f in files] + types = [f.name.rsplit('.md', 1)[0] for f in files] # Get the default template default_file = __get_file_in_tree( ticketrepo, commit.tree, ['templates', 'default.md'], From 91c1f357adc77f0b21e15f6177c68ffc97f3ec67 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Sep 21 2017 08:20:29 +0000 Subject: [PATCH 3/5] Adjust the documentation around ticket templates Relates to https://pagure.io/pagure/issue/2601 Signed-off-by: Pierre-Yves Chibon --- diff --git a/doc/usage/ticket_templates.rst b/doc/usage/ticket_templates.rst index 07e6e9f..e83ec74 100644 --- a/doc/usage/ticket_templates.rst +++ b/doc/usage/ticket_templates.rst @@ -26,7 +26,7 @@ For a project named ``test`` on ``pagure.io``. :: - git clone ssh://git@pagure.io/tickets/pagure.git + git clone ssh://git@pagure.io/tickets/test.git cd test * Create the templates folder @@ -72,6 +72,8 @@ And place in this file the following content: -.. [#f1] All the URLs to the different git repositories can be found on the +.. [#f1] The URLs to the different git repositories can be found on the main page of the project, on the right-side menu, under the section - ``Source GIT URLs``, click on ``more`` to see them. + ``Source GIT URLs``. Click on ``more`` to see them if you are logged + in and have access to the repository (the ticket and request git + repositories require a `commit` access or higher). From fc1d7f885d8b658ce7ba2fbd9cf20692b32f7732 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Sep 21 2017 08:20:29 +0000 Subject: [PATCH 4/5] Flake8 fix fixing the tests --- diff --git a/pagure/internal/__init__.py b/pagure/internal/__init__.py index 40fc6ff..d729b86 100644 --- a/pagure/internal/__init__.py +++ b/pagure/internal/__init__.py @@ -322,7 +322,8 @@ def get_pull_request_ready_branch(): @PV.route('//issue/template', methods=['POST']) @PV.route('///issue/template', methods=['POST']) @PV.route('/fork///issue/template', methods=['POST']) -@PV.route('/fork////issue/template', methods=['POST']) +@PV.route('/fork////issue/template', + methods=['POST']) def get_ticket_template(repo, namespace=None, username=None): """ Return the template asked for the specified project """ From 75b9021afbb08a3bdc1128cb282ea9c2394c0b67 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Sep 21 2017 08:20:29 +0000 Subject: [PATCH 5/5] Add unit-tests for the fixes around loading issue template Signed-off-by: Pierre-Yves Chibon --- diff --git a/tests/test_pagure_flask_ui_issues_templates.py b/tests/test_pagure_flask_ui_issues_templates.py new file mode 100644 index 0000000..bb2ec64 --- /dev/null +++ b/tests/test_pagure_flask_ui_issues_templates.py @@ -0,0 +1,264 @@ +# -*- coding: utf-8 -*- + +""" + (c) 2017 - Copyright Red Hat Inc + + Authors: + Pierre-Yves Chibon + +""" + +__requires__ = ['SQLAlchemy >= 0.8'] +import pkg_resources + +import json +import unittest +import sys +import os + +import pygit2 +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 + + +def create_templates(repopath): + """ Create a couple of templates at the specified repo. + """ + clone_repo = pygit2.Repository(repopath) + + # Create the RFE template + os.mkdir(os.path.join(repopath, 'templates')) + template = os.path.join(repopath, 'templates', 'RFE.md') + with open(template, 'w') as stream: + stream.write('RFE\n###\n\n* Idea description') + clone_repo.index.add(os.path.join('templates', 'RFE.md')) + clone_repo.index.write() + + # Commit + tree = clone_repo.index.write_tree() + author = pygit2.Signature( + 'Alice Author', 'alice@authors.tld') + committer = pygit2.Signature( + 'Cecil Committer', 'cecil@committers.tld') + commit = clone_repo.create_commit( + 'refs/heads/master', # the name of the reference to update + author, + committer, + 'Add a RFE template', + # binary string representing the tree object ID + tree, + # list of binary strings representing parents of the new commit + [] + ) + + # Create the 2018-bid.md template + template = os.path.join(repopath, 'templates', '2018-bid.md') + with open(template, 'w') as stream: + stream.write('Bid for 2018\n############\n\n* Location:') + clone_repo.index.add(os.path.join('templates', '2018-bid.md')) + clone_repo.index.write() + + # Commit + tree = clone_repo.index.write_tree() + author = pygit2.Signature( + 'Alice Author', 'alice@authors.tld') + committer = pygit2.Signature( + 'Cecil Committer', 'cecil@committers.tld') + clone_repo.create_commit( + 'refs/heads/master', # the name of the reference to update + author, + committer, + 'Add a RFE template', + # binary string representing the tree object ID + tree, + # list of binary strings representing parents of the new commit + [commit.hex] + ) + + +class PagureFlaskIssuestests(tests.Modeltests): + """ Tests for flask issues controller of pagure """ + + @patch('pagure.lib.git.update_git', MagicMock(return_value=True)) + @patch('pagure.lib.notify.send_email', MagicMock(return_value=True)) + def setUp(self): + """ Set up the environnment, run before every tests. """ + super(PagureFlaskIssuestests, self).setUp() + + pagure.APP.config['TESTING'] = True + pagure.SESSION = self.session + pagure.ui.SESSION = self.session + pagure.ui.app.SESSION = self.session + pagure.ui.issues.SESSION = self.session + pagure.ui.repo.SESSION = self.session + pagure.ui.filters.SESSION = self.session + pagure.APP.config['TICKETS_FOLDER'] = os.path.join( + self.path, 'tickets') + + tests.create_projects(self.session) + tests.create_projects_git( + os.path.join(self.path, 'repos'), bare=True) + tests.create_projects_git( + os.path.join(self.path, 'tickets')) + + # Add a couple of templates to test2 + repopath = os.path.join(self.path, 'tickets', 'test2.git') + create_templates(repopath) + + # Add a couple of templates to somenamespace/test3 + repopath = os.path.join( + self.path, 'tickets', 'somenamespace', 'test3.git') + create_templates(repopath) + + def test_new_issue_no_template(self): + """ Test the new_issue endpoint when the project has no templates. + """ + + user = tests.FakeUser() + with tests.user_set(pagure.APP, user): + output = self.app.get('/test/new_issue') + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\n New issue', + output.data) + self.assertNotIn( + '', + output.data) + self.assertNotIn( + '', + output.data) + self.assertIn( + '', + output.data) + self.assertIn( + '', + output.data) + + def test_get_ticket_template_no_csrf(self): + """ Test the get_ticket_template endpoint when the project has no + templates. + """ + + user = tests.FakeUser() + with tests.user_set(pagure.APP, user): + output = self.app.post('/pv/test/issue/template') + self.assertEqual(output.status_code, 400) + data = json.loads(output.data) + self.assertEqual( + data, + {"code": "ERROR", "message": "Invalid input submitted"}) + + def test_get_ticket_template_no_template_specified(self): + """ Test the get_ticket_template endpoint when not specifying which + template to get. + """ + + user = tests.FakeUser() + with tests.user_set(pagure.APP, user): + csrf = self.get_csrf() + data = {'csrf_token': csrf} + output = self.app.post('/pv/test/issue/template', data=data) + self.assertEqual(output.status_code, 400) + data = json.loads(output.data) + self.assertEqual( + data, + {"code": "ERROR", "message": "No template provided"}) + + def test_get_ticket_template_no_project(self): + """ Test the get_ticket_template endpoint when not specifying which + template to get. + """ + + user = tests.FakeUser() + with tests.user_set(pagure.APP, user): + csrf = self.get_csrf() + data = {'csrf_token': csrf} + output = self.app.post( + '/pv/test/issue/template?template=RFE', data=data) + self.assertEqual(output.status_code, 404) + + def test_get_ticket_template_no_template(self): + """ Test the get_ticket_template endpoint when the project has no + templates. + """ + + user = tests.FakeUser() + with tests.user_set(pagure.APP, user): + csrf = self.get_csrf() + data = {'csrf_token': csrf} + output = self.app.post( + '/pv/test/issue/template?template=RFE', data=data) + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertEqual( + data, + {"code": "ERROR", "message": "No such template found"}) + + def test_get_ticket_template_w_template(self): + """ Test the get_ticket_template endpoint when the project has + templates. + """ + + user = tests.FakeUser() + with tests.user_set(pagure.APP, user): + csrf = self.get_csrf() + data = {'csrf_token': csrf} + output = self.app.post( + '/pv/test2/issue/template?template=RFE', data=data) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertEqual( + data, + { + "code": "OK", + "message": "RFE\n###\n\n* Idea description" + } + ) + + def test_get_ticket_template_w_template_namespace(self): + """ Test the get_ticket_template endpoint when the project has + templates and a namespace. + """ + + user = tests.FakeUser() + with tests.user_set(pagure.APP, user): + csrf = self.get_csrf() + data = {'csrf_token': csrf} + output = self.app.post( + '/pv/somenamespace/test3/issue/template?template=RFE', + data=data) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertEqual( + data, + { + "code": "OK", + "message": "RFE\n###\n\n* Idea description" + } + ) + +if __name__ == '__main__': + unittest.main(verbosity=2)