From f8c0d916290685f90cebc40ae08ecbb485ba5a2d Mon Sep 17 00:00:00 2001 From: Clement Verna Date: Dec 05 2017 21:19:00 +0000 Subject: [PATCH 1/5] Add a new decorators module. This commit move the decorator that checks if a project has an issue tracker to a module dedicated to custom decorator. Signed-off-by: Clement Verna --- diff --git a/pagure/lib/decorators.py b/pagure/lib/decorators.py new file mode 100644 index 0000000..e992d33 --- /dev/null +++ b/pagure/lib/decorators.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +""" + (c) 2017 - Copyright Red Hat Inc + + Authors: + Clement Verna + +""" +import flask +from functools import wraps + + +def has_issue_tracker(function): + """ + Decorator that checks if the current pagure project has the + issue tracker active + If not active returns a 404 page + """ + @wraps(function) + def check_issue_tracker(*args, **kwargs): + repo = flask.g.repo + if not repo.settings.get('issue_tracker', True): + flask.abort(404, 'No issue tracker found for this project') + return function(*args, **kwargs) + + return check_issue_tracker diff --git a/pagure/ui/issues.py b/pagure/ui/issues.py index 1439581..9d301f8 100644 --- a/pagure/ui/issues.py +++ b/pagure/ui/issues.py @@ -19,7 +19,6 @@ import logging import os import re from collections import defaultdict -from functools import wraps from math import ceil import flask @@ -32,6 +31,7 @@ import pagure.doc_utils import pagure.exceptions import pagure.lib import pagure.lib.mimetype +from pagure.lib.decorators import has_issue_tracker import pagure.forms from pagure import (APP, SESSION, __get_file_in_tree, login_required, authenticated, urlpattern) @@ -40,22 +40,6 @@ from pagure import (APP, SESSION, __get_file_in_tree, _log = logging.getLogger(__name__) -def has_issue_tracker(function): - """ - Decorator that checks if the current pagure project has the - issue tracker active - If not active returns a 404 page - """ - @wraps(function) - def check_issue_tracker(*args, **kwargs): - repo = flask.g.repo - if not repo.settings.get('issue_tracker', True): - flask.abort(404, 'No issue tracker found for this project') - return function(*args, **kwargs) - - return check_issue_tracker - - @APP.route( '//issue//update/', methods=['GET', 'POST']) @@ -1340,9 +1324,6 @@ def view_issue_raw_file( repo = flask.g.repo - if not repo.settings.get('issue_tracker', True): - flask.abort(404, 'No issue tracker found for this project') - attachdir = os.path.join(APP.config['ATTACHMENTS_FOLDER'], repo.fullname) attachpath = os.path.join(attachdir, filename) if not os.path.exists(attachpath): From c4a8d5348d1384b52ec38e291be7de5ed1e6aac9 Mon Sep 17 00:00:00 2001 From: Clement Verna Date: Dec 05 2017 21:19:00 +0000 Subject: [PATCH 2/5] Add decorator to check admin permission. This commit adds a new decorator that check if a user has admin permission to the project. Introduce the decorator in the ui/issues.py module. Signed-off-by: Clement Verna --- diff --git a/pagure/lib/decorators.py b/pagure/lib/decorators.py index e992d33..5878c27 100644 --- a/pagure/lib/decorators.py +++ b/pagure/lib/decorators.py @@ -25,3 +25,18 @@ def has_issue_tracker(function): return function(*args, **kwargs) return check_issue_tracker + + +def is_repo_admin(function): + """ + Decorator that checks if the current user is the admin of + the project. + If not active returns a 403 page + """ + @wraps(function) + def check_repo_admin(*args, **kwargs): + if not flask.g.repo_admin: + flask.abort(403, 'You are not allowed to change the \ + settings for this project') + return function(*args, **kwargs) + return check_repo_admin diff --git a/pagure/ui/issues.py b/pagure/ui/issues.py index 9d301f8..e4c225e 100644 --- a/pagure/ui/issues.py +++ b/pagure/ui/issues.py @@ -31,7 +31,7 @@ import pagure.doc_utils import pagure.exceptions import pagure.lib import pagure.lib.mimetype -from pagure.lib.decorators import has_issue_tracker +from pagure.lib.decorators import has_issue_tracker, is_repo_admin import pagure.forms from pagure import (APP, SESSION, __get_file_in_tree, login_required, authenticated, urlpattern) @@ -373,18 +373,13 @@ def update_issue(repo, issueid, username=None, namespace=None): '/fork////tag//edit', methods=('GET', 'POST')) @login_required +@is_repo_admin @has_issue_tracker def edit_tag(repo, tag, username=None, namespace=None): """ Edit the specified tag associated with the issues of a project. """ repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to edit tags associated with the issues of \ - this project') - tags = pagure.lib.get_tags_of_project(SESSION, repo) if not tags: flask.abort(404, 'Project has no tags to edit') @@ -440,6 +435,7 @@ def edit_tag(repo, tag, username=None, namespace=None): @APP.route('//update/tags', methods=['POST']) @APP.route('///update/tags', methods=['POST']) @login_required +@is_repo_admin @has_issue_tracker def update_tags(repo, username=None, namespace=None): """ Update the tags of a project. @@ -447,11 +443,6 @@ def update_tags(repo, username=None, namespace=None): repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - form = pagure.forms.ConfirmationForm() error = False @@ -531,18 +522,13 @@ def update_tags(repo, username=None, namespace=None): @APP.route('/fork///droptag/', methods=['POST']) @APP.route('/fork////droptag/', methods=['POST']) @login_required +@is_repo_admin @has_issue_tracker def remove_tag(repo, username=None, namespace=None): """ Remove the specified tag, associated with the issues, from the project. """ repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to remove tags associated with the issues \ - of this project') - form = pagure.forms.DeleteIssueTagForm() if form.validate_on_submit(): tags = form.tag.data @@ -1466,13 +1452,10 @@ def edit_comment_issue( @APP.route( '/fork////issues/reports', methods=['POST']) @login_required +@is_repo_admin def save_reports(repo, username=None, namespace=None): """ Marked for watching or Unwatching """ - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to create reports for this project') return_point = flask.url_for( 'view_issues', repo=repo, username=username, namespace=namespace) From b137dda49df8eed72018fbcf26ec8445dcad2a4a Mon Sep 17 00:00:00 2001 From: Clement Verna Date: Dec 05 2017 21:19:00 +0000 Subject: [PATCH 3/5] Add is_repo_admin decorator to ui/plugins.py Signed-off-by: Clement Verna --- diff --git a/pagure/ui/plugins.py b/pagure/ui/plugins.py index 6447ab6..cf2875a 100644 --- a/pagure/ui/plugins.py +++ b/pagure/ui/plugins.py @@ -22,6 +22,7 @@ import pagure.lib.plugins import pagure.forms from pagure import APP, SESSION, login_required from pagure.exceptions import FileNotFoundException +from pagure.lib.decorators import is_repo_admin _log = logging.getLogger(__name__) @@ -68,16 +69,12 @@ _log = logging.getLogger(__name__) '/fork////settings//', methods=('GET', 'POST')) @login_required +@is_repo_admin def view_plugin(repo, plugin, username=None, namespace=None, full=True): """ Presents the settings of the project. """ repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - # Private repos are not allowed to leak information outside so disabling CI # enables us to keep the repos totally discreate and prevents from leaking # information outside From cf180d9fff3fe9748d06656a8349e7db49d07f2f Mon Sep 17 00:00:00 2001 From: Clement Verna Date: Dec 05 2017 21:19:00 +0000 Subject: [PATCH 4/5] New decorator for admin session timeout. This commit adds a new decorator to check if an admin session has timedout. It introduce this decorator and the is_repo_admin to the ui/repo.py module Signed-off-by: Clement Verna --- diff --git a/pagure/lib/decorators.py b/pagure/lib/decorators.py index 5878c27..4ed0615 100644 --- a/pagure/lib/decorators.py +++ b/pagure/lib/decorators.py @@ -8,6 +8,7 @@ """ import flask +from pagure import admin_session_timedout from functools import wraps @@ -40,3 +41,19 @@ def is_repo_admin(function): settings for this project') return function(*args, **kwargs) return check_repo_admin + + +def is_admin_sess_timedout(function): + """ + Decorator that checks if the admin session has timeout. + If not true redirect to the login page + """ + @wraps(function) + def check_session_timeout(*args, **kwargs): + if admin_session_timedout(): + if flask.request.method == 'POST': + flask.flash('Action canceled, try it again', 'error') + return flask.redirect( + flask.url_for('auth_login', next=flask.request.url)) + return function(*args, **kwargs) + return check_session_timeout diff --git a/pagure/ui/repo.py b/pagure/ui/repo.py index 499b9c5..bfbbdbd 100644 --- a/pagure/ui/repo.py +++ b/pagure/ui/repo.py @@ -50,8 +50,9 @@ import pagure.forms import pagure import pagure.ui.plugins from pagure import (APP, SESSION, __get_file_in_tree, login_required, - admin_session_timedout, authenticated) + authenticated) from pagure.lib import encoding_utils +from pagure.lib.decorators import is_repo_admin, is_admin_sess_timedout _log = logging.getLogger(__name__) @@ -922,6 +923,7 @@ def view_tags(repo, username=None, namespace=None): @APP.route( '/fork////upload', methods=('GET', 'POST')) @login_required +@is_repo_admin def new_release(repo, username=None, namespace=None): """ Upload a new release. """ @@ -931,11 +933,6 @@ def new_release(repo, username=None, namespace=None): repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - form = pagure.forms.UploadFileForm() if form.validate_on_submit(): @@ -992,23 +989,15 @@ def new_release(repo, username=None, namespace=None): @APP.route( '/fork////settings', methods=('GET', 'POST')) @login_required +@is_admin_sess_timedout +@is_repo_admin def view_settings(repo, username=None, namespace=None): """ Presents the settings of the project. """ - if admin_session_timedout(): - if flask.request.method == 'POST': - flask.flash('Action canceled, try it again', 'error') - return flask.redirect( - flask.url_for('auth_login', next=flask.request.url)) repo = flask.g.repo repo_obj = flask.g.repo_obj - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - plugins = pagure.lib.plugins.get_plugin_names( APP.config.get('DISABLED_PLUGINS')) tags = pagure.lib.get_tags_of_project(SESSION, repo) @@ -1082,24 +1071,15 @@ def view_settings(repo, username=None, namespace=None): '/fork////settings/test_hook', methods=('GET', 'POST')) @login_required +@is_admin_sess_timedout +@is_repo_admin def test_web_hook(repo, username=None, namespace=None): """ Endpoint that can be called to send a test message to the web-hook service allowing to test the web-hooks set. """ - if admin_session_timedout(): - if flask.request.method == 'POST': - flask.flash('Action canceled, try it again', 'error') - return flask.redirect( - flask.url_for('auth_login', next=flask.request.url)) repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to trigger a test notification for this ' - 'project') - form = pagure.forms.ConfirmationForm() if form.validate_on_submit(): if pagure.lib.REDIS: @@ -1128,24 +1108,14 @@ def test_web_hook(repo, username=None, namespace=None): @APP.route('/fork///update', methods=['POST']) @APP.route('/fork////update', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def update_project(repo, username=None, namespace=None): """ Update the description of a project. """ - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - form = pagure.forms.ProjectFormSimplified() if form.validate_on_submit(): @@ -1181,27 +1151,17 @@ def update_project(repo, username=None, namespace=None): '/fork////update/priorities', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def update_priorities(repo, username=None, namespace=None): """ Update the priorities of a project. """ - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) repo = flask.g.repo if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - form = pagure.forms.ConfirmationForm() error = False @@ -1281,27 +1241,17 @@ def update_priorities(repo, username=None, namespace=None): '/fork////update/default_priority', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def default_priority(repo, username=None, namespace=None): """ Update the default priority of a project. """ - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) repo = flask.g.repo if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - form = pagure.forms.DefaultPriorityForm( priorities=repo.priorities.values()) @@ -1332,27 +1282,17 @@ def default_priority(repo, username=None, namespace=None): '/fork////update/milestones', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def update_milestones(repo, username=None, namespace=None): """ Update the milestones of a project. """ - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) repo = flask.g.repo if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - form = pagure.forms.ConfirmationForm() error = False @@ -1424,26 +1364,15 @@ def update_milestones(repo, username=None, namespace=None): @APP.route( '/fork////default/branch/', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def change_ref_head(repo, username=None, namespace=None): """ Change HEAD reference """ - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) - repo = flask.g.repo repo_obj = flask.g.repo_obj - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - branches = repo_obj.listall_branches() form = pagure.forms.DefaultBranchForm(branches=branches) @@ -1467,6 +1396,8 @@ def change_ref_head(repo, username=None, namespace=None): @APP.route('/fork///delete', methods=['POST']) @APP.route('/fork////delete', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def delete_repo(repo, username=None, namespace=None): """ Delete the present project. """ @@ -1478,19 +1409,6 @@ def delete_repo(repo, username=None, namespace=None): or (repo.is_fork and not del_fork): flask.abort(404) - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) - - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - if repo.read_only: flask.flash( 'The ACLs of this project are being refreshed in the backend ' @@ -1513,27 +1431,16 @@ def delete_repo(repo, username=None, namespace=None): @APP.route( '/fork////hook_token', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def new_repo_hook_token(repo, username=None, namespace=None): """ Re-generate a hook token for the present project. """ if not pagure.APP.config.get('WEBHOOK', False): flask.abort(404) - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) - repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - form = pagure.forms.ConfirmationForm() if not form.validate_on_submit(): flask.abort(400, 'Invalid request') @@ -1559,6 +1466,8 @@ def new_repo_hook_token(repo, username=None, namespace=None): @APP.route('/fork////dropdeploykey/', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def remove_deploykey(repo, keyid, username=None, namespace=None): """ Remove the specified deploy key from the project. """ @@ -1566,21 +1475,8 @@ def remove_deploykey(repo, keyid, username=None, namespace=None): if not APP.config.get('DEPLOY_KEY', True): flask.abort(404, 'This pagure instance disabled deploy keys') - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) - repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the deploy keys for this project') - form = pagure.forms.ConfirmationForm() if form.validate_on_submit(): keyids = [str(key.id) for key in repo.deploykeys] @@ -1622,6 +1518,8 @@ def remove_deploykey(repo, keyid, username=None, namespace=None): @APP.route('/fork////dropuser/', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def remove_user(repo, userid, username=None, namespace=None): """ Remove the specified user from the project. """ @@ -1629,21 +1527,8 @@ def remove_user(repo, userid, username=None, namespace=None): if not pagure.APP.config.get('ENABLE_USER_MNGT', True): flask.abort(404, 'User management not allowed in the pagure instance') - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) - repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the users for this project') - form = pagure.forms.ConfirmationForm() if form.validate_on_submit(): userids = [str(user.id) for user in repo.users] @@ -1698,26 +1583,16 @@ def remove_user(repo, userid, username=None, namespace=None): '/fork////adddeploykey', methods=('GET', 'POST')) @login_required +@is_admin_sess_timedout +@is_repo_admin def add_deploykey(repo, username=None, namespace=None): """ Add the specified deploy key to the project. """ - if not APP.config.get('DEPLOY_KEY', True): flask.abort(404, 'This pagure instance disabled deploy keys') - if admin_session_timedout(): - if flask.request.method == 'POST': - flask.flash('Action canceled, try it again', 'error') - return flask.redirect( - flask.url_for('auth_login', next=flask.request.url)) - repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to add deploy keys to this project') - form = pagure.forms.AddDeployKeyForm() if form.validate_on_submit(): @@ -1765,6 +1640,8 @@ def add_deploykey(repo, username=None, namespace=None): @APP.route( '/fork////adduser', methods=('GET', 'POST')) @login_required +@is_admin_sess_timedout +@is_repo_admin def add_user(repo, username=None, namespace=None): """ Add the specified user to the project. """ @@ -1773,19 +1650,8 @@ def add_user(repo, username=None, namespace=None): flask.abort( 404, 'User management is not allowed in this pagure instance') - if admin_session_timedout(): - if flask.request.method == 'POST': - flask.flash('Action canceled, try it again', 'error') - return flask.redirect( - flask.url_for('auth_login', next=flask.request.url)) - repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to add users to this project') - user_to_update = flask.request.args.get('user', '').strip() user_to_update_obj = None user_access = None @@ -1845,6 +1711,8 @@ def add_user(repo, username=None, namespace=None): '/fork////dropgroup/', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def remove_group_project(repo, groupid, username=None, namespace=None): """ Remove the specified group from the project. """ @@ -1853,21 +1721,8 @@ def remove_group_project(repo, groupid, username=None, namespace=None): flask.abort( 404, 'User management is not allowed in this pagure instance') - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) - repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the users for this project') - form = pagure.forms.ConfirmationForm() if form.validate_on_submit(): grpids = [grp.id for grp in repo.groups] @@ -1910,6 +1765,8 @@ def remove_group_project(repo, groupid, username=None, namespace=None): @APP.route( '/fork////addgroup', methods=('GET', 'POST')) @login_required +@is_admin_sess_timedout +@is_repo_admin def add_group_project(repo, username=None, namespace=None): """ Add the specified group to the project. """ @@ -1918,19 +1775,8 @@ def add_group_project(repo, username=None, namespace=None): flask.abort( 404, 'User management is not allowed in this pagure instance') - if admin_session_timedout(): - if flask.request.method == 'POST': - flask.flash('Action canceled, try it again', 'error') - return flask.redirect( - flask.url_for('auth_login', next=flask.request.url)) - repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to add groups to this project') - group_to_update = flask.request.args.get('group', '').strip() group_to_update_obj = None group_access = None @@ -1988,22 +1834,14 @@ def add_group_project(repo, username=None, namespace=None): @APP.route('/fork///regenerate', methods=['POST']) @APP.route('/fork////regenerate', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def regenerate_git(repo, username=None, namespace=None): """ Regenerate the specified git repo with the content in the project. """ - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort(403, 'You are not allowed to regenerate the git repos') - regenerate = flask.request.form.get('regenerate') if not regenerate or regenerate.lower() not in ['tickets', 'requests']: flask.abort(400, 'You can only regenerate tickest or requests repos') @@ -2061,14 +1899,10 @@ def regenerate_git(repo, username=None, namespace=None): '/fork////token/new', methods=('GET', 'POST')) @login_required +@is_admin_sess_timedout def add_token(repo, username=None, namespace=None): """ Add a token to a specified project. """ - if admin_session_timedout(): - if flask.request.method == 'POST': - flask.flash('Action canceled, try it again', 'error') - return flask.redirect( - flask.url_for('auth_login', next=flask.request.url)) repo = flask.g.repo @@ -2122,24 +1956,14 @@ def add_token(repo, username=None, namespace=None): '/fork////token/revoke/', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def revoke_api_token(repo, token_id, username=None, namespace=None): """ Revokie a token to a specified project. """ - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - token = pagure.lib.get_api_token(SESSION, token_id) if not token \ @@ -2181,17 +2005,13 @@ def revoke_api_token(repo, token_id, username=None, namespace=None): '/fork////edit//f/' '', methods=('GET', 'POST')) @login_required +@is_repo_admin def edit_file(repo, branchname, filename, username=None, namespace=None): """ Edit a file online. """ repo = flask.g.repo repo_obj = flask.g.repo_obj - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - user = pagure.lib.search_user( SESSION, username=flask.g.fas_user.username) @@ -2440,24 +2260,14 @@ def watch_repo(repo, watch, username=None, namespace=None): @APP.route( '/fork////public_notif', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def update_public_notifications(repo, username=None, namespace=None): """ Update the public notification settings of a project. """ - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - form = pagure.forms.PublicNotificationForm() if form.validate_on_submit(): @@ -2500,27 +2310,17 @@ def update_public_notifications(repo, username=None, namespace=None): '/fork////update/close_status', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def update_close_status(repo, username=None, namespace=None): """ Update the close_status of a project. """ - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) repo = flask.g.repo if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - form = pagure.forms.ConfirmationForm() if form.validate_on_submit(): @@ -2549,16 +2349,11 @@ def update_close_status(repo, username=None, namespace=None): '/fork////update/quick_replies', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def update_quick_replies(repo, username=None, namespace=None): """ Update the quick_replies of a project. """ - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) repo = flask.g.repo @@ -2568,11 +2363,6 @@ def update_quick_replies(repo, username=None, namespace=None): 404, 'Issue tracker and pull requests are disabled for this project') - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - form = pagure.forms.ConfirmationForm() if form.validate_on_submit(): @@ -2601,27 +2391,17 @@ def update_quick_replies(repo, username=None, namespace=None): '/fork////update/custom_keys', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def update_custom_keys(repo, username=None, namespace=None): """ Update the custom_keys of a project. """ - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) repo = flask.g.repo if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - form = pagure.forms.ConfirmationForm() if form.validate_on_submit(): @@ -2663,27 +2443,17 @@ def update_custom_keys(repo, username=None, namespace=None): '/fork////delete/report', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def delete_report(repo, username=None, namespace=None): """ Delete a report from a project. """ - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) repo = flask.g.repo if not repo.settings.get('issue_tracker', True): flask.abort(404, 'No issue tracker found for this project') - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - form = pagure.forms.ConfirmationForm() if form.validate_on_submit(): @@ -2714,27 +2484,16 @@ def delete_report(repo, username=None, namespace=None): '/fork////give', methods=['POST']) @login_required +@is_admin_sess_timedout +@is_repo_admin def give_project(repo, username=None, namespace=None): """ Give a project to someone else. """ if not APP.config.get('ENABLE_GIVE_PROJECTS', True): flask.abort(404) - if admin_session_timedout(): - flask.flash('Action canceled, try it again', 'error') - url = flask.url_for( - 'view_settings', username=username, repo=repo, - namespace=namespace) - return flask.redirect( - flask.url_for('auth_login', next=url)) - repo = flask.g.repo - if not flask.g.repo_admin: - flask.abort( - 403, - 'You are not allowed to change the settings for this project') - if flask.g.fas_user.username != repo.user.user and not pagure.is_admin(): flask.abort( 403, diff --git a/tests/test_pagure_flask_ui_repo.py b/tests/test_pagure_flask_ui_repo.py index ea20d0e..4e3a1aa 100644 --- a/tests/test_pagure_flask_ui_repo.py +++ b/tests/test_pagure_flask_ui_repo.py @@ -52,7 +52,7 @@ class PagureFlaskRepotests(tests.Modeltests): pagure.APP.config['UPLOAD_FOLDER_PATH'] = os.path.join( self.path, 'releases') - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_add_user_when_user_mngt_off(self, ast): """ Test the add_user endpoint when user management is turned off in the pagure instance """ @@ -104,7 +104,7 @@ class PagureFlaskRepotests(tests.Modeltests): pagure.APP.config['ENABLE_USER_MNGT'] = True - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_add_deploykey(self, ast): """ Test the add_deploykey endpoint. """ ast.return_value = False @@ -206,7 +206,7 @@ class PagureFlaskRepotests(tests.Modeltests): self.assertIn('Deploy key added', output.data) self.assertIn('PUSH ACCESS', output.data) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') @patch.dict('pagure.APP.config', {'DEPLOY_KEY': False}) def test_add_deploykey_disabled(self, ast): """ Test the add_deploykey endpoint when it's disabled in the config. @@ -223,7 +223,7 @@ class PagureFlaskRepotests(tests.Modeltests): output = self.app.post('/test/adddeploykey') self.assertEqual(output.status_code, 404) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') @patch('pagure.lib.notify.log') def test_add_user(self, mock_log, ast): """ Test the add_user endpoint. """ @@ -319,7 +319,7 @@ class PagureFlaskRepotests(tests.Modeltests): mock_log.assert_called_with(ANY, topic='project.user.added', msg=ANY, redis=ANY) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_add_group_project_when_user_mngt_off(self, ast): """ Test the add_group_project endpoint when user management is turned off in the pagure instance""" @@ -379,7 +379,7 @@ class PagureFlaskRepotests(tests.Modeltests): pagure.APP.config['ENABLE_USER_MNGT'] = True - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_add_group_project(self, ast): """ Test the add_group_project endpoint. """ ast.return_value = False @@ -481,7 +481,7 @@ class PagureFlaskRepotests(tests.Modeltests): self.assertIn( '\n Group added', output.data) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_remove_user_when_user_mngt_off(self, ast): """ Test the remove_user endpoint when user management is turned off in the pagure instance""" @@ -534,7 +534,7 @@ class PagureFlaskRepotests(tests.Modeltests): pagure.APP.config['ENABLE_USER_MNGT'] = True - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_remove_deploykey(self, ast): """ Test the remove_deploykey endpoint. """ ast.return_value = False @@ -609,7 +609,7 @@ class PagureFlaskRepotests(tests.Modeltests): self.assertIn('

Settings for test

', output.data) self.assertIn('Deploy key removed', output.data) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') @patch.dict('pagure.APP.config', {'DEPLOY_KEY': False}) def test_remove_deploykey_disabled(self, ast): """ Test the remove_deploykey endpoint when it's disabled in the @@ -624,7 +624,7 @@ class PagureFlaskRepotests(tests.Modeltests): output = self.app.post('/test/dropdeploykey/1') self.assertEqual(output.status_code, 404) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') @patch('pagure.lib.notify.log') def test_remove_user(self, mock_log, ast): """ Test the remove_user endpoint. """ @@ -713,7 +713,7 @@ class PagureFlaskRepotests(tests.Modeltests): mock_log.assert_called_with(ANY, topic='project.user.removed', msg=ANY) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_remove_group_project_when_user_mngt_off(self, ast): """ Test the remove_group_project endpoint when user management is turned off in the pagure instance""" @@ -781,7 +781,7 @@ class PagureFlaskRepotests(tests.Modeltests): pagure.APP.config['ENABLE_USER_MNGT'] = True - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_remove_group_project(self, ast): """ Test the remove_group_project endpoint. """ ast.return_value = False @@ -885,7 +885,7 @@ class PagureFlaskRepotests(tests.Modeltests): repo = pagure.get_authorized_project(self.session, 'test') self.assertEqual(len(repo.groups), 0) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_update_project(self, ast): """ Test the update_project endpoint. """ ast.return_value = True @@ -981,7 +981,7 @@ class PagureFlaskRepotests(tests.Modeltests): '\n Project updated', output.data) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_update_project_update_tag(self, ast): """ Test the view_settings endpoint when updating the project's tags. @@ -1058,7 +1058,7 @@ class PagureFlaskRepotests(tests.Modeltests): '\n Project updated', output.data) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_view_settings(self, ast): """ Test the view_settings endpoint. """ ast.return_value = False @@ -1184,7 +1184,7 @@ class PagureFlaskRepotests(tests.Modeltests): 'name="issue_tracker" checked=""/>', output.data) @patch('pagure.lib.git.generate_gitolite_acls') - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_view_settings_pr_only(self, ast, gen_acl): """ Test the view_settings endpoint when turning on PR only. """ ast.return_value = False @@ -1243,7 +1243,7 @@ class PagureFlaskRepotests(tests.Modeltests): self.assertEqual(args[1].keys(), ['project']) self.assertEqual(args[1]['project'].fullname, 'test') - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_fields_in_view_settings(self, ast): """ Test the default fields in view_settings endpoint. """ ast.return_value = False @@ -2727,7 +2727,7 @@ index 0000000..fb7093d @patch.dict('pagure.APP.config', {'ENABLE_DEL_PROJECTS': False}) @patch('pagure.lib.notify.send_email') - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_delete_repo_when_turned_off(self, ast, send_email): """ Test the delete_repo endpoint when deletion of a repo is turned off in the pagure instance """ @@ -2945,7 +2945,7 @@ index 0000000..fb7093d self.assertEqual(output.status_code, 404) @patch('pagure.lib.notify.send_email') - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_delete_read_only_repo(self, ast, send_email): """ Test the delete_repo endpoint when the repo is read_only """ ast.return_value = False @@ -2995,7 +2995,7 @@ index 0000000..fb7093d output.data) @patch('pagure.lib.notify.send_email') - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_delete_repo(self, ast, send_email): """ Test the delete_repo endpoint. """ ast.return_value = False @@ -3265,7 +3265,7 @@ index 0000000..fb7093d @patch.dict('pagure.APP.config', {'TICKETS_FOLDER': None}) @patch('pagure.lib.notify.send_email', MagicMock(return_value=True)) - @patch('pagure.ui.repo.admin_session_timedout', MagicMock(return_value=False)) + @patch('pagure.lib.decorators.admin_session_timedout', MagicMock(return_value=False)) def test_delete_repo_no_ticket(self): """ Test the delete_repo endpoint when tickets aren't enabled in this pagure instance. """ @@ -3304,7 +3304,7 @@ index 0000000..fb7093d output.data) @patch('pagure.lib.notify.send_email') - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_delete_repo_with_users(self, ast, send_email): """ Test the delete_repo endpoint. """ ast.return_value = False @@ -3392,7 +3392,7 @@ index 0000000..fb7093d self.assertEqual(repo, None) @patch('pagure.lib.notify.send_email') - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_delete_repo_with_group(self, ast, send_email): """ Test the delete_repo endpoint. """ ast.return_value = False @@ -3494,7 +3494,7 @@ index 0000000..fb7093d self.assertEqual(repo, None) @patch('pagure.lib.notify.send_email') - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_delete_repo_with_coloredtag(self, ast, send_email): """ Test the delete_repo endpoint. """ ast.return_value = False @@ -3588,7 +3588,7 @@ index 0000000..fb7093d repo = pagure.get_authorized_project(self.session, 'test2') self.assertEqual(repo, None) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_new_repo_hook_token(self, ast): """ Test the new_repo_hook_token endpoint. """ ast.return_value = False @@ -3647,7 +3647,7 @@ index 0000000..fb7093d self.assertNotEqual(repo.hook_token, 'aaabbbccc') @patch('pagure.lib.notify.send_email') - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') @patch('pagure.lib.git.update_git') def test_regenerate_git(self, upgit, ast, sendmail): """ Test the regenerate_git endpoint. """ @@ -3957,7 +3957,7 @@ index 0000000..fb7093d self.assertIn( '

No content found

', output.data) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_change_ref_head(self,ast): """ Test the change_ref_head endpoint. """ ast.return_value = True @@ -4157,7 +4157,7 @@ index 0000000..fb7093d 'been uploaded', output.data) self.assertIn('This project has not been tagged.', output.data) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_add_token_all_tokens(self, ast): """ Test the add_token endpoint. """ ast.return_value = False @@ -4176,7 +4176,7 @@ index 0000000..fb7093d ) @patch.dict('pagure.APP.config', {'USER_ACLS': ['create_project']}) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_add_token_one_token(self, ast): """ Test the add_token endpoint. """ ast.return_value = False @@ -4194,7 +4194,7 @@ index 0000000..fb7093d 1 ) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_add_token(self, ast): """ Test the add_token endpoint. """ ast.return_value = False @@ -4268,7 +4268,7 @@ index 0000000..fb7093d 'Valid until: ', output.data) - @patch('pagure.ui.repo.admin_session_timedout') + @patch('pagure.lib.decorators.admin_session_timedout') def test_revoke_api_token(self, ast): """ Test the revoke_api_token endpoint. """ ast.return_value = False From fbf2aa0a8c29ccd8bc43576b30b3595eedbf21a8 Mon Sep 17 00:00:00 2001 From: Clement Verna Date: Dec 05 2017 21:19:00 +0000 Subject: [PATCH 5/5] Use issue tracker decorator in ui/repo.py Signed-off-by: Clement Verna --- diff --git a/pagure/ui/repo.py b/pagure/ui/repo.py index bfbbdbd..b10c635 100644 --- a/pagure/ui/repo.py +++ b/pagure/ui/repo.py @@ -52,8 +52,8 @@ import pagure.ui.plugins from pagure import (APP, SESSION, __get_file_in_tree, login_required, authenticated) from pagure.lib import encoding_utils -from pagure.lib.decorators import is_repo_admin, is_admin_sess_timedout - +from pagure.lib.decorators import (is_repo_admin, is_admin_sess_timedout, + has_issue_tracker) _log = logging.getLogger(__name__) @@ -1151,6 +1151,7 @@ def update_project(repo, username=None, namespace=None): '/fork////update/priorities', methods=['POST']) @login_required +@has_issue_tracker @is_admin_sess_timedout @is_repo_admin def update_priorities(repo, username=None, namespace=None): @@ -1159,9 +1160,6 @@ def update_priorities(repo, username=None, namespace=None): repo = flask.g.repo - if not repo.settings.get('issue_tracker', True): - flask.abort(404, 'No issue tracker found for this project') - form = pagure.forms.ConfirmationForm() error = False @@ -1241,6 +1239,7 @@ def update_priorities(repo, username=None, namespace=None): '/fork////update/default_priority', methods=['POST']) @login_required +@has_issue_tracker @is_admin_sess_timedout @is_repo_admin def default_priority(repo, username=None, namespace=None): @@ -1249,9 +1248,6 @@ def default_priority(repo, username=None, namespace=None): repo = flask.g.repo - if not repo.settings.get('issue_tracker', True): - flask.abort(404, 'No issue tracker found for this project') - form = pagure.forms.DefaultPriorityForm( priorities=repo.priorities.values()) @@ -1282,6 +1278,7 @@ def default_priority(repo, username=None, namespace=None): '/fork////update/milestones', methods=['POST']) @login_required +@has_issue_tracker @is_admin_sess_timedout @is_repo_admin def update_milestones(repo, username=None, namespace=None): @@ -1290,9 +1287,6 @@ def update_milestones(repo, username=None, namespace=None): repo = flask.g.repo - if not repo.settings.get('issue_tracker', True): - flask.abort(404, 'No issue tracker found for this project') - form = pagure.forms.ConfirmationForm() error = False @@ -2310,6 +2304,7 @@ def update_public_notifications(repo, username=None, namespace=None): '/fork////update/close_status', methods=['POST']) @login_required +@has_issue_tracker @is_admin_sess_timedout @is_repo_admin def update_close_status(repo, username=None, namespace=None): @@ -2318,9 +2313,6 @@ def update_close_status(repo, username=None, namespace=None): repo = flask.g.repo - if not repo.settings.get('issue_tracker', True): - flask.abort(404, 'No issue tracker found for this project') - form = pagure.forms.ConfirmationForm() if form.validate_on_submit(): @@ -2349,6 +2341,7 @@ def update_close_status(repo, username=None, namespace=None): '/fork////update/quick_replies', methods=['POST']) @login_required +@has_issue_tracker @is_admin_sess_timedout @is_repo_admin def update_quick_replies(repo, username=None, namespace=None): @@ -2357,11 +2350,8 @@ def update_quick_replies(repo, username=None, namespace=None): repo = flask.g.repo - if (not repo.settings.get('issue_tracker', True) and - not repo.settings.get('pull_requests', True)): - flask.abort( - 404, - 'Issue tracker and pull requests are disabled for this project') + if (not repo.settings.get('pull_requests', True)): + flask.abort(404, 'Pull requests are disabled for this project') form = pagure.forms.ConfirmationForm() @@ -2391,6 +2381,7 @@ def update_quick_replies(repo, username=None, namespace=None): '/fork////update/custom_keys', methods=['POST']) @login_required +@has_issue_tracker @is_admin_sess_timedout @is_repo_admin def update_custom_keys(repo, username=None, namespace=None): @@ -2399,9 +2390,6 @@ def update_custom_keys(repo, username=None, namespace=None): repo = flask.g.repo - if not repo.settings.get('issue_tracker', True): - flask.abort(404, 'No issue tracker found for this project') - form = pagure.forms.ConfirmationForm() if form.validate_on_submit(): @@ -2443,6 +2431,7 @@ def update_custom_keys(repo, username=None, namespace=None): '/fork////delete/report', methods=['POST']) @login_required +@has_issue_tracker @is_admin_sess_timedout @is_repo_admin def delete_report(repo, username=None, namespace=None): @@ -2451,9 +2440,6 @@ def delete_report(repo, username=None, namespace=None): repo = flask.g.repo - if not repo.settings.get('issue_tracker', True): - flask.abort(404, 'No issue tracker found for this project') - form = pagure.forms.ConfirmationForm() if form.validate_on_submit():