From 5a55feb7d449b97b638d8a16d807b7ef52a63ea5 Mon Sep 17 00:00:00 2001 From: Matt Prahl Date: Apr 13 2017 13:38:08 +0000 Subject: [PATCH 1/4] Remove usage of 'assert_called_once' in test because pinned version of mock doesn't support it --- diff --git a/tests/test_pagure_lib.py b/tests/test_pagure_lib.py index d816823..c4e3b59 100644 --- a/tests/test_pagure_lib.py +++ b/tests/test_pagure_lib.py @@ -1416,7 +1416,7 @@ class PagureLibtests(tests.Modeltests): user='pingou', ) self.assertEqual(msg, 'Edited successfully settings of repo: test2') - mock_log.assert_called_once() + self.assertEqual(mock_log.call_count, 1) args = mock_log.call_args self.assertEqual(len(args), 2) self.assertEqual(args[0][0].fullname, 'test2') From 1a51d985c22f55a7c6d223b5a83a99242c9c7ded Mon Sep 17 00:00:00 2001 From: Matt Prahl Date: Apr 13 2017 13:38:11 +0000 Subject: [PATCH 2/4] Add group information API that shows group members --- diff --git a/pagure/api/__init__.py b/pagure/api/__init__.py index 045586c..d349944 100644 --- a/pagure/api/__init__.py +++ b/pagure/api/__init__.py @@ -84,6 +84,7 @@ class APIERROR(enum.Enum): EINVALIDISSUEFIELD_LINK = 'Invalid custom field submitted, the value '\ 'is not a link' EINVALIDPRIORITY = 'Invalid priority submitted' + ENOGROUP = 'Group not found' def check_api_acls(acls, optional=False): @@ -212,6 +213,7 @@ if pagure.APP.config.get('ENABLE_TICKETS', True): from pagure.api import fork # noqa from pagure.api import project # noqa from pagure.api import user # noqa +from pagure.api import group # noqa if pagure.APP.config.get('PAGURE_CI_SERVICES', False): from pagure.api.ci import jenkins # noqa @@ -480,6 +482,8 @@ def api(): api_view_user_activity_date_doc = load_doc( user.api_view_user_activity_date) + api_view_group_doc = load_doc(group.api_view_group) + if pagure.APP.config.get('ENABLE_TICKETS', True): api_project_tags_doc = load_doc(api_project_tags) api_groups_doc = load_doc(api_groups) @@ -519,6 +523,9 @@ def api(): api_view_user_activity_stats_doc, api_view_user_activity_date_doc, ], + groups=[ + api_view_group_doc + ], ci=ci_doc, extras=extras, ) diff --git a/pagure/api/group.py b/pagure/api/group.py new file mode 100644 index 0000000..3e30ca9 --- /dev/null +++ b/pagure/api/group.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +""" + (c) 2017 - Copyright Red Hat Inc + + Authors: + Matt Prahl + +""" + +import flask + +import pagure +import pagure.exceptions +import pagure.lib +from pagure import SESSION +from pagure.api import API, api_method, APIERROR + + +@API.route('/group/') +@api_method +def api_view_group(group): + """ + Group information + ----------------- + Use this endpoint to retrieve information about a specific group. + + :: + + GET /api/0/group/ + + :: + + GET /api/0/group/some_group_name + + Sample response + ^^^^^^^^^^^^^^^ + + :: + + { + "creator": { + "default_email": "user1@example.com", + "emails": [ + "user1@example.com" + ], + "fullname": "User1", + "name": "user1" + }, + "date_created": "1492011511", + "description": "Some Group", + "display_name": "Some Group", + "group_type": "user", + "members": [ + "user1", + "user2" + ], + "name": "some_group_name" + } + """ + group = pagure.lib.search_groups(SESSION, group_name=group) + if not group: + raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOGROUP) + + jsonout = flask.jsonify(group.to_json()) + jsonout.status_code = 200 + return jsonout diff --git a/pagure/lib/model.py b/pagure/lib/model.py index 441e7df..3bbf258 100644 --- a/pagure/lib/model.py +++ b/pagure/lib/model.py @@ -1978,6 +1978,7 @@ class PagureGroup(BASE): 'group_type': self.group_type, 'creator': self.creator.to_json(public=public), 'date_created': self.created.strftime('%s'), + 'members': [user.username for user in self.users] } return output diff --git a/pagure/templates/api.html b/pagure/templates/api.html index b34c151..d14e235 100644 --- a/pagure/templates/api.html +++ b/pagure/templates/api.html @@ -76,6 +76,18 @@ {% endfor %} +

+ Groups + + + +

+
+ {% for html in groups %} + {{ html | InsertDiv | safe }} + {% endfor %} +
+ {% if config.get('PAGURE_CI_SERVICES') %}

Continous Integration Services diff --git a/tests/test_pagure_flask_api_group.py b/tests/test_pagure_flask_api_group.py new file mode 100644 index 0000000..1041372 --- /dev/null +++ b/tests/test_pagure_flask_api_group.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- + +""" + (c) 2017 - Copyright Red Hat Inc + + Authors: + Matt Prahl + +""" + +__requires__ = ['SQLAlchemy >= 0.8'] +import unittest +import sys +import os +import json + +sys.path.insert(0, os.path.join(os.path.dirname( + os.path.abspath(__file__)), '..')) + +import pagure.api +import pagure.lib +import tests + + +class PagureFlaskApiGroupTests(tests.Modeltests): + """ Tests for the flask API of pagure for issue """ + + def setUp(self): + """ Set up the environnment, ran before every tests. """ + super(PagureFlaskApiGroupTests, self).setUp() + + pagure.APP.config['TESTING'] = True + pagure.SESSION = self.session + pagure.api.SESSION = self.session + pagure.api.group.SESSION = self.session + pagure.api.user.SESSION = self.session + pagure.lib.SESSION = self.session + + pagure.APP.config['REQUESTS_FOLDER'] = None + + msg = pagure.lib.add_group( + self.session, + group_name='some_group', + display_name='Some Group', + description=None, + group_type='bar', + user='pingou', + is_admin=False, + blacklist=[], + ) + self.session.commit() + + self.app = pagure.APP.test_client() + + def test_api_view_group(self): + """ + Test the api_view_group method of the flask api + The tested group has one member. + """ + output = self.app.get("/api/0/group/some_group") + self.assertEqual(output.status_code, 200) + exp = { + "display_name": "Some Group", + "description": None, + "creator": { + "fullname": "PY C", + "default_email": "bar@pingou.com", + "emails": [ + "bar@pingou.com", + "foo@pingou.com" + ], + "name": "pingou" + }, + "members": ["pingou"], + "date_created": "1492020239", + "group_type": "user", + "name": "some_group" + } + data = json.loads(output.data) + data['date_created'] = '1492020239' + self.assertDictEqual(data, exp) + + def test_api_view_group_two_members(self): + """ + Test the api_view_group method of the flask api + The tested group has two members. + """ + user = pagure.lib.model.User( + user='mprahl', + fullname='Matt Prahl', + password='foo', + default_email='mprahl@redhat.com', + ) + self.session.add(user) + self.session.commit() + group = pagure.lib.search_groups(self.session, group_name='some_group') + result = pagure.lib.add_user_to_group( + self.session, user.username, group, user.username, True) + self.session.commit() + output = self.app.get("/api/0/group/some_group") + self.assertEqual(output.status_code, 200) + exp = { + "display_name": "Some Group", + "description": None, + "creator": { + "fullname": "PY C", + "default_email": "bar@pingou.com", + "emails": [ + "bar@pingou.com", + "foo@pingou.com" + ], + "name": "pingou" + }, + "members": ["pingou", "mprahl"], + "date_created": "1492020239", + "group_type": "user", + "name": "some_group" + } + self.maxDiff = None + data = json.loads(output.data) + data['date_created'] = '1492020239' + from pprint import pprint + pprint(data) + self.assertDictEqual(data, exp) + + def test_api_view_group_no_group_error(self): + """ + Test the api_view_group method of the flask api + The tested group has one member. + """ + output = self.app.get("/api/0/group/some_group3") + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertEqual(data['error'], 'Group not found') + self.assertEqual(data['error_code'], 'ENOGROUP') + +if __name__ == "__main__": + SUITE = unittest.TestLoader().loadTestsFromTestCase( + PagureFlaskApiGroupTests) + unittest.TextTestRunner(verbosity=2).run(SUITE) From 802ab83ec0e1f31c926f87180359e35e9d9e64dc Mon Sep 17 00:00:00 2001 From: Matt Prahl Date: Apr 13 2017 13:38:13 +0000 Subject: [PATCH 3/4] Move api_groups function to pagure.api.group --- diff --git a/pagure/api/__init__.py b/pagure/api/__init__.py index d349944..3c542f3 100644 --- a/pagure/api/__init__.py +++ b/pagure/api/__init__.py @@ -359,55 +359,6 @@ def api_project_tags(repo, username=None): ) -@API.route('/groups/') -@API.route('/groups') -def api_groups(): - ''' - List groups - ----------- - Retrieve groups on this Pagure instance. - This can then be used as input for autocompletion in some forms/fields. - - :: - - GET /api/0/groups - - Parameters - ^^^^^^^^^^ - - +---------------+----------+---------------+--------------------------+ - | Key | Type | Optionality | Description | - +===============+==========+===============+==========================+ - | ``pattern`` | string | Optional | | Filters the starting | - | | | | letters of the group | - | | | | names | - +---------------+----------+---------------+--------------------------+ - - Sample response - ^^^^^^^^^^^^^^^ - - :: - - { - "total_groups": 2, - "groups": ["group1", "group2"] - } - - ''' - pattern = flask.request.args.get('pattern', None) - if pattern is not None and not pattern.endswith('*'): - pattern += '*' - - groups = pagure.lib.search_groups(SESSION, pattern=pattern) - - return flask.jsonify( - { - 'total_groups': len(groups), - 'groups': [group.group_name for group in groups] - } - ) - - @API.route('/error_codes/') @API.route('/error_codes') def api_error_codes(): @@ -483,10 +434,10 @@ def api(): user.api_view_user_activity_date) api_view_group_doc = load_doc(group.api_view_group) + api_groups_doc = load_doc(group.api_groups) if pagure.APP.config.get('ENABLE_TICKETS', True): api_project_tags_doc = load_doc(api_project_tags) - api_groups_doc = load_doc(api_groups) api_error_codes_doc = load_doc(api_error_codes) extras = [ @@ -519,11 +470,11 @@ def api(): users=[ api_users_doc, api_view_user_doc, - api_groups_doc, api_view_user_activity_stats_doc, api_view_user_activity_date_doc, ], groups=[ + api_groups_doc, api_view_group_doc ], ci=ci_doc, diff --git a/pagure/api/group.py b/pagure/api/group.py index 3e30ca9..57b7752 100644 --- a/pagure/api/group.py +++ b/pagure/api/group.py @@ -4,6 +4,7 @@ (c) 2017 - Copyright Red Hat Inc Authors: + Pierre-Yves Chibon Matt Prahl """ @@ -17,6 +18,55 @@ from pagure import SESSION from pagure.api import API, api_method, APIERROR +@API.route('/groups/') +@API.route('/groups') +def api_groups(): + ''' + List groups + ----------- + Retrieve groups on this Pagure instance. + This can then be used as input for autocompletion in some forms/fields. + + :: + + GET /api/0/groups + + Parameters + ^^^^^^^^^^ + + +---------------+----------+---------------+--------------------------+ + | Key | Type | Optionality | Description | + +===============+==========+===============+==========================+ + | ``pattern`` | string | Optional | | Filters the starting | + | | | | letters of the group | + | | | | names | + +---------------+----------+---------------+--------------------------+ + + Sample response + ^^^^^^^^^^^^^^^ + + :: + + { + "total_groups": 2, + "groups": ["group1", "group2"] + } + + ''' + pattern = flask.request.args.get('pattern', None) + if pattern is not None and not pattern.endswith('*'): + pattern += '*' + + groups = pagure.lib.search_groups(SESSION, pattern=pattern) + + return flask.jsonify( + { + 'total_groups': len(groups), + 'groups': [group.group_name for group in groups] + } + ) + + @API.route('/group/') @api_method def api_view_group(group): diff --git a/tests/test_pagure_flask_api.py b/tests/test_pagure_flask_api.py index c912d38..0b198cd 100644 --- a/tests/test_pagure_flask_api.py +++ b/tests/test_pagure_flask_api.py @@ -109,41 +109,6 @@ class PagureFlaskApitests(tests.Modeltests): self.assertEqual(data['tags'], []) self.assertEqual(data['total_tags'], 0) - def test_api_groups(self): - """ Test the api_groups function. """ - - # Add a couple of groups so that we can list them - item = pagure.lib.model.PagureGroup( - group_name='group1', - group_type='user', - display_name='User group', - user_id=1, # pingou - ) - self.session.add(item) - - item = pagure.lib.model.PagureGroup( - group_name='rel-eng', - group_type='user', - display_name='Release engineering group', - user_id=1, # pingou - ) - self.session.add(item) - self.session.commit() - - output = self.app.get('/api/0/groups') - self.assertEqual(output.status_code, 200) - data = json.loads(output.data) - self.assertEqual(data['groups'], ['group1', 'rel-eng']) - self.assertEqual(sorted(data.keys()), ['groups', 'total_groups']) - self.assertEqual(data['total_groups'], 2) - - output = self.app.get('/api/0/groups?pattern=re') - self.assertEqual(output.status_code, 200) - data = json.loads(output.data) - self.assertEqual(data['groups'], ['rel-eng']) - self.assertEqual(sorted(data.keys()), ['groups', 'total_groups']) - self.assertEqual(data['total_groups'], 1) - if __name__ == '__main__': SUITE = unittest.TestLoader().loadTestsFromTestCase(PagureFlaskApitests) diff --git a/tests/test_pagure_flask_api_group.py b/tests/test_pagure_flask_api_group.py index 1041372..896e780 100644 --- a/tests/test_pagure_flask_api_group.py +++ b/tests/test_pagure_flask_api_group.py @@ -52,6 +52,41 @@ class PagureFlaskApiGroupTests(tests.Modeltests): self.app = pagure.APP.test_client() + def test_api_groups(self): + """ Test the api_groups function. """ + + # Add a couple of groups so that we can list them + item = pagure.lib.model.PagureGroup( + group_name='group1', + group_type='user', + display_name='User group', + user_id=1, # pingou + ) + self.session.add(item) + + item = pagure.lib.model.PagureGroup( + group_name='rel-eng', + group_type='user', + display_name='Release engineering group', + user_id=1, # pingou + ) + self.session.add(item) + self.session.commit() + + output = self.app.get('/api/0/groups') + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertEqual(data['groups'], ['some_group', 'group1', 'rel-eng']) + self.assertEqual(sorted(data.keys()), ['groups', 'total_groups']) + self.assertEqual(data['total_groups'], 3) + + output = self.app.get('/api/0/groups?pattern=re') + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertEqual(data['groups'], ['rel-eng']) + self.assertEqual(sorted(data.keys()), ['groups', 'total_groups']) + self.assertEqual(data['total_groups'], 1) + def test_api_view_group(self): """ Test the api_view_group method of the flask api From 9264b1af733f59dbad93a5d9aec8f1bd90bd1ba5 Mon Sep 17 00:00:00 2001 From: Matt Prahl Date: Apr 13 2017 13:38:16 +0000 Subject: [PATCH 4/4] Add optional authentication to the groups API --- diff --git a/pagure/api/group.py b/pagure/api/group.py index 57b7752..78ab1b2 100644 --- a/pagure/api/group.py +++ b/pagure/api/group.py @@ -15,7 +15,7 @@ import pagure import pagure.exceptions import pagure.lib from pagure import SESSION -from pagure.api import API, api_method, APIERROR +from pagure.api import API, APIERROR, api_method, api_login_optional @API.route('/groups/') @@ -68,6 +68,7 @@ def api_groups(): @API.route('/group/') +@api_login_optional() @api_method def api_view_group(group): """ @@ -112,6 +113,7 @@ def api_view_group(group): if not group: raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOGROUP) - jsonout = flask.jsonify(group.to_json()) + jsonout = flask.jsonify(group.to_json( + public=(not pagure.api_authenticated()))) jsonout.status_code = 200 return jsonout diff --git a/tests/test_pagure_flask_api_group.py b/tests/test_pagure_flask_api_group.py index 896e780..8d82405 100644 --- a/tests/test_pagure_flask_api_group.py +++ b/tests/test_pagure_flask_api_group.py @@ -87,12 +87,14 @@ class PagureFlaskApiGroupTests(tests.Modeltests): self.assertEqual(sorted(data.keys()), ['groups', 'total_groups']) self.assertEqual(data['total_groups'], 1) - def test_api_view_group(self): + def test_api_view_group_authenticated(self): """ - Test the api_view_group method of the flask api - The tested group has one member. + Test the api_view_group method of the flask api with an + authenticated user. The tested group has one member. """ - output = self.app.get("/api/0/group/some_group") + tests.create_tokens(self.session) + headers = {'Authorization': 'token aaabbbcccddd'} + output = self.app.get('/api/0/group/some_group', headers=headers) self.assertEqual(output.status_code, 200) exp = { "display_name": "Some Group", @@ -115,10 +117,33 @@ class PagureFlaskApiGroupTests(tests.Modeltests): data['date_created'] = '1492020239' self.assertDictEqual(data, exp) - def test_api_view_group_two_members(self): + def test_api_view_group_unauthenticated(self): """ - Test the api_view_group method of the flask api - The tested group has two members. + Test the api_view_group method of the flask api with an + unauthenticated user. The tested group has one member. + """ + output = self.app.get('/api/0/group/some_group') + self.assertEqual(output.status_code, 200) + exp = { + "display_name": "Some Group", + "description": None, + "creator": { + "fullname": "PY C", + "name": "pingou" + }, + "members": ["pingou"], + "date_created": "1492020239", + "group_type": "user", + "name": "some_group" + } + data = json.loads(output.data) + data['date_created'] = '1492020239' + self.assertDictEqual(data, exp) + + def test_api_view_group_two_members_authenticated(self): + """ + Test the api_view_group method of the flask api with an + authenticated user. The tested group has two members. """ user = pagure.lib.model.User( user='mprahl', @@ -132,7 +157,10 @@ class PagureFlaskApiGroupTests(tests.Modeltests): result = pagure.lib.add_user_to_group( self.session, user.username, group, user.username, True) self.session.commit() - output = self.app.get("/api/0/group/some_group") + + tests.create_tokens(self.session) + headers = {'Authorization': 'token aaabbbcccddd'} + output = self.app.get('/api/0/group/some_group', headers=headers) self.assertEqual(output.status_code, 200) exp = { "display_name": "Some Group",