diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py
index ee260ba..5d0d3da 100644
--- a/pagure/lib/__init__.py
+++ b/pagure/lib/__init__.py
@@ -2184,7 +2184,6 @@ def search_projects(
model.ProjectGroup.access == 'admin',
model.ProjectGroup.access == 'commit',
)
-
)
)
@@ -2207,29 +2206,87 @@ def search_projects(
# No filtering is done if private == username i.e if the owner of the
# project is viewing the project
elif isinstance(private, six.string_types) and private != username:
- # if we use the sqlalchemy.or_ in projects.filter, it will
- # fail to find any projects assuming there are no rows in
- # the ProjectUser table due to the way sqlalchemy creates
- # nested selects from conditions; therefore we create the
- # subquery explicitly on our own and do it right
- subquery = session.query(
+ # All the public repo
+ subquery0 = session.query(
sqlalchemy.distinct(model.Project.id)
- ).outerjoin(
- model.ProjectUser
- ).outerjoin(
- model.User
).filter(
- sqlalchemy.or_(
- model.Project.private == False, # noqa: E712
- sqlalchemy.and_(
- model.User.user == private,
- model.Project.private == True,
+ model.Project.private == False, # noqa: E712
+ )
+ sub_q1 = session.query(
+ sqlalchemy.distinct(model.Project.id)
+ ).filter(
+ sqlalchemy.and_(
+ model.Project.private == True, # noqa: E712
+ model.User.id == model.Project.user_id,
+ model.User.user == private,
+ )
+ )
+ sub_q2 = session.query(
+ model.Project.id
+ ).filter(
+ # User got admin or commit right
+ sqlalchemy.and_(
+ model.Project.private == True, # noqa: E712
+ model.User.user == private,
+ model.User.id == model.ProjectUser.user_id,
+ model.ProjectUser.project_id == model.Project.id,
+ sqlalchemy.or_(
+ model.ProjectUser.access == 'admin',
+ model.ProjectUser.access == 'commit',
+ )
+ )
+ )
+ sub_q3 = session.query(
+ model.Project.id
+ ).filter(
+ # User created a group that has admin or commit right
+ sqlalchemy.and_(
+ model.Project.private == True, # noqa: E712
+ model.User.user == private,
+ model.PagureGroup.user_id == model.User.id,
+ model.PagureGroup.group_type == 'user',
+ model.PagureGroup.id == model.ProjectGroup.group_id,
+ model.Project.id == model.ProjectGroup.project_id,
+ sqlalchemy.or_(
+ model.ProjectGroup.access == 'admin',
+ model.ProjectGroup.access == 'commit',
+ )
+ )
+ )
+ sub_q4 = session.query(
+ model.Project.id
+ ).filter(
+ # User is part of a group that has admin or commit right
+ sqlalchemy.and_(
+ model.Project.private == True, # noqa: E712
+ model.User.user == private,
+ model.PagureUserGroup.user_id == model.User.id,
+ model.PagureUserGroup.group_id == model.PagureGroup.id,
+ model.PagureGroup.group_type == 'user',
+ model.PagureGroup.id == model.ProjectGroup.group_id,
+ model.Project.id == model.ProjectGroup.project_id,
+ sqlalchemy.or_(
+ model.ProjectGroup.access == 'admin',
+ model.ProjectGroup.access == 'commit',
)
)
)
+ # 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.filter(
- model.Project.id.in_(subquery)
+ model.Project.id.in_(
+ subquery0.union(sub_q1).union(sub_q2).union(sub_q3).union(
+ sub_q4)
+ )
)
if fork is not None:
diff --git a/pagure/templates/_render_repo.html b/pagure/templates/_render_repo.html
index 3efd66c..91a35e0 100644
--- a/pagure/templates/_render_repo.html
+++ b/pagure/templates/_render_repo.html
@@ -37,6 +37,9 @@
{{ repo.namespace + '/' if repo.namespace }}{{ repo.name }}
+ {% if repo.private %}
+
+ {% endif %}
@@ -258,7 +261,7 @@
{% endif %}
{{ repo.fullname }}
-
+
{% if repo.description %}
diff --git a/pagure/ui/app.py b/pagure/ui/app.py
index 1bd5e60..e2b729f 100644
--- a/pagure/ui/app.py
+++ b/pagure/ui/app.py
@@ -87,20 +87,26 @@ def index():
limit = pagure_config['ITEM_PER_PAGE']
start = limit * (page - 1)
+ private = None
+ if authenticated():
+ private = flask.g.fas_user.username
+
repos = pagure.lib.search_projects(
flask.g.session,
fork=False,
start=start,
limit=limit,
- sort=sorting)
+ sort=sorting,
+ private=private,
+ )
num_repos = pagure.lib.search_projects(
flask.g.session,
fork=False,
+ private=private,
count=True)
total_page = int(ceil(num_repos / float(limit)) if num_repos > 0 else 1)
-
return flask.render_template(
'index.html',
select="projects",
diff --git a/tests/test_pagure_flask_ui_app_browse.py b/tests/test_pagure_flask_ui_app_browse.py
new file mode 100644
index 0000000..10072bd
--- /dev/null
+++ b/tests/test_pagure_flask_ui_app_browse.py
@@ -0,0 +1,539 @@
+# -*- coding: utf-8 -*-
+
+"""
+ (c) 2018 - Copyright Red Hat Inc
+
+ Authors:
+ Pierre-Yves Chibon
+
+"""
+
+from __future__ import unicode_literals
+
+__requires__ = ['SQLAlchemy >= 0.8']
+import pkg_resources
+
+import unittest
+import sys
+import os
+
+from mock import patch, MagicMock
+
+sys.path.insert(0, os.path.join(os.path.dirname(
+ os.path.abspath(__file__)), '..'))
+
+import pagure.lib
+import tests
+
+
+class PagureFlaskAppBrowsetests(tests.Modeltests):
+ """ Tests for the browse pages of flask app controller of pagure """
+
+ def setUp(self):
+ """ Set up the environnment, ran before every tests. """
+ super(PagureFlaskAppBrowsetests, self).setUp()
+
+ tests.create_projects(self.session)
+
+ # Add a 3rd project with a long description
+ item = pagure.lib.model.Project(
+ user_id=2, # foo
+ name='test3',
+ description='test project #3 with a very long description',
+ hook_token='aaabbbeeefff',
+ private=True,
+ )
+ self.session.add(item)
+ self.session.commit()
+
+ @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
+ def test_browse_project_logged_in_private_project(self):
+ """ Test the browse project endpoint when logged in with a private
+ project. """
+
+ user = tests.FakeUser(username='foo')
+ with tests.user_set(self.app.application, user):
+ output = self.app.get('/browse/projects/')
+ self.assertEqual(output.status_code, 200)
+ output_text = output.get_data(as_text=True)
+ self.assertIn(
+ 'Home - Pagure\n',
+ output_text)
+ self.assertIn(
+ 'All Projects '
+ '4
',
+ output_text)
+ self.assertIn(
+ '',
+ output_text)
+ self.assertEqual(output_text.count('title="Private project"'), 1)
+
+ @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
+ def test_browse_project_unauth_private_project(self):
+ """ Test the browse project endpoint when logged out with a private
+ project. """
+
+ output = self.app.get('/browse/projects/')
+ self.assertEqual(output.status_code, 200)
+ output_text = output.get_data(as_text=True)
+ self.assertIn(
+ 'Home - Pagure\n',
+ output_text)
+ self.assertIn(
+ 'All Projects '
+ '3
',
+ output_text)
+ self.assertNotIn(
+ '',
+ output_text)
+ self.assertEqual(output_text.count('title="Private project"'), 0)
+
+ @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
+ def test_browse_project_logged_in_no_access_private_project(self):
+ """ Test the browse project endpoint when logged in as an user that
+ has no access to the private project. """
+
+ user = tests.FakeUser(username='pingou')
+ with tests.user_set(self.app.application, user):
+ output = self.app.get('/browse/projects/')
+ self.assertEqual(output.status_code, 200)
+ output_text = output.get_data(as_text=True)
+ self.assertIn(
+ 'Home - Pagure\n',
+ output_text)
+ self.assertIn(
+ 'All Projects '
+ '3
',
+ output_text)
+ self.assertNotIn(
+ '',
+ output_text)
+ self.assertEqual(output_text.count('title="Private project"'), 0)
+
+ @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
+ def test_browse_project_logged_in_ticket_private_project(self):
+ """ Test the browse project endpoint when logged in as an user that
+ has no access to the private project. """
+
+ # Add user 'pingou' with ticket access on repo
+ repo = pagure.lib._get_project(self.session, 'test3')
+ msg = pagure.lib.add_user_to_project(
+ self.session,
+ repo,
+ new_user='pingou',
+ user='foo',
+ access='ticket',
+ )
+ self.assertEqual(msg, 'User added')
+ self.session.commit()
+
+ # Ticket access level isn't sufficient to access private projects
+ user = tests.FakeUser(username='pingou')
+ with tests.user_set(self.app.application, user):
+ output = self.app.get('/browse/projects/')
+ self.assertEqual(output.status_code, 200)
+ output_text = output.get_data(as_text=True)
+ self.assertIn(
+ 'Home - Pagure\n',
+ output_text)
+ self.assertIn(
+ 'All Projects '
+ '3
',
+ output_text)
+ self.assertNotIn(
+ '',
+ output_text)
+ self.assertEqual(output_text.count('title="Private project"'), 0)
+
+ @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
+ def test_browse_project_logged_in_commit_private_project(self):
+ """ Test the browse project endpoint when logged in as an user that
+ has no access to the private project. """
+
+ # Add user 'pingou' with commit access on repo
+ repo = pagure.lib._get_project(self.session, 'test3')
+ msg = pagure.lib.add_user_to_project(
+ self.session,
+ repo,
+ new_user='pingou',
+ user='foo',
+ access='commit',
+ )
+ self.assertEqual(msg, 'User added')
+ self.session.commit()
+
+ user = tests.FakeUser(username='pingou')
+ with tests.user_set(self.app.application, user):
+ output = self.app.get('/browse/projects/')
+ self.assertEqual(output.status_code, 200)
+ output_text = output.get_data(as_text=True)
+ self.assertIn(
+ 'Home - Pagure\n',
+ output_text)
+ self.assertIn(
+ 'All Projects '
+ '4
',
+ output_text)
+ self.assertIn(
+ '',
+ output_text)
+ self.assertEqual(output_text.count('title="Private project"'), 1)
+
+ @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
+ def test_browse_project_logged_in_admin_private_project(self):
+ """ Test the browse project endpoint when logged in as an user that
+ has no access to the private project. """
+
+ # Add user 'pingou' with admin access on repo
+ repo = pagure.lib._get_project(self.session, 'test3')
+ msg = pagure.lib.add_user_to_project(
+ self.session,
+ repo,
+ new_user='pingou',
+ user='foo',
+ access='admin',
+ )
+ self.assertEqual(msg, 'User added')
+ self.session.commit()
+
+ user = tests.FakeUser(username='pingou')
+ with tests.user_set(self.app.application, user):
+ output = self.app.get('/browse/projects/')
+ self.assertEqual(output.status_code, 200)
+ output_text = output.get_data(as_text=True)
+ self.assertIn(
+ 'Home - Pagure\n',
+ output_text)
+ self.assertIn(
+ 'All Projects '
+ '4
',
+ output_text)
+ self.assertIn(
+ '',
+ output_text)
+ self.assertEqual(output_text.count('title="Private project"'), 1)
+
+class PagureFlaskAppBrowseGroupAdmintests(tests.Modeltests):
+ """ Tests for the browse pages of flask app controller of pagure """
+
+ def setUp(self):
+ """ Set up the environnment, ran before every tests. """
+ super(PagureFlaskAppBrowseGroupAdmintests, self).setUp()
+
+ tests.create_projects(self.session)
+
+ # Add a 3rd project with a long description
+ item = pagure.lib.model.Project(
+ user_id=2, # foo
+ name='test3',
+ description='test project #3 with a very long description',
+ hook_token='aaabbbeeefff',
+ private=True,
+ )
+ self.session.add(item)
+ self.session.commit()
+
+ # Create a group
+ msg = pagure.lib.add_group(
+ self.session,
+ group_name='JL',
+ display_name='Justice League',
+ description='Nope, it\'s not JLA anymore',
+ group_type='user',
+ user='foo',
+ is_admin=False,
+ blacklist=pagure.config.config.get('BLACKLISTED_PROJECTS')
+ )
+
+ self.assertEqual(msg, 'User `foo` added to the group `JL`.')
+
+ # Add the group to project we just created, test3
+ # Add it with admin ACL
+ project = pagure.lib._get_project(self.session, 'test3')
+ msg = pagure.lib.add_group_to_project(
+ self.session,
+ project=project,
+ new_group='JL',
+ user='foo',
+ access='admin'
+ )
+ self.session.commit()
+ self.assertEqual(msg, 'Group added')
+
+ @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
+ def test_browse_project_user_not_in_group(self):
+ """ Test the browse project endpoint when logged in as an user that
+ has no access to the private project via a group as admin. """
+
+ user = tests.FakeUser(username='pingou')
+ with tests.user_set(self.app.application, user):
+ output = self.app.get('/browse/projects/')
+ self.assertEqual(output.status_code, 200)
+ output_text = output.get_data(as_text=True)
+ self.assertIn(
+ 'Home - Pagure\n',
+ output_text)
+ self.assertIn(
+ 'All Projects '
+ '3
',
+ output_text)
+ self.assertNotIn(
+ '',
+ output_text)
+ self.assertEqual(output_text.count('title="Private project"'), 0)
+
+ @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
+ def test_browse_project_user_in_group(self):
+ """ Test the browse project endpoint when logged in as an user that
+ has no access to the private project via a group as admin. """
+ group = pagure.lib.search_groups(
+ self.session, group_name='JL')
+
+ pagure.lib.add_user_to_group(
+ session=self.session,
+ username='pingou',
+ group=group,
+ user='foo',
+ is_admin=False,
+ )
+ self.session.commit()
+
+ user = tests.FakeUser(username='pingou')
+ with tests.user_set(self.app.application, user):
+ output = self.app.get('/browse/projects/')
+ self.assertEqual(output.status_code, 200)
+ output_text = output.get_data(as_text=True)
+ self.assertIn(
+ 'Home - Pagure\n',
+ output_text)
+ self.assertIn(
+ 'All Projects '
+ '4
',
+ output_text)
+ self.assertIn(
+ '',
+ output_text)
+ self.assertEqual(output_text.count('title="Private project"'), 1)
+
+
+class PagureFlaskAppBrowseGroupCommittests(tests.Modeltests):
+ """ Tests for the browse pages of flask app controller of pagure """
+
+ def setUp(self):
+ """ Set up the environnment, ran before every tests. """
+ super(PagureFlaskAppBrowseGroupCommittests, self).setUp()
+
+ tests.create_projects(self.session)
+
+ # Add a 3rd project with a long description
+ item = pagure.lib.model.Project(
+ user_id=2, # foo
+ name='test3',
+ description='test project #3 with a very long description',
+ hook_token='aaabbbeeefff',
+ private=True,
+ )
+ self.session.add(item)
+ self.session.commit()
+
+ # Create a group
+ msg = pagure.lib.add_group(
+ self.session,
+ group_name='JL',
+ display_name='Justice League',
+ description='Nope, it\'s not JLA anymore',
+ group_type='user',
+ user='foo',
+ is_admin=False,
+ blacklist=pagure.config.config.get('BLACKLISTED_PROJECTS')
+ )
+
+ self.assertEqual(msg, 'User `foo` added to the group `JL`.')
+
+ # Add the group to project we just created, test3
+ # Add it with commit ACL
+ project = pagure.lib._get_project(self.session, 'test3')
+ msg = pagure.lib.add_group_to_project(
+ self.session,
+ project=project,
+ new_group='JL',
+ user='foo',
+ access='commit'
+ )
+ self.session.commit()
+ self.assertEqual(msg, 'Group added')
+
+ @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
+ def test_browse_project_user_not_in_group(self):
+ """ Test the browse project endpoint when logged in as an user that
+ has no access to the private project via a group as admin. """
+
+ user = tests.FakeUser(username='pingou')
+ with tests.user_set(self.app.application, user):
+ output = self.app.get('/browse/projects/')
+ self.assertEqual(output.status_code, 200)
+ output_text = output.get_data(as_text=True)
+ self.assertIn(
+ 'Home - Pagure\n',
+ output_text)
+ self.assertIn(
+ 'All Projects '
+ '3
',
+ output_text)
+ self.assertNotIn(
+ '',
+ output_text)
+ self.assertEqual(output_text.count('title="Private project"'), 0)
+
+ @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
+ def test_browse_project_user_in_group(self):
+ """ Test the browse project endpoint when logged in as an user that
+ has no access to the private project via a group as admin. """
+ group = pagure.lib.search_groups(
+ self.session, group_name='JL')
+
+ pagure.lib.add_user_to_group(
+ session=self.session,
+ username='pingou',
+ group=group,
+ user='foo',
+ is_admin=False,
+ )
+ self.session.commit()
+
+ user = tests.FakeUser(username='pingou')
+ with tests.user_set(self.app.application, user):
+ output = self.app.get('/browse/projects/')
+ self.assertEqual(output.status_code, 200)
+ output_text = output.get_data(as_text=True)
+ self.assertIn(
+ 'Home - Pagure\n',
+ output_text)
+ self.assertIn(
+ 'All Projects '
+ '4
',
+ output_text)
+ self.assertIn(
+ '',
+ output_text)
+ self.assertEqual(output_text.count('title="Private project"'), 1)
+
+
+class PagureFlaskAppBrowseGroupTickettests(tests.Modeltests):
+ """ Tests for the browse pages of flask app controller of pagure """
+
+ def setUp(self):
+ """ Set up the environnment, ran before every tests. """
+ super(PagureFlaskAppBrowseGroupTickettests, self).setUp()
+
+ tests.create_projects(self.session)
+
+ # Add a 3rd project with a long description
+ item = pagure.lib.model.Project(
+ user_id=2, # foo
+ name='test3',
+ description='test project #3 with a very long description',
+ hook_token='aaabbbeeefff',
+ private=True,
+ )
+ self.session.add(item)
+ self.session.commit()
+
+ # Create a group
+ msg = pagure.lib.add_group(
+ self.session,
+ group_name='JL',
+ display_name='Justice League',
+ description='Nope, it\'s not JLA anymore',
+ group_type='user',
+ user='foo',
+ is_admin=False,
+ blacklist=pagure.config.config.get('BLACKLISTED_PROJECTS')
+ )
+
+ self.assertEqual(msg, 'User `foo` added to the group `JL`.')
+
+ # Add the group to project we just created, test3
+ # Add it with ticket ACL
+ project = pagure.lib._get_project(self.session, 'test3')
+ msg = pagure.lib.add_group_to_project(
+ self.session,
+ project=project,
+ new_group='JL',
+ user='foo',
+ access='ticket'
+ )
+ self.session.commit()
+ self.assertEqual(msg, 'Group added')
+
+ @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
+ def test_browse_project_user_not_in_group(self):
+ """ Test the browse project endpoint when logged in as an user that
+ has no access to the private project via a group as admin. """
+
+ user = tests.FakeUser(username='pingou')
+ with tests.user_set(self.app.application, user):
+ output = self.app.get('/browse/projects/')
+ self.assertEqual(output.status_code, 200)
+ output_text = output.get_data(as_text=True)
+ self.assertIn(
+ 'Home - Pagure\n',
+ output_text)
+ self.assertIn(
+ 'All Projects '
+ '3
',
+ output_text)
+ self.assertNotIn(
+ '',
+ output_text)
+ self.assertEqual(output_text.count('title="Private project"'), 0)
+
+ @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
+ def test_browse_project_user_in_group(self):
+ """ Test the browse project endpoint when logged in as an user that
+ has no access to the private project via a group as admin. """
+ group = pagure.lib.search_groups(
+ self.session, group_name='JL')
+
+ pagure.lib.add_user_to_group(
+ session=self.session,
+ username='pingou',
+ group=group,
+ user='foo',
+ is_admin=False,
+ )
+ self.session.commit()
+
+ # Ticket ACL isn't enough to grant you access
+ user = tests.FakeUser(username='pingou')
+ with tests.user_set(self.app.application, user):
+ output = self.app.get('/browse/projects/')
+ self.assertEqual(output.status_code, 200)
+ output_text = output.get_data(as_text=True)
+ self.assertIn(
+ 'Home - Pagure\n',
+ output_text)
+ self.assertIn(
+ 'All Projects '
+ '3
',
+ output_text)
+ self.assertNotIn(
+ '',
+ output_text)
+ self.assertEqual(output_text.count('title="Private project"'), 0)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/tests/test_pagure_flask_ui_app_index.py b/tests/test_pagure_flask_ui_app_index.py
index 03734e1..bf8040d 100644
--- a/tests/test_pagure_flask_ui_app_index.py
+++ b/tests/test_pagure_flask_ui_app_index.py
@@ -497,6 +497,43 @@ class PagureFlaskAppIndextests(tests.Modeltests):
r'foo/test3(\s*<[^>]+?>\s*)*?forked from a deleted repository'
)
+ @patch.dict('pagure.config.config', {'PRIVATE_PROJECTS': True})
+ def test_index_logged_in_private_project(self):
+ """ Test the index endpoint when logged in with a private project. """
+ tests.create_projects(self.session)
+
+ # Add a 3rd project with a long description
+ item = pagure.lib.model.Project(
+ user_id=2, # foo
+ name='test3',
+ description='test project #3 with a very long description',
+ hook_token='aaabbbeeefff',
+ private=True,
+ )
+ self.session.add(item)
+ self.session.commit()
+
+ user = tests.FakeUser(username='foo')
+ with tests.user_set(self.app.application, user):
+ output = self.app.get('/')
+ self.assertEqual(output.status_code, 200)
+ output_text = output.get_data(as_text=True)
+ self.assertIn(
+ 'Projects 1',
+ output_text)
+ self.assertIn(
+ '',
+ output_text)
+ self.assertEqual(output_text.count('title="Private project"'), 1)
+ self.assertIn(
+ 'Forks 0',
+ output_text)
+ self.assertEqual(
+ output_text.count('No group found
'), 1)
+ self.assertEqual(
+ output_text.count('