From 67f81f18830188e010cf3edc845f09be7d959d9d Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jul 31 2020 18:47:49 +0000 Subject: Add a collaborator level to projects. The collaborators are collaborators that are only granted limited access to the project (for example, one or a few branches in the repository). They are also provided ticket access. They are not granted full commit on the entire project. Signed-off-by: Pierre-Yves Chibon --- diff --git a/alembic/versions/2b39a728a38f_add_branch_info_to_projects_groups.py b/alembic/versions/2b39a728a38f_add_branch_info_to_projects_groups.py new file mode 100644 index 0000000..7adbcd9 --- /dev/null +++ b/alembic/versions/2b39a728a38f_add_branch_info_to_projects_groups.py @@ -0,0 +1,30 @@ +"""Add branch info to projects_groups + +Revision ID: 2b39a728a38f +Revises: 318a4793b360 +Create Date: 2020-03-26 21:50:45.899760 + +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '2b39a728a38f' +down_revision = '318a4793b360' + + +def upgrade(): + ''' Add the column branches to the table projects_groups. + ''' + op.add_column( + 'projects_groups', + sa.Column('branches', sa.Text, nullable=True) + ) + + +def downgrade(): + ''' Drop the column branches from the table projects_groups. + ''' + op.drop_column('projects_groups', 'branches') diff --git a/alembic/versions/318a4793b360_add_branch_info_to_project_user.py b/alembic/versions/318a4793b360_add_branch_info_to_project_user.py new file mode 100644 index 0000000..2b61738 --- /dev/null +++ b/alembic/versions/318a4793b360_add_branch_info_to_project_user.py @@ -0,0 +1,30 @@ +"""Add branch info to user_projects + +Revision ID: 318a4793b360 +Revises: 060b20d6d6e6 +Create Date: 2020-03-26 21:49:17.632967 + +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '318a4793b360' +down_revision = '060b20d6d6e6' + + +def upgrade(): + ''' Add the column branches to the table user_projects. + ''' + op.add_column( + 'user_projects', + sa.Column('branches', sa.Text, nullable=True) + ) + + +def downgrade(): + ''' Drop the column branches from the table user_projects. + ''' + op.drop_column('user_projects', 'branches') diff --git a/pagure/flask_app.py b/pagure/flask_app.py index ceefd5b..efeb564 100644 --- a/pagure/flask_app.py +++ b/pagure/flask_app.py @@ -395,6 +395,11 @@ def set_request(): flask.g.repo_obj = pygit2.Repository(flask.g.reponame) flask.g.repo_admin = pagure.utils.is_repo_admin(flask.g.repo) flask.g.repo_committer = pagure.utils.is_repo_committer(flask.g.repo) + if flask.g.authenticated and not flask.g.repo_committer: + flask.g.repo_committer = flask.g.fas_user.username in [ + u.user.username for u in flask.g.repo.collaborators + ] + flask.g.repo_user = pagure.utils.is_repo_user(flask.g.repo) flask.g.branches = sorted(flask.g.repo_obj.listall_branches()) diff --git a/pagure/forms.py b/pagure/forms.py index 83e6d53..366d8ae 100644 --- a/pagure/forms.py +++ b/pagure/forms.py @@ -632,6 +632,10 @@ class AddUserForm(PagureForm): 'Access Level *', [wtforms.validators.DataRequired()], ) + branches = wtforms.StringField( + 'Git branches *', + [wtforms.validators.Optional()], + ) class AddUserToGroupForm(PagureForm): @@ -666,6 +670,10 @@ class AddGroupForm(PagureForm): 'Access Level *', [wtforms.validators.DataRequired()], ) + branches = wtforms.StringField( + 'Git branches *', + [wtforms.validators.Optional()], + ) class ConfirmationForm(PagureForm): diff --git a/pagure/internal/__init__.py b/pagure/internal/__init__.py index 96f1a81..9a65e1e 100644 --- a/pagure/internal/__init__.py +++ b/pagure/internal/__init__.py @@ -126,7 +126,7 @@ def lookup_ssh_key(): @PV.route("/ssh/checkaccess/", methods=["POST"]) @internal_access_only def check_ssh_access(): - """ Determines whether a user has any access to the requested repo. """ + """ Determines whether a user has read access to the requested repo. """ gitdir = flask.request.form["gitdir"] remoteuser = flask.request.form["username"] _auth_log.info( @@ -192,8 +192,9 @@ def check_ssh_access(): ) return flask.jsonify({"access": False}) - _log.info("Access granted to %s on: %s" % (remoteuser, project.fullname)) - + _log.info( + "Read access granted to %s on: %s" % (remoteuser, project.fullname) + ) return flask.jsonify( { "access": True, diff --git a/pagure/lib/git_auth.py b/pagure/lib/git_auth.py index 92bb4ea..b354a51 100644 --- a/pagure/lib/git_auth.py +++ b/pagure/lib/git_auth.py @@ -27,7 +27,7 @@ import pagure.lib.model_base import pagure.lib.query from pagure.config import config as pagure_config from pagure.lib import model -from pagure.utils import is_repo_committer, lookup_deploykey +from pagure.utils import is_repo_collaborator, lookup_deploykey # logging.config.dictConfig(pagure_config.get('LOGGING') or {'version': 1}) @@ -901,7 +901,9 @@ class PagureGitAuth(GitAuthHelper): return False # Determine whether the current user is allowed to push - is_committer = is_repo_committer(project, username, session) + is_committer = is_repo_collaborator( + project, refname, username, session + ) deploykey = lookup_deploykey(project, username) if deploykey is not None: self.info("Deploykey used. Push access: %s" % deploykey.pushaccess) diff --git a/pagure/lib/model.py b/pagure/lib/model.py index 9d366e3..9c23143 100644 --- a/pagure/lib/model.py +++ b/pagure/lib/model.py @@ -142,7 +142,7 @@ def create_default_status(session, acls=None): session.rollback() _log.debug("ACL %s could not be added", acl) - for access in ["ticket", "commit", "admin"]: + for access in ["ticket", "collaborator", "commit", "admin"]: access_obj = AccessLevels(access=access) session.add(access_obj) try: @@ -443,6 +443,13 @@ class Project(BASE): viewonly=True, ) + collaborators = relation( + "ProjectUser", + primaryjoin="and_(projects.c.id==user_projects.c.project_id,\ + user_projects.c.access=='collaborator')", + viewonly=True, + ) + groups = relation( "PagureGroup", secondary="projects_groups", @@ -479,6 +486,13 @@ class Project(BASE): viewonly=True, ) + collaborator_groups = relation( + "ProjectGroup", + primaryjoin="and_(projects.c.id==projects_groups.c.project_id,\ + projects_groups.c.access=='collaborator')", + viewonly=True, + ) + def __repr__(self): return ( "Project(%s, name:%s, namespace:%s, url:%s, is_fork:%s, " @@ -905,7 +919,7 @@ class Project(BASE): :type combine: boolean """ - if access not in ["admin", "commit", "ticket"]: + if access not in ["admin", "commit", "collaborator", "ticket"]: raise pagure.exceptions.AccessLevelNotFound( "The access level does not exist" ) @@ -915,6 +929,8 @@ class Project(BASE): return self.admins elif access == "commit": return self.committers + elif access == "collaborator": + return [u.user for u in self.collaborators] elif access == "ticket": return self.users else: @@ -924,11 +940,20 @@ class Project(BASE): committers = set(self.committers) admins = set(self.admins) return list(committers - admins) - elif access == "ticket": + elif access == "collaborator": + admins = set(self.admins) committers = set(self.committers) + return list( + set([u.user for u in self.collaborators]) + - committers + - admins + ) + elif access == "ticket": admins = set(self.admins) + committers = set(self.committers) + collaborators = set([u.user for u in self.collaborators]) users = set(self.users) - return list(users - committers - admins) + return list(users - collaborators - committers - admins) def get_project_groups(self, access, combine=True): """ Returns the list of groups of the project according @@ -951,7 +976,7 @@ class Project(BASE): :type combine: boolean """ - if access not in ["admin", "commit", "ticket"]: + if access not in ["admin", "commit", "collaborator", "ticket"]: raise pagure.exceptions.AccessLevelNotFound( "The access level does not exist" ) @@ -961,6 +986,8 @@ class Project(BASE): return self.admin_groups elif access == "commit": return self.committer_groups + elif access == "collaborator": + return self.collaborator_groups elif access == "ticket": return self.groups else: @@ -970,11 +997,18 @@ class Project(BASE): committers = set(self.committer_groups) admins = set(self.admin_groups) return list(committers - admins) + elif access == "collaborator": + committers = set(self.committer_groups) + admins = set(self.admin_groups) + return list( + set(self.collaborator_groups) - committers - admins + ) elif access == "ticket": committers = set(self.committer_groups) admins = set(self.admin_groups) + collaborators = set(self.collaborator_groups) groups = set(self.groups) - return list(groups - committers - admins) + return list(groups - collaborators - committers - admins) @property def access_users(self): @@ -989,6 +1023,9 @@ class Project(BASE): self.get_project_users(access="commit", combine=False), key=lambda u: u.user, ), + "collaborator": sorted( + self.get_project_users(access="collaborator", combine=False) + ), "ticket": sorted( self.get_project_users(access="ticket", combine=False), key=lambda u: u.user, @@ -1028,6 +1065,9 @@ class Project(BASE): self.get_project_groups(access="commit", combine=False), key=lambda x: x.group_name, ), + "collaborator": sorted( + self.get_project_groups(access="collaborator", combine=False) + ), "ticket": sorted( self.get_project_groups(access="ticket", combine=False), key=lambda x: x.group_name, @@ -1171,6 +1211,7 @@ class ProjectUser(BASE): ), nullable=False, ) + branches = sa.Column(sa.Text, nullable=True,) project = relation( "Project", @@ -2707,6 +2748,7 @@ class ProjectGroup(BASE): ), nullable=False, ) + branches = sa.Column(sa.Text, nullable=True,) project = relation( "Project", diff --git a/pagure/lib/query.py b/pagure/lib/query.py index 48a72bf..8ee4df6 100644 --- a/pagure/lib/query.py +++ b/pagure/lib/query.py @@ -1098,7 +1098,13 @@ def add_sshkey_to_project_or_user( def add_user_to_project( - session, project, new_user, user, access="admin", required_groups=None + session, + project, + new_user, + user, + access="admin", + branches=None, + required_groups=None, ): """ Add a specified user to a specified project with a specified access """ @@ -1127,15 +1133,20 @@ def add_user_to_project( ) users.add(project.user.user) - if new_user in users: + if new_user in users and access != "collaborator": raise pagure.exceptions.PagureException( "This user is already listed on this project with the same access" ) + # Reset the branches to None if the user isn't a collaborator + if access != "collaborator": + branches = None + # user has some access on project, so update to new access if new_user_obj in project.users: access_obj = get_obj_access(session, project, new_user_obj) access_obj.access = access + access_obj.branches = branches project.date_modified = datetime.datetime.utcnow() update_read_only_mode(session, project, read_only=True) session.add(access_obj) @@ -1149,6 +1160,7 @@ def add_user_to_project( project=project.to_json(public=True), new_user=new_user_obj.username, new_access=access, + new_branches=branches, agent=user_obj.username, ), ) @@ -1156,7 +1168,10 @@ def add_user_to_project( return "User access updated" project_user = model.ProjectUser( - project_id=project.id, user_id=new_user_obj.id, access=access + project_id=project.id, + user_id=new_user_obj.id, + access=access, + branches=branches, ) project.date_modified = datetime.datetime.utcnow() session.add(project_user) @@ -1173,6 +1188,7 @@ def add_user_to_project( project=project.to_json(public=True), new_user=new_user_obj.username, access=access, + branches=branches, agent=user_obj.username, ), ) @@ -1186,6 +1202,7 @@ def add_group_to_project( new_group, user, access="admin", + branches=None, create=False, is_admin=False, ): @@ -1228,15 +1245,20 @@ def add_group_to_project( ] ) - if new_group in groups: + if new_group in groups and access != "collaborator": raise pagure.exceptions.PagureException( "This group already has this access on this project" ) + # Reset the branches to None if the group isn't a collaborator + if access != "collaborator": + branches = None + # the group already has some access, update to new access if group_obj in project.groups: access_obj = get_obj_access(session, project, group_obj) access_obj.access = access + access_obj.branches = branches session.add(access_obj) project.date_modified = datetime.datetime.utcnow() update_read_only_mode(session, project, read_only=True) @@ -1250,6 +1272,7 @@ def add_group_to_project( project=project.to_json(public=True), new_group=group_obj.group_name, new_access=access, + new_branches=branches, agent=user, ), ) @@ -1257,7 +1280,10 @@ def add_group_to_project( return "Group access updated" project_group = model.ProjectGroup( - project_id=project.id, group_id=group_obj.id, access=access + project_id=project.id, + group_id=group_obj.id, + access=access, + branches=branches, ) session.add(project_group) # Make sure we won't have SQLAlchemy error before we continue @@ -1274,6 +1300,7 @@ def add_group_to_project( project=project.to_json(public=True), new_group=group_obj.group_name, access=access, + branches=branches, agent=user, ), ) @@ -2380,6 +2407,7 @@ def search_projects( sqlalchemy.or_( model.ProjectUser.access == "admin", model.ProjectUser.access == "commit", + model.ProjectUser.access == "collaborator", ), ) ) @@ -2394,6 +2422,7 @@ def search_projects( sqlalchemy.or_( model.ProjectGroup.access == "admin", model.ProjectGroup.access == "commit", + model.ProjectGroup.access == "collaborator", ), ) ) @@ -2409,6 +2438,7 @@ def search_projects( sqlalchemy.or_( model.ProjectGroup.access == "admin", model.ProjectGroup.access == "commit", + model.ProjectGroup.access == "collaborator", ), ) ) @@ -2455,6 +2485,7 @@ def search_projects( sqlalchemy.or_( model.ProjectUser.access == "admin", model.ProjectUser.access == "commit", + model.ProjectUser.access == "collaborator", ), ) ) @@ -2470,6 +2501,7 @@ def search_projects( sqlalchemy.or_( model.ProjectGroup.access == "admin", model.ProjectGroup.access == "commit", + model.ProjectGroup.access == "collaborator", ), ) ) @@ -2486,6 +2518,7 @@ def search_projects( sqlalchemy.or_( model.ProjectGroup.access == "admin", model.ProjectGroup.access == "commit", + model.ProjectGroup.access == "collaborator", ), ) ) @@ -2591,7 +2624,7 @@ def list_users_projects( projects = session.query(sqlalchemy.distinct(model.Project.id)) if acls is None: - acls = ["main admin", "admin", "commit", "ticket"] + acls = ["main admin", "admin", "collaborator", "commit", "ticket"] if username is not None: diff --git a/pagure/templates/_access_levels_descriptions.html b/pagure/templates/_access_levels_descriptions.html new file mode 100644 index 0000000..992502e --- /dev/null +++ b/pagure/templates/_access_levels_descriptions.html @@ -0,0 +1,34 @@ +

Access Levels

+

+Ticket: A user or a group with this level of access can only edit metadata + of an issue. This includes changing the status of an issue, adding/removing + tags from them, adding/removing assignees and every other option which can + be accessed when you click "Edit Metadata" button in an issue page. However, + this user can not "create" a new tag or "delete" an existing tag because, + that would involve access to settings page of the project which this user + won't have. It also won't be able to "delete" the issue because, it falls + outside of "Edit Metadata". +

+

+Collaborator: A user or a group with this level of access can do everything what + a user/group with ticket access can do + it can commit to some branches in the project. + These branches are defined here using their name or a pattern and needs to be comma separated.
+ Some examples: +

+

+

+Commit: A user or a group with this level of access can do everything what + a user/group with ticket access can do + it can do everything on the project + which doesn't include access to settings page. It can "Edit Metadata" of an issue + just like a user with ticket access would do, can merge a pull request, can push + to the main repository directly, delete an issue, cancel a pull request etc. +

+

+Admin: The user/group with this access has access to everything on the project. + All the "users" of the project that have been added till now are having this access. + They can change the settings of the project, add/remove users/groups on the project. +

diff --git a/pagure/templates/add_group_project.html b/pagure/templates/add_group_project.html index 0fdd20e..f07ca58 100644 --- a/pagure/templates/add_group_project.html +++ b/pagure/templates/add_group_project.html @@ -33,6 +33,8 @@ {% endfor %} +

@@ -41,29 +43,7 @@ {{ form.csrf_token }}

-

Access Levels

-

- Ticket: A user or a group with this level of access can only edit metadata - of an issue. This includes changing the status of an issue, adding/removing - tags from them, adding/removing assignees and every other option which can - be accessed when you click "Edit Metadata" button in an issue page. However, - this user can not "create" a new tag or "delete" an existing tag because, - that would involve access to settings page of the project which this user - won't have. It also won't be able to "delete" the issue because, it falls - outside of "Edit Metadata". -

-

- Commit: A user or a group with this level of access can do everything what - a user/group with ticket access can do + it can do everything on the project - which doesn't include access to settings page. It can "Edit Metadata" of an issue - just like a user with ticket access would do, can merge a pull request, can push - to the main repository directly, delete an issue, cancel a pull request etc. -

-

- Admin: The user/group with this access has access to everything on the project. - All the "users" of the project that have been added till now are having this access. - They can change the settings of the project, add/remove users/groups on the project. -

+ {% include '_access_levels_descriptions.html' %} @@ -90,7 +70,10 @@ function set_up_group_list(url, query, callback) { ); } + $( document ).ready(function() { + $("#branches").hide(); + var group_to_update = "{{ group_to_update }}"; if (!group_to_update || group_to_update === "None") { $('#group').selectize({ @@ -114,9 +97,24 @@ $( document ).ready(function() { if (group_access !== "None") { $("#" + "{{ group_access.access }}").attr("selected", "selected"); } + $("#branches").val("{{ group_access.branches or ''}}"); $("#card-topic").html("Update group access in {{repo.name}}"); $("#add_update_button").attr("value", "Update"); - } + }; + + if ($("#access").val() == "collaborator") { + $("#branches").show(); + }; + + $("#access").on("change", function() { + var _acc = $("#access"); + if (_acc.val() == "collaborator") { + $("#branches").show(); + } else { + $("#branches").hide(); + } + }); + }); {% endblock %} diff --git a/pagure/templates/add_user.html b/pagure/templates/add_user.html index e5acd4a..78d602f 100644 --- a/pagure/templates/add_user.html +++ b/pagure/templates/add_user.html @@ -31,6 +31,9 @@ {% endfor %} + +

@@ -39,29 +42,7 @@ {{ form.csrf_token }}

-

Access Levels

-

- Ticket: A user or a group with this level of access can only edit metadata - of an issue. This includes changing the status of an issue, adding/removing - tags from them, adding/removing assignees and every other option which can - be accessed when you click "Edit Metadata" button in an issue page. However, - this user can not "create" a new tag or "delete" an existing tag because, - that would involve access to settings page of the project which this user - won't have. It also won't be able to "delete" the issue because, it falls - outside of "Edit Metadata". -

-

- Commit: A user or a group with this level of access can do everything what - a user/group with ticket access can do + it can do everything on the project - which doesn't include access to settings page. It can "Edit Metadata" of an issue - just like a user with ticket access would do, can merge a pull request, can push - to the main repository directly, delete an issue, cancel a pull request etc. -

-

- Admin: The user/group with this access has access to everything on the project. - All the "users" of the project that have been added till now are having this access. - They can change the settings of the project, add/remove users/groups on the project. -

+ {% include '_access_levels_descriptions.html' %} @@ -75,6 +56,8 @@ {% endblock %} diff --git a/pagure/ui/repo.py b/pagure/ui/repo.py index 040b2bc..06e38ac 100644 --- a/pagure/ui/repo.py +++ b/pagure/ui/repo.py @@ -2081,6 +2081,7 @@ def add_user(repo, username=None, namespace=None): new_user=form.user.data, user=flask.g.fas_user.username, access=form.access.data, + branches=form.branches.data, required_groups=pagure_config.get("REQUIRED_GROUPS"), ) flask.g.session.commit() @@ -2241,6 +2242,7 @@ def add_group_project(repo, username=None, namespace=None): new_group=form.group.data, user=flask.g.fas_user.username, access=form.access.data, + branches=form.branches.data, create=pagure_config.get("ENABLE_GROUP_MNGT", False), is_admin=pagure.utils.is_admin(), ) diff --git a/pagure/utils.py b/pagure/utils.py index 2bab9c5..fcf1b6b 100644 --- a/pagure/utils.py +++ b/pagure/utils.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - (c) 2017 - Copyright Red Hat Inc + (c) 2017-2020 - Copyright Red Hat Inc Authors: Pierre-Yves Chibon @@ -11,6 +11,7 @@ from __future__ import unicode_literals, absolute_import import datetime +import fnmatch import logging import logging.config import os @@ -269,6 +270,63 @@ def is_repo_committer(repo_obj, username=None, session=None): return False +def is_repo_collaborator(repo_obj, refname, username=None, session=None): + """ Return whether the user has commit on the specified branch of the + provided repo. """ + committer = is_repo_committer(repo_obj, username=username, session=session) + if committer: + _log.debug("User is a committer") + return committer + + import pagure.lib.query + + if username is None: + if not authenticated(): + return False + if is_admin(): + return True + username = flask.g.fas_user.username + usergroups = set(flask.g.fas_user.groups) + + if not session: + session = flask.g.session + try: + user = pagure.lib.query.get_user(session, username) + usergroups = set(user.groups) + except pagure.exceptions.PagureException: + return False + + # If they are in the list of committers -> maybe + for user in repo_obj.collaborators: + if user.user.username == username: + # if branch is None when the user tries to read, + # so we'll allow that + if refname is None: + return True + # If the branch is specified: the user is trying to write, we'll + # check if they are allowed to + for pattern in user.branches.split(","): + pattern = "refs/heads/{}".format(pattern.strip()) + if fnmatch.fnmatch(refname, pattern): + return True + + # If they are in a group that has commit access -> maybe + for project_group in repo_obj.collaborator_groups: + if project_group.group.group_name in usergroups: + # if branch is None when the user tries to read, + # so we'll allow that + if refname is None: + return True + # If the branch is specified: the user is trying to write, we'll + # check if they are allowed to + for pattern in project_group.branches.split(","): + pattern = "refs/heads/{}".format(pattern.strip()) + if fnmatch.fnmatch(refname, pattern): + return True + + return False + + def is_repo_user(repo_obj, username=None): """ Return whether the user has some access in the provided repo. """ if username: diff --git a/tests/test_pagure_flask.py b/tests/test_pagure_flask.py index 0ad4fd7..82b5dc0 100644 --- a/tests/test_pagure_flask.py +++ b/tests/test_pagure_flask.py @@ -317,6 +317,193 @@ class PagureGetRemoteRepoPath(tests.SimplePagureTest): output = pagure.utils.is_repo_committer(repo) self.assertFalse(output) + def test_is_repo_collaborator_logged_out(self): + """ Test is_repo_committer in pagure when there is no logged in user. + """ + repo = pagure.lib.query._get_project(self.session, "test") + with self.app.application.app_context(): + output = pagure.utils.is_repo_collaborator(repo, "master") + self.assertFalse(output) + + def test_is_repo_collaborator_logged_in(self): + """ Test is_repo_collaborator in pagure with the appropriate user logged + in. """ + repo = pagure.lib.query._get_project(self.session, "test") + + g = munch.Munch() + g.fas_user = tests.FakeUser(username="pingou") + g.authenticated = True + g.session = self.session + with mock.patch("flask.g", g): + output = pagure.utils.is_repo_collaborator( + repo, "refs/heads/master" + ) + self.assertTrue(output) + + def test_is_repo_collaborator_invalid_username(self): + """ Test is_repo_collaborator in pagure with the appropriate user logged + in. """ + repo = pagure.lib.query._get_project(self.session, "test") + + g = munch.Munch() + g.fas_user = tests.FakeUser(username="invalid") + g.authenticated = True + g.session = self.session + with mock.patch("flask.g", g): + output = pagure.utils.is_repo_collaborator( + repo, "refs/heads/master" + ) + self.assertFalse(output) + + @mock.patch.dict("pagure.config.config", {"PAGURE_ADMIN_USERS": ["foo"]}) + def test_is_repo_collaborator_admin_user(self): + """ Test is_repo_collaborator in pagure with the appropriate user logged + in. """ + repo = pagure.lib.query._get_project(self.session, "test") + + g = munch.Munch() + g.fas_user = tests.FakeUser(username="foo") + g.authenticated = True + g.session = self.session + with mock.patch("flask.g", g): + output = pagure.utils.is_repo_collaborator( + repo, "refs/heads/master" + ) + self.assertTrue(output) + + def test_is_repo_collaborator_not_in_project(self): + """ Test is_repo_collaborator in pagure with the appropriate user logged + in. """ + repo = pagure.lib.query._get_project(self.session, "test") + + g = munch.Munch() + g.fas_user = tests.FakeUser(username="foo") + g.authenticated = True + g.session = self.session + with mock.patch("flask.g", g): + output = pagure.utils.is_repo_collaborator( + repo, "refs/heads/master" + ) + self.assertFalse(output) + + def test_is_repo_collaborator_in_project(self): + """ Test is_repo_collaborator in pagure with the appropriate user logged + in. """ + repo = pagure.lib.query._get_project(self.session, "test") + + # Add user foo to project test + msg = pagure.lib.query.add_user_to_project( + self.session, + project=repo, + new_user="foo", + user="pingou", + access="collaborator", + branches="epel*", + ) + self.session.commit() + + g = munch.Munch() + g.fas_user = tests.FakeUser(username="foo") + g.authenticated = True + g.session = self.session + with mock.patch("flask.g", g): + # Collaborator trying to read the project + output = pagure.utils.is_repo_collaborator(repo, None) + self.assertTrue(output) + + # Collaborator trying to write to the project + output = pagure.utils.is_repo_collaborator( + repo, "refs/heads/master" + ) + self.assertFalse(output) + + output = pagure.utils.is_repo_collaborator(repo, "refs/heads/epel") + self.assertTrue(output) + + output = pagure.utils.is_repo_collaborator( + repo, "refs/heads/epel8" + ) + self.assertTrue(output) + + output = pagure.utils.is_repo_collaborator( + repo, "refs/heads/epel8-sig-foobar" + ) + self.assertTrue(output) + + def test_is_repo_collaborator_logged_in_in_group(self): + """ Test is_repo_committer in pagure with the appropriate user logged + in. """ + # Create group + msg = pagure.lib.query.add_group( + self.session, + group_name="packager", + display_name="packager", + description="The Fedora packager groups", + group_type="user", + user="pingou", + is_admin=False, + blacklist=[], + ) + self.session.commit() + self.assertEqual(msg, "User `pingou` added to the group `packager`.") + + # Add user to group + group = pagure.lib.query.search_groups( + self.session, group_name="packager" + ) + msg = pagure.lib.query.add_user_to_group( + self.session, + username="foo", + group=group, + user="pingou", + is_admin=True, + ) + self.session.commit() + self.assertEqual(msg, "User `foo` added to the group `packager`.") + + # Add group packager to project test + project = pagure.lib.query._get_project(self.session, "test") + msg = pagure.lib.query.add_group_to_project( + self.session, + project=project, + new_group="packager", + user="pingou", + access="collaborator", + branches="epel*", + ) + self.session.commit() + self.assertEqual(msg, "Group added") + + repo = pagure.lib.query._get_project(self.session, "test") + + g = munch.Munch() + g.fas_user = tests.FakeUser(username="foo") + g.authenticated = True + g.session = self.session + with mock.patch("flask.g", g): + # Collaborator in the group trying to read the project + output = pagure.utils.is_repo_collaborator(repo, None) + self.assertTrue(output) + + # Collaborator in the group trying to write to the project + output = pagure.utils.is_repo_collaborator( + repo, "refs/heads/master" + ) + self.assertFalse(output) + + output = pagure.utils.is_repo_collaborator(repo, "refs/heads/epel") + self.assertTrue(output) + + output = pagure.utils.is_repo_collaborator( + repo, "refs/heads/epel8" + ) + self.assertTrue(output) + + output = pagure.utils.is_repo_collaborator( + repo, "refs/heads/epel8-sig-foobar" + ) + self.assertTrue(output) + if __name__ == "__main__": unittest.main(verbosity=2) diff --git a/tests/test_pagure_flask_api_fork.py b/tests/test_pagure_flask_api_fork.py index 6e1b22c..14e61a9 100644 --- a/tests/test_pagure_flask_api_fork.py +++ b/tests/test_pagure_flask_api_fork.py @@ -422,11 +422,13 @@ class PagureFlaskApiForktests(tests.Modeltests): "project": { "access_groups": { "admin": [], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -460,11 +462,13 @@ class PagureFlaskApiForktests(tests.Modeltests): "repo_from": { "access_groups": { "admin": [], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -763,9 +767,15 @@ class PagureFlaskApiForktests(tests.Modeltests): "initial_comment": None, "last_updated": "1431414800", "project": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -797,9 +807,15 @@ class PagureFlaskApiForktests(tests.Modeltests): }, "remote_git": None, "repo_from": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -921,9 +937,15 @@ class PagureFlaskApiForktests(tests.Modeltests): "initial_comment": None, "last_updated": "1431414800", "project": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -955,9 +977,15 @@ class PagureFlaskApiForktests(tests.Modeltests): }, "remote_git": None, "repo_from": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -3036,9 +3064,15 @@ class PagureFlaskApiForktests(tests.Modeltests): "initial_comment": "Nothing much, the changes speak for themselves", "last_updated": "1516348115", "project": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -3070,9 +3104,15 @@ class PagureFlaskApiForktests(tests.Modeltests): }, "remote_git": None, "repo_from": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -3173,9 +3213,15 @@ class PagureFlaskApiForktests(tests.Modeltests): "initial_comment": None, "last_updated": "1516348115", "project": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -3207,9 +3253,15 @@ class PagureFlaskApiForktests(tests.Modeltests): }, "remote_git": None, "repo_from": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -3532,9 +3584,15 @@ class PagureApiThresholdReachedTests(tests.Modeltests): "initial_comment": "Nothing much, the changes speak for themselves", "last_updated": "1516348115", "project": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -3566,9 +3624,15 @@ class PagureApiThresholdReachedTests(tests.Modeltests): }, "remote_git": None, "repo_from": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], diff --git a/tests/test_pagure_flask_api_fork_update.py b/tests/test_pagure_flask_api_fork_update.py index 6846b00..d0bc401 100644 --- a/tests/test_pagure_flask_api_fork_update.py +++ b/tests/test_pagure_flask_api_fork_update.py @@ -256,9 +256,15 @@ class PagureFlaskApiForkUpdatetests(tests.SimplePagureTest): "initial_comment": "Edited initial comment", "last_updated": "1551276261", "project": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -290,9 +296,15 @@ class PagureFlaskApiForkUpdatetests(tests.SimplePagureTest): }, "remote_git": None, "repo_from": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -310,11 +322,13 @@ class PagureFlaskApiForkUpdatetests(tests.SimplePagureTest): "parent": { "access_groups": { "admin": [], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -412,9 +426,15 @@ class PagureFlaskApiForkUpdatetests(tests.SimplePagureTest): "initial_comment": "", "last_updated": "1551276261", "project": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -446,9 +466,15 @@ class PagureFlaskApiForkUpdatetests(tests.SimplePagureTest): }, "remote_git": None, "repo_from": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -466,11 +492,13 @@ class PagureFlaskApiForkUpdatetests(tests.SimplePagureTest): "parent": { "access_groups": { "admin": [], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -588,9 +616,15 @@ class PagureFlaskApiForkUpdatetests(tests.SimplePagureTest): "fixes #2 \n\nThanks", "last_updated": "1551276261", "project": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -622,9 +656,15 @@ class PagureFlaskApiForkUpdatetests(tests.SimplePagureTest): }, "remote_git": None, "repo_from": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -642,11 +682,13 @@ class PagureFlaskApiForkUpdatetests(tests.SimplePagureTest): "parent": { "access_groups": { "admin": [], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], diff --git a/tests/test_pagure_flask_api_group.py b/tests/test_pagure_flask_api_group.py index f5522c2..39c2b7f 100644 --- a/tests/test_pagure_flask_api_group.py +++ b/tests/test_pagure_flask_api_group.py @@ -290,11 +290,13 @@ class PagureFlaskApiGroupTests(tests.SimplePagureTest): { "access_groups": { "admin": ["some_group"], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -368,11 +370,13 @@ class PagureFlaskApiGroupTests(tests.SimplePagureTest): { "access_groups": { "admin": ["some_group"], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -438,11 +442,13 @@ class PagureFlaskApiGroupTests(tests.SimplePagureTest): { "access_groups": { "admin": ["some_group"], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], diff --git a/tests/test_pagure_flask_api_project.py b/tests/test_pagure_flask_api_project.py index c370caf..870aaa0 100644 --- a/tests/test_pagure_flask_api_project.py +++ b/tests/test_pagure_flask_api_project.py @@ -36,6 +36,8 @@ from pagure.lib.repo import PagureRepo class PagureFlaskApiProjecttests(tests.Modeltests): """ Tests for the flask API of pagure for issue """ + maxDiff = None + def setUp(self): super(PagureFlaskApiProjecttests, self).setUp() self.gga_patcher = patch( @@ -225,9 +227,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): }, "projects": [ { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -441,9 +449,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): }, "projects": [ { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -502,9 +516,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): }, "projects": [ { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -535,9 +555,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): }, }, { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -568,9 +594,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): }, }, { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -629,9 +661,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): }, "projects": [ { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -662,9 +700,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): }, }, { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -695,9 +739,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): }, }, { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -752,9 +802,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): }, "projects": [ { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -809,9 +865,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): }, "projects": [ { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -882,9 +944,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): data["date_created"] = "1436527638" data["date_modified"] = "1436527638" expected_data = { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -972,11 +1040,13 @@ class PagureFlaskApiProjecttests(tests.Modeltests): expected_data = { "access_groups": { "admin": [], + "collaborator": [], "commit": ["some_group"], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -1036,9 +1106,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): data["date_created"] = "1436527638" data["date_modified"] = "1436527638" expected_data = { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -1101,9 +1177,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): }, "projects": [ { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -1134,9 +1216,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): }, }, { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -1167,9 +1255,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): }, }, { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -1238,9 +1332,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): "pagination": {"next": None, "page": 2, "pages": 2, "per_page": 2}, "projects": [ { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -1396,9 +1496,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): data["date_created"] = "1496338274" data["date_modified"] = "1496338274" expected_output = { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["foo"], "ticket": [], @@ -1451,9 +1557,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): data["date_created"] = "1496338274" data["date_modified"] = "1496338274" expected_output = { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": ["pingou"], + "collaborator": [], "commit": [], "owner": ["foo"], "ticket": [], @@ -1516,9 +1628,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): data["date_created"] = "1496338274" data["date_modified"] = "1496338274" expected_output = { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": ["pingou"], + "collaborator": [], "commit": [], "owner": ["foo"], "ticket": [], @@ -1573,9 +1691,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): data["date_created"] = "1496338274" data["date_modified"] = "1496338274" expected_output = { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["foo"], "ticket": [], @@ -1632,9 +1756,15 @@ class PagureFlaskApiProjecttests(tests.Modeltests): data["date_created"] = "1496338274" data["date_modified"] = "1496338274" expected_output = { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["foo"], "ticket": [], @@ -2986,7 +3116,8 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests): project = pagure.lib.query._get_project(self.session, "test") self.assertEquals( - project.access_users, {"admin": [], "commit": [], "ticket": []} + project.access_users, + {"admin": [], "collaborator": [], "commit": [], "ticket": []}, ) def test_api_modify_acls_no_project(self): @@ -3126,9 +3257,15 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests): data["date_modified"] = "1510742566" expected_output = { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": ["foo"], "owner": ["pingou"], "ticket": [], @@ -3190,9 +3327,15 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests): data["date_modified"] = "1510742566" expected_output = { - "access_groups": {"admin": [], "commit": [], "ticket": ["baz"]}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": ["baz"], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -3231,7 +3374,8 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests): project = pagure.lib.query._get_project(self.session, "test") self.assertEquals( - project.access_users, {"admin": [], "commit": [], "ticket": []} + project.access_users, + {"admin": [], "collaborator": [], "commit": [], "ticket": []}, ) data = {"user_type": "user", "name": "foo"} @@ -3280,7 +3424,12 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests): user_foo = pagure.lib.query.search_user(self.session, username="foo") self.assertEquals( project.access_users, - {"admin": [], "commit": [user_foo], "ticket": []}, + { + "admin": [], + "collaborator": [], + "commit": [user_foo], + "ticket": [], + }, ) # Create an API token for `foo` for the project `test` @@ -3309,9 +3458,15 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests): data["date_modified"] = "1510742566" expected_output = { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -3348,7 +3503,8 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests): self.session = pagure.lib.query.create_session(self.dbpath) project = pagure.lib.query._get_project(self.session, "test") self.assertEquals( - project.access_users, {"admin": [], "commit": [], "ticket": []} + project.access_users, + {"admin": [], "collaborator": [], "commit": [], "ticket": []}, ) def test_api_modify_acls_remove_someone_else_acl(self): @@ -3362,7 +3518,12 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests): user_foo = pagure.lib.query.search_user(self.session, username="foo") self.assertEquals( project.access_users, - {"admin": [], "commit": [user_foo], "ticket": []}, + { + "admin": [], + "collaborator": [], + "commit": [user_foo], + "ticket": [], + }, ) headers = {"Authorization": "token aaabbbcccddd"} @@ -3376,9 +3537,15 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests): data["date_modified"] = "1510742566" expected_output = { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -3415,7 +3582,8 @@ class PagureFlaskApiProjectModifyAclTests(tests.Modeltests): self.session = pagure.lib.query.create_session(self.dbpath) project = pagure.lib.query._get_project(self.session, "test") self.assertEquals( - project.access_users, {"admin": [], "commit": [], "ticket": []} + project.access_users, + {"admin": [], "collaborator": [], "commit": [], "ticket": []}, ) @@ -3434,7 +3602,8 @@ class PagureFlaskApiProjectOptionsTests(tests.Modeltests): project = pagure.lib.query._get_project(self.session, "test") self.assertEquals( - project.access_users, {"admin": [], "commit": [], "ticket": []} + project.access_users, + {"admin": [], "collaborator": [], "commit": [], "ticket": []}, ) def test_api_get_project_options_wrong_project(self): diff --git a/tests/test_pagure_flask_api_project_delete_project.py b/tests/test_pagure_flask_api_project_delete_project.py index 7c40d66..1a0cb7c 100644 --- a/tests/test_pagure_flask_api_project_delete_project.py +++ b/tests/test_pagure_flask_api_project_delete_project.py @@ -152,9 +152,15 @@ class PagureFlaskApiProjectDeleteProjecttests(tests.Modeltests): { "message": "Project deleted", "project": { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], diff --git a/tests/test_pagure_flask_api_ui_private_repo.py b/tests/test_pagure_flask_api_ui_private_repo.py index 72e3055..b4a56eb 100644 --- a/tests/test_pagure_flask_api_ui_private_repo.py +++ b/tests/test_pagure_flask_api_ui_private_repo.py @@ -1396,11 +1396,13 @@ class PagurePrivateRepotest(tests.Modeltests): { "access_groups": { "admin": [], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -1454,11 +1456,13 @@ class PagurePrivateRepotest(tests.Modeltests): { "access_groups": { "admin": [], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -1588,11 +1592,13 @@ class PagurePrivateRepotest(tests.Modeltests): "project": { "access_groups": { "admin": [], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -1621,11 +1627,13 @@ class PagurePrivateRepotest(tests.Modeltests): "repo_from": { "access_groups": { "admin": [], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -1719,11 +1727,13 @@ class PagurePrivateRepotest(tests.Modeltests): "project": { "access_groups": { "admin": [], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -1752,11 +1762,13 @@ class PagurePrivateRepotest(tests.Modeltests): "repo_from": { "access_groups": { "admin": [], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], diff --git a/tests/test_pagure_flask_api_user.py b/tests/test_pagure_flask_api_user.py index 8e688c7..7e27638 100644 --- a/tests/test_pagure_flask_api_user.py +++ b/tests/test_pagure_flask_api_user.py @@ -139,9 +139,15 @@ class PagureFlaskApiUSertests(tests.Modeltests): }, "repos": [ { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -172,9 +178,15 @@ class PagureFlaskApiUSertests(tests.Modeltests): }, }, { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -205,9 +217,15 @@ class PagureFlaskApiUSertests(tests.Modeltests): }, }, { - "access_groups": {"admin": [], "commit": [], "ticket": []}, + "access_groups": { + "admin": [], + "collaborator": [], + "commit": [], + "ticket": [], + }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], @@ -1759,11 +1777,13 @@ class PagureFlaskApiUsertestissues(tests.Modeltests): "project": { "access_groups": { "admin": [], + "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], + "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], diff --git a/tests/test_pagure_lib.py b/tests/test_pagure_lib.py index e88a8bb..1076bb6 100644 --- a/tests/test_pagure_lib.py +++ b/tests/test_pagure_lib.py @@ -4413,7 +4413,9 @@ class PagureLibtests(tests.Modeltests): """ Test the get_access_levels method in pagure.lib """ acls = pagure.lib.query.get_access_levels(self.session) - self.assertEqual(sorted(["admin", "commit", "ticket"]), sorted(acls)) + self.assertEqual( + sorted(["admin", "collaborator", "commit", "ticket"]), sorted(acls) + ) def test_get_project_users(self): """ Test the get_project_users method when combine is True diff --git a/tests/test_pagure_lib_git.py b/tests/test_pagure_lib_git.py index c12f34b..fd73e1b 100644 --- a/tests/test_pagure_lib_git.py +++ b/tests/test_pagure_lib_git.py @@ -1683,7 +1683,7 @@ new file mode 100644 index 0000000..60f7480 --- /dev/null +++ b/456 -@@ -0,0 +1,152 @@ +@@ -0,0 +1,156 @@ +{ + "assignee": null, + "branch": "master", @@ -1701,11 +1701,13 @@ index 0000000..60f7480 + "project": { + "access_groups": { + "admin": [], ++ "collaborator": [], + "commit": [], + "ticket": [] + }, + "access_users": { + "admin": [], ++ "collaborator": [], + "commit": [], + "owner": [ + "pingou" @@ -1762,11 +1764,13 @@ index 0000000..60f7480 + "repo_from": { + "access_groups": { + "admin": [], ++ "collaborator": [], + "commit": [], + "ticket": [] + }, + "access_users": { + "admin": [], ++ "collaborator": [], + "commit": [], + "owner": [ + "pingou" diff --git a/tests/test_pagure_lib_git_auth_paguregitauth.py b/tests/test_pagure_lib_git_auth_paguregitauth.py index 7b709ba..f7dbf28 100644 --- a/tests/test_pagure_lib_git_auth_paguregitauth.py +++ b/tests/test_pagure_lib_git_auth_paguregitauth.py @@ -63,6 +63,17 @@ class PagureLibGitAuthPagureGitAuthtests(tests.Modeltests): self.session.add(push_dkey) self.session.commit() + # Allow the user foo to commit to project test on epel* branches + msg = pagure.lib.query.add_user_to_project( + self.session, + project=project, + new_user="foo", + user="pingou", + access="collaborator", + branches="epel*", + ) + self.session.commit() + def create_fork(self): # Create fork headers = {"Authorization": "token aaabbbcccddd"} @@ -82,6 +93,7 @@ class PagureLibGitAuthPagureGitAuthtests(tests.Modeltests): "project_pr_only": False, "global_pr_only": False, "project": {"name": "acltest"}, + "ref": "refs/heads/master", "repotype": "main", "expected_messages": ["Internal push allowed"], "expected_result": True, @@ -93,6 +105,7 @@ class PagureLibGitAuthPagureGitAuthtests(tests.Modeltests): "project_pr_only": False, "global_pr_only": True, "project": {"name": "acltest"}, + "ref": "refs/heads/master", "repotype": "main", "expected_messages": ["Pull request required"], "expected_result": False, @@ -104,6 +117,7 @@ class PagureLibGitAuthPagureGitAuthtests(tests.Modeltests): "project_pr_only": False, "global_pr_only": True, "project": {"name": "acltest", "user": "pingou"}, + "ref": "refs/heads/master", "repotype": "main", "expected_messages": ["Has commit access: False"], "expected_result": False, @@ -115,6 +129,7 @@ class PagureLibGitAuthPagureGitAuthtests(tests.Modeltests): "project_pr_only": True, "global_pr_only": False, "project": {"name": "acltest"}, + "ref": "refs/heads/master", "repotype": "main", "expected_messages": ["Pull request required"], "expected_result": False, @@ -126,6 +141,7 @@ class PagureLibGitAuthPagureGitAuthtests(tests.Modeltests): "project_pr_only": True, "global_pr_only": False, "project": {"name": "acltest"}, + "ref": "refs/heads/master", "repotype": "ticket", "expected_messages": ["Has commit access: False"], "expected_result": False, @@ -137,6 +153,7 @@ class PagureLibGitAuthPagureGitAuthtests(tests.Modeltests): "project_pr_only": False, "global_pr_only": False, "project": {"name": "acltest"}, + "ref": "refs/heads/master", "repotype": "main", "expected_messages": [ "Deploykey used. Push access: False", @@ -151,6 +168,7 @@ class PagureLibGitAuthPagureGitAuthtests(tests.Modeltests): "project_pr_only": False, "global_pr_only": False, "project": {"name": "acltest"}, + "ref": "refs/heads/master", "repotype": "main", "expected_messages": [ "Deploykey used. Push access: True", @@ -165,6 +183,7 @@ class PagureLibGitAuthPagureGitAuthtests(tests.Modeltests): "project_pr_only": False, "global_pr_only": False, "project": {"name": "acltest"}, + "ref": "refs/heads/master", "repotype": "main", "expected_messages": ["Has commit access: False"], "expected_result": False, @@ -176,6 +195,43 @@ class PagureLibGitAuthPagureGitAuthtests(tests.Modeltests): "project_pr_only": False, "global_pr_only": False, "project": {"name": "acltest"}, + "ref": "refs/heads/master", + "repotype": "main", + "expected_messages": ["Has commit access: True"], + "expected_result": True, + }, + # Contributor invalid branch + { + "internal": False, + "username": "foo", + "project_pr_only": False, + "global_pr_only": False, + "project": {"name": "acltest"}, + "ref": "refs/heads/master", + "repotype": "main", + "expected_messages": ["Has commit access: False"], + "expected_result": False, + }, + # Contributor valid branch epel-foo + { + "internal": False, + "username": "foo", + "project_pr_only": False, + "global_pr_only": False, + "project": {"name": "acltest"}, + "ref": "refs/heads/epel-foo", + "repotype": "main", + "expected_messages": ["Has commit access: True"], + "expected_result": True, + }, + # Contributor valid branch epel + { + "internal": False, + "username": "foo", + "project_pr_only": False, + "global_pr_only": False, + "project": {"name": "acltest"}, + "ref": "refs/heads/epel", "repotype": "main", "expected_messages": ["Has commit access: True"], "expected_result": True, @@ -210,7 +266,7 @@ class PagureLibGitAuthPagureGitAuthtests(tests.Modeltests): session=self.session, project=project, username=case["username"], - refname="refs/heads/master", + refname=case["ref"], pull_request=None, repotype=case["repotype"], is_internal=case["internal"],