From 0f50193c1233b134e96cc2c69bc93ed54a6cb87b Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 07 2017 10:40:49 +0000 Subject: Add the EXCLUDE_GROUP_INDEX feature and corresponding tests This new configuration key allows to hide projects an user has only access to via one or more specified group. This will not remove the access, just not show the project on the user's user page in order to not show the 17,000 projects that the people in the provenpackager group in Fedora have access to when pagure is used as a front-end for Fedora's git repositories. --- diff --git a/doc/configuration.rst b/doc/configuration.rst index 4c6a666..46782fb 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -604,6 +604,24 @@ this pagure instance does not have a documentation server. Defaults to: ``None`` +EXCLUDE_GROUP_INDEX +~~~~~~~~~~~~~~~~~~~ + +This configuration key can be used to hide project an user has access to via +one of the groups listed in this key. + +The use-case is the following: the Fedora project is deploying pagure has a +front-end for the git repos of the packages in the distribution, that means +about 17,000 git repositories in pagure. The project has a group of people +that have access to all of these repositories, so when viewing the user's +page of one member ot that group, instead of seeing all the project that +this user works on, you can see all the projects hosted in that pagure +instance. Using this configuration key, pagure will hide all the projects +that this user has access to via the specified groups and thus return only +the groups of forks of that users. + +Defaults to: ``[]`` + Deprecated configuration keys ----------------------------- diff --git a/pagure/default_config.py b/pagure/default_config.py index 658b27a..3d9a780 100644 --- a/pagure/default_config.py +++ b/pagure/default_config.py @@ -232,3 +232,7 @@ PAGURE_CI_SERVICES = [] # Boolean to turn on project being by default in the user's namespace USER_NAMESPACE = False + +# List of groups whose projects should not be shown on the user's info page +# unless the user has direct access to it. +EXCLUDE_GROUP_INDEX = [] diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index dd0c511..c5fac38 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -1685,7 +1685,8 @@ def fork_project(session, user, repo, gitfolder, def search_projects( session, username=None, fork=None, tags=None, namespace=None, pattern=None, - start=None, limit=None, count=False, sort=None): + start=None, limit=None, count=False, sort=None, + exclude_groups=None): '''List existing projects ''' projects = session.query( @@ -1736,6 +1737,16 @@ def search_projects( ) ) + # Exclude projects that the user has accessed via a group that we + # do not want to include + if exclude_groups: + sub_q3 = sub_q3.filter( + model.PagureGroup.group_name.notin_(exclude_groups) + ) + sub_q4 = sub_q4.filter( + model.PagureGroup.group_name.notin_(exclude_groups) + ) + projects = projects.union(sub_q2).union(sub_q3).union(sub_q4) if fork is not None: diff --git a/pagure/ui/app.py b/pagure/ui/app.py index 302e70b..a7b0920 100644 --- a/pagure/ui/app.py +++ b/pagure/ui/app.py @@ -95,6 +95,7 @@ def index_auth(): repos = pagure.lib.search_projects( SESSION, username=flask.g.fas_user.username, + exclude_groups=APP.config.get('EXCLUDE_GROUP_INDEX'), fork=False) repos_length = pagure.lib.search_projects( SESSION, @@ -298,6 +299,7 @@ def view_user(username): SESSION, username=username, fork=False, + exclude_groups=APP.config.get('EXCLUDE_GROUP_INDEX'), start=repo_start, limit=limit) repos_length = pagure.lib.search_projects( diff --git a/tests/test_pagure_exclude_group_index.py b/tests/test_pagure_exclude_group_index.py new file mode 100644 index 0000000..295de5a --- /dev/null +++ b/tests/test_pagure_exclude_group_index.py @@ -0,0 +1,175 @@ +# -*- coding: utf-8 -*- + +""" + (c) 2017 - Copyright Red Hat Inc + + Authors: + Pierre-Yves Chibon + +""" + +__requires__ = ['SQLAlchemy >= 0.8'] +import pkg_resources + +import unittest +import shutil +import sys +import os + +import mock + +sys.path.insert(0, os.path.join(os.path.dirname( + os.path.abspath(__file__)), '..')) + +import pagure.lib +import pagure.lib.model +import tests + +class PagureExcludeGroupIndex(tests.Modeltests): + """ Tests the EXCLUDE_GROUP_INDEX configuration key in pagure """ + + def setUp(self): + """ Set up the environnment, ran before every tests. """ + super(PagureExcludeGroupIndex, self).setUp() + + pagure.APP.config['GIT_FOLDER'] = os.path.join(self.path, 'repos') + tests.create_projects(self.session) + tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True) + + # Create a ``provenpackger`` group: + msg = pagure.lib.add_group( + self.session, + group_name='provenpackager', + display_name='Proven Packagers', + description='Packagers having access to all the repo', + group_type='user', + user='pingou', + is_admin=False, + blacklist=[], + ) + self.session.commit() + self.assertEqual( + msg, 'User `pingou` added to the group `provenpackager`.') + + # Add the `provenpackager` group to the test2 project + project = pagure.lib.get_project(self.session, 'test2') + msg = pagure.lib.add_group_to_project( + session=self.session, + project=project, + new_group='provenpackager', + user='pingou', + ) + self.session.commit() + self.assertEqual(msg, 'Group added') + + def test_defaults_pingou(self): + """ Test which repo pingou has by default. """ + + repos = pagure.lib.search_projects( + self.session, + username='pingou', + fork=False, + ) + + self.assertEqual(len(repos), 3) + for idx, name in enumerate(['test', 'test2', 'test3']): + self.assertEqual(repos[idx].name, name) + + def test_defaults_foo(self): + """ Test which repo foo has by default. """ + + repos = pagure.lib.search_projects( + self.session, + username='foo', + fork=False, + ) + + self.assertEqual(len(repos), 0) + + + def test_add_foo_test(self): + """ Test adding foo to the test project. """ + + group = pagure.lib.search_groups( + self.session, group_name='provenpackager') + self.assertEqual(group.group_name, 'provenpackager') + + # List all foo's project before (ie: there should be none) + repos = pagure.lib.search_projects( + self.session, + username='foo', + fork=False, + ) + + self.assertEqual(len(repos), 0) + + # Adding `foo` to the `provenpackager` group + msg = pagure.lib.add_user_to_group( + self.session, + username='foo', + group=group, + user='pingou', + is_admin=False, + ) + self.assertEqual( + msg, 'User `foo` added to the group `provenpackager`.') + + # Test that foo has now one project, via the provenpackager group + repos = pagure.lib.search_projects( + self.session, + username='foo', + fork=False, + ) + + self.assertEqual(len(repos), 1) + self.assertEqual(repos[0].name, 'test2') + + def test_excluding_provenpackager(self): + """ Test retrieving user's repo with a group excluded. """ + + # Add `foo` to `provenpackager` + group = pagure.lib.search_groups( + self.session, group_name='provenpackager') + self.assertEqual(group.group_name, 'provenpackager') + + msg = pagure.lib.add_user_to_group( + self.session, + username='foo', + group=group, + user='pingou', + is_admin=False, + ) + self.assertEqual( + msg, 'User `foo` added to the group `provenpackager`.') + + # Get foo's project outside of proven packager + repos = pagure.lib.search_projects( + self.session, + username='foo', + exclude_groups=['provenpackager'], + fork=False, + ) + + self.assertEqual(len(repos), 0) + + # Get pingou's project outside of proven packager (nothing changes) + repos = pagure.lib.search_projects( + self.session, + username='pingou', + exclude_groups=['provenpackager'], + fork=False, + ) + repos2 = pagure.lib.search_projects( + self.session, + username='pingou', + fork=False, + ) + + self.assertEqual(repos, repos2) + self.assertEqual(len(repos), 3) + for idx, name in enumerate(['test', 'test2', 'test3']): + self.assertEqual(repos[idx].name, name) + + +if __name__ == '__main__': + unittest.main(verbosity=2)