Blame pagure/ui/repo.py

Pierre-Yves Chibon 33b534
# -*- coding: utf-8 -*-
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 47950c
"""
Pierre-Yves Chibon a04944
 (c) 2014-2018 - Copyright Red Hat Inc
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 47950c
 Authors:
Pierre-Yves Chibon 47950c
   Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
farhaanbukhsh 141da6
   Farhaan Bukhsh <farhaan.bukhsh@gmail.com></farhaan.bukhsh@gmail.com>
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 47950c
"""
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 22a554
# pylint: disable=too-many-lines
Pierre-Yves Chibon 22a554
# pylint: disable=too-many-branches
Pierre-Yves Chibon 22a554
# pylint: disable=too-many-locals
Pierre-Yves Chibon 22a554
# pylint: disable=too-many-statements
Pierre-Yves Chibon 22a554
# pylint: disable=bare-except
Pierre-Yves Chibon 22a554
# pylint: disable=broad-except
Pierre-Yves Chibon 53e4c2
Pierre-Yves Chibon 53e4c2
Pierre-Yves Chibon 67d1cc
from __future__ import unicode_literals, absolute_import
Aurélien Bompard dcf6f6
Pierre-Yves Chibon e649cf
import datetime
Pierre-Yves Chibon 8c8487
import json
Pierre-Yves Chibon 4635b5
import logging
Pierre-Yves Chibon 47950c
import os
Pierre-Yves Chibon 7b3c51
import re
Pierre-Yves Chibon 47950c
from math import ceil
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon e649cf
import flask
Pierre-Yves Chibon 47950c
import pygit2
Pierre-Yves Chibon 5b7bfc
import kitchen.text.converters as ktc
Aurélien Bompard 831553
import six
Pierre-Yves Chibon cda607
import werkzeug
Pierre-Yves Chibon 5b7bfc
Aurélien Bompard 831553
from six import BytesIO
Pierre-Yves Chibon a1aa0b
from PIL import Image
Pierre-Yves Chibon 5b7bfc
from sqlalchemy.exc import SQLAlchemyError
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 801c6f
from binaryornot.helpers import is_binary_string
Pierre-Yves Chibon 801c6f
Pierre-Yves Chibon fe5017
import pagure.exceptions
Pierre-Yves Chibon fe5017
import pagure.lib.git
Shengjing Zhu c28196
import pagure.lib.mimetype
Pierre-Yves Chibon 295cfb
import pagure.lib.plugins
Pierre-Yves Chibon 930073
import pagure.lib.query
Pierre-Yves Chibon 5b06f7
import pagure.lib.tasks
Pierre-Yves Chibon fe5017
import pagure.forms
Pierre-Yves Chibon fe5017
import pagure.ui.plugins
Pierre-Yves Chibon b130e5
from pagure.config import config as pagure_config
Pierre-Yves Chibon 9efbd5
from pagure.flask_app import _get_user
farhaanbukhsh b24eb0
from pagure.lib import encoding_utils
Pierre-Yves Chibon b130e5
from pagure.ui import UI_NS
Pierre-Yves Chibon b130e5
from pagure.utils import (
Pierre-Yves Chibon b130e5
    __get_file_in_tree,
Pierre-Yves Chibon b130e5
    login_required,
Aurélien Bompard 619e2a
    is_true,
Patrick Uiterwijk 71124e
    stream_template,
Pierre-Yves Chibon b130e5
)
Clement Verna afe475
from pagure.decorators import (
Clement Verna afe475
    is_repo_admin,
Clement Verna afe475
    is_admin_sess_timedout,
Pierre-Yves Chibon 9c2953
    has_issue_tracker,
Pierre-Yves Chibon d86b5c
    has_issue_or_pr_enabled,
Clement Verna 36168f
    has_pr_enabled,
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b8c7ae
Pierre-Yves Chibon 4635b5
_log = logging.getLogger(__name__)
Pierre-Yves Chibon 4635b5
Pierre-Yves Chibon 4635b5
Karsten Hopp dd024f
def get_preferred_readme(tree):
Karsten Hopp dd024f
    """ Establish some order about which README gets displayed
Karsten Hopp dd024f
    if there are several in the repository. If none of the listed
Karsten Hopp 018f64
    README files is availabe, display either the next file that
Karsten Hopp dd024f
    starts with 'README' or nothing at all.
Karsten Hopp dd024f
    """
Pierre-Yves Chibon 9c2953
    order = ["README.md", "README.rst", "README", "README.txt"]
Karsten Hopp dd024f
    readmes = [x for x in tree if x.name.startswith("README")]
Karsten Hopp 0f3f40
    if len(readmes) > 1:
Karsten Hopp dd024f
        for i in order:
Karsten Hopp dd024f
            for j in readmes:
Karsten Hopp dd024f
                if i == j.name:
Karsten Hopp dd024f
                    return j
Karsten Hopp 0f3f40
    elif len(readmes) == 1:
Karsten Hopp dd024f
        return readmes[0]
Karsten Hopp dd024f
    return None
Karsten Hopp dd024f
Pierre-Yves Chibon 4ea41a
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>.git")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>.git")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>.git")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>.git")</repo></namespace></username>
Pierre-Yves Chibon 4501da
def view_repo_git(repo, username=None, namespace=None):
Pierre-Yves Chibon 9c2953
    """ Redirect to the project index page when user wants to view
Vivek Anand 59997f
    the git repo of the project
Pierre-Yves Chibon 9c2953
    """
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_repo",
Pierre-Yves Chibon 9c2953
            repo=repo,
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>")</repo></namespace></username>
Pierre-Yves Chibon 4501da
def view_repo(repo, username=None, namespace=None):
Pierre-Yves Chibon 47950c
    """ Front page of a specific repo.
Pierre-Yves Chibon 47950c
    """
Pierre-Yves Chibon 4501da
    repo_db = flask.g.repo
Pierre-Yves Chibon 16572e
    repo_obj = flask.g.repo_obj
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 1e2612
    if not repo_obj.is_empty and not repo_obj.head_is_unborn:
Pierre-Yves Chibon 1e2612
        head = repo_obj.head.shorthand
Pierre-Yves Chibon 1e2612
    else:
Pierre-Yves Chibon 1e2612
        head = None
Pierre-Yves Chibon 1e2612
Pierre-Yves Chibon 47950c
    cnt = 0
Pierre-Yves Chibon 47950c
    last_commits = []
Pierre-Yves Chibon 47950c
    tree = []
Pierre-Yves Chibon 47950c
    if not repo_obj.is_empty:
Pierre-Yves Chibon e63173
        try:
Pierre-Yves Chibon e63173
            for commit in repo_obj.walk(
Slavek Kabrda 0dd0cd
                repo_obj.head.target, pygit2.GIT_SORT_NONE
Pierre-Yves Chibon 9c2953
            ):
Pierre-Yves Chibon e63173
                last_commits.append(commit)
Pierre-Yves Chibon e63173
                cnt += 1
Pierre-Yves Chibon e63173
                if cnt == 3:
Pierre-Yves Chibon e63173
                    break
Pierre-Yves Chibon e63173
            tree = sorted(last_commits[0].tree, key=lambda x: x.filemode)
Pierre-Yves Chibon e63173
        except pygit2.GitError:
Pierre-Yves Chibon e63173
            pass
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 47950c
    readme = None
Pierre-Yves Chibon f77c9a
    safe = False
Ghost-script d50d9e
Ghost-script d50d9e
    if not repo_obj.is_empty and not repo_obj.head_is_unborn:
Ghost-script d50d9e
        branchname = repo_obj.head.shorthand
Ghost-script d50d9e
    else:
Ghost-script d50d9e
        branchname = None
Pierre-Yves Chibon 930073
    project = pagure.lib.query.get_authorized_project(
Pierre-Yves Chibon 9c2953
        flask.g.session, repo, user=username, namespace=namespace
Pierre-Yves Chibon 9c2953
    )
Karsten Hopp 028a86
    watch_users = set()
Karsten Hopp 028a86
    watch_users.add(project.user.username)
Karsten Hopp 277ab2
    for access_type in project.access_users.keys():
Karsten Hopp 277ab2
        for user in project.access_users[access_type]:
Karsten Hopp 028a86
            watch_users.add(user.username)
Karsten Hopp 277ab2
    for watcher in project.watchers:
Karsten Hopp 028a86
        if watcher.watch_issues or watcher.watch_commits:
Karsten Hopp 028a86
            watch_users.add(watcher.user.username)
Karsten Hopp dd024f
    readmefile = get_preferred_readme(tree)
Karsten Hopp dd024f
    if readmefile:
Karsten Hopp dd024f
        name, ext = os.path.splitext(readmefile.name)
Karsten Hopp dd024f
        content = __get_file_in_tree(
Pierre-Yves Chibon 9c2953
            repo_obj, last_commits[0].tree, [readmefile.name]
Pierre-Yves Chibon 9c2953
        ).data
Karsten Hopp dd024f
        readme, safe = pagure.doc_utils.convert_readme(
Pierre-Yves Chibon 9c2953
            content,
Pierre-Yves Chibon 9c2953
            ext,
Karsten Hopp dd024f
            view_file_url=flask.url_for(
Pierre-Yves Chibon 9c2953
                "ui_ns.view_raw_file",
Pierre-Yves Chibon 9c2953
                username=username,
Pierre-Yves Chibon 9c2953
                repo=repo_db.name,
Pierre-Yves Chibon 9c2953
                identifier=branchname,
Pierre-Yves Chibon 9c2953
                filename="",
Pierre-Yves Chibon 9c2953
            ),
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 47950c
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "repo_info.html",
Pierre-Yves Chibon 9c2953
        select="overview",
Pierre-Yves Chibon 4501da
        repo=repo_db,
Pierre-Yves Chibon 47950c
        username=username,
Pierre-Yves Chibon 1e2612
        head=head,
Pierre-Yves Chibon 47950c
        readme=readme,
Pierre-Yves Chibon f77c9a
        safe=safe,
Pierre-Yves Chibon 9c2953
        origin="view_repo",
Ghost-script 966a39
        branchname=branchname,
Pierre-Yves Chibon 47950c
        last_commits=last_commits,
Pierre-Yves Chibon 47950c
        tree=tree,
Karsten Hopp 277ab2
        num_watchers=len(watch_users),
Pierre-Yves Chibon 47950c
    )
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 77bdcd
Ryan Lerch 6d2e06
"""
Pierre-Yves Chibon b130e5
@UI_NS.route('/<repo>/branch/<path:branchname>')</path:branchname></repo>
Pierre-Yves Chibon b130e5
@UI_NS.route('/<namespace>/<repo>/branch/<path:branchname>')</path:branchname></repo></namespace>
Pierre-Yves Chibon b130e5
@UI_NS.route('/fork/<username>/<repo>/branch/<path:branchname>')</path:branchname></repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route('/fork/<username>/<namespace>/<repo>/branch/<path:branchname>')</path:branchname></repo></namespace></username>
Pierre-Yves Chibon 4501da
def view_repo_branch(repo, branchname, username=None, namespace=None):
Pierre-Yves Chibon b8c7ae
    ''' Returns the list of branches in the repo. '''
Pierre-Yves Chibon b8c7ae
Pierre-Yves Chibon 16572e
    repo = flask.g.repo
Pierre-Yves Chibon 16572e
    repo_obj = flask.g.repo_obj
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 05748c
    if branchname not in repo_obj.listall_branches():
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description='Branch not found')
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 47950c
    branch = repo_obj.lookup_branch(branchname)
Ghost-script fdcd15
    if not repo_obj.is_empty and not repo_obj.head_is_unborn:
Ghost-script fdcd15
        head = repo_obj.head.shorthand
Ghost-script fdcd15
    else:
Ghost-script fdcd15
        head = None
Pierre-Yves Chibon 47950c
    cnt = 0
Pierre-Yves Chibon 47950c
    last_commits = []
Pierre-Yves Chibon 29ff0a
    for commit in repo_obj.walk(branch.peel().hex, pygit2.GIT_SORT_NONE):
Pierre-Yves Chibon 47950c
        last_commits.append(commit)
Pierre-Yves Chibon 47950c
        cnt += 1
Pierre-Yves Chibon ce2f5b
        if cnt == 3:
Pierre-Yves Chibon 47950c
            break
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 47950c
    diff_commits = []
Pierre-Yves Chibon 4fcac8
farhaanbukhsh 778e69
    if repo.is_fork and repo.parent:
Patrick Uiterwijk 3f97f6
        parentname = repo.parent.repopath('main')
Pierre-Yves Chibon 2c9e9f
    else:
Patrick Uiterwijk 3f97f6
        parentname = repo.repopath('main')
Pierre-Yves Chibon 2c9e9f
Pierre-Yves Chibon 2c9e9f
    orig_repo = pygit2.Repository(parentname)
Pierre-Yves Chibon 26dbc9
Pierre-Yves Chibon 277040
    tree = None
Pierre-Yves Chibon 53e4c2
    safe = False
Pierre-Yves Chibon 277040
    readme = None
Pierre-Yves Chibon 2c9e9f
    if not repo_obj.is_empty and not orig_repo.is_empty:
Pierre-Yves Chibon 47950c
Ghost-script fdcd15
        if not orig_repo.head_is_unborn:
Ghost-script fdcd15
            compare_branch = orig_repo.lookup_branch(orig_repo.head.shorthand)
Ghost-script fdcd15
        else:
Ghost-script fdcd15
            compare_branch = None
Pierre-Yves Chibon 5c7892
Pierre-Yves Chibon 53e4c2
        commit_list = []
Ghost-script fdcd15
Ghost-script fdcd15
        if compare_branch:
Pierre-Yves Chibon 53e4c2
            commit_list = [
Pierre-Yves Chibon 5c7892
                commit.oid.hex
Pierre-Yves Chibon 5c7892
                for commit in orig_repo.walk(
Pierre-Yves Chibon 29ff0a
                    compare_branch.peel().hex,
Slavek Kabrda 0dd0cd
                    pygit2.GIT_SORT_NONE)
Pierre-Yves Chibon 5c7892
            ]
Pierre-Yves Chibon acb942
Pierre-Yves Chibon 29ff0a
        repo_commit = repo_obj[branch.peel().hex]
Pierre-Yves Chibon 2c9e9f
Pierre-Yves Chibon 2c9e9f
        for commit in repo_obj.walk(
Slavek Kabrda 0dd0cd
                repo_commit.oid.hex, pygit2.GIT_SORT_NONE):
Pierre-Yves Chibon 53e4c2
            if commit.oid.hex in commit_list:
Pierre-Yves Chibon 2c9e9f
                break
Pierre-Yves Chibon 2c9e9f
            diff_commits.append(commit.oid.hex)
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 53e4c2
        tree = sorted(last_commits[0].tree, key=lambda x: x.filemode)
Ryan Lerch 0db4c7
        for i in tree:
Ryan Lerch 0db4c7
            name, ext = os.path.splitext(i.name)
Ryan Lerch 0db4c7
            if name == 'README':
Ryan Lerch 0db4c7
                content = __get_file_in_tree(
Ryan Lerch 0db4c7
                    repo_obj, last_commits[0].tree, [i.name]).data
Ryan Lerch 0db4c7
Ryan Lerch 0db4c7
                readme, safe = pagure.doc_utils.convert_readme(
Ryan Lerch 0db4c7
                    content, ext,
Ryan Lerch 0db4c7
                    view_file_url=flask.url_for(
Pierre-Yves Chibon b130e5
                        'ui_ns.view_raw_file', username=username,
Pierre-Yves Chibon 45aebf
                        namespace=repo.namespace,
Ryan Lerch 0db4c7
                        repo=repo.name, identifier=branchname, filename=''))
Ryan Lerch 0db4c7
Pierre-Yves Chibon 47950c
    return flask.render_template(
Pierre-Yves Chibon 47950c
        'repo_info.html',
Pierre-Yves Chibon 47950c
        select='overview',
Pierre-Yves Chibon 47950c
        repo=repo,
Ghost-script fdcd15
        head=head,
Pierre-Yves Chibon 47950c
        username=username,
Pierre-Yves Chibon 47950c
        branchname=branchname,
Ryan Lerch 3d532e
        origin='view_repo_branch',
Pierre-Yves Chibon 47950c
        last_commits=last_commits,
Ryan Lerch 0db4c7
        tree=tree,
Ryan Lerch 0db4c7
        safe=safe,
Ryan Lerch 0db4c7
        readme=readme,
Pierre-Yves Chibon 47950c
        diff_commits=diff_commits,
Pierre-Yves Chibon 47950c
    )
Ryan Lerch 6d2e06
"""
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 77bdcd
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/commits/")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/commits")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/commits/<path:branchname>")</path:branchname></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/commits/")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/commits")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/commits/<path:branchname>")</path:branchname></repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/commits/")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/commits")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/commits/<path:branchname>")</path:branchname></repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/commits/")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/commits")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/commits/<path:branchname>")</path:branchname></repo></namespace></username>
Pierre-Yves Chibon 4501da
def view_commits(repo, branchname=None, username=None, namespace=None):
Pierre-Yves Chibon c5e646
    """ Displays the commits of the specified repo.
Pierre-Yves Chibon 47950c
    """
Pierre-Yves Chibon 16572e
    repo = flask.g.repo
Pierre-Yves Chibon 16572e
    repo_obj = flask.g.repo_obj
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon d4bfa3
    commit = None
Pierre-Yves Chibon d4bfa3
    branch = None
Pierre-Yves Chibon d4bfa3
    if branchname and branchname in repo_obj.listall_branches():
Pierre-Yves Chibon 47950c
        branch = repo_obj.lookup_branch(branchname)
Pierre-Yves Chibon 91cec1
        commit = branch.peel(pygit2.Commit)
Pierre-Yves Chibon d4bfa3
    elif branchname:
Pierre-Yves Chibon d4bfa3
        try:
Pierre-Yves Chibon d4bfa3
            commit = repo_obj.get(branchname)
Pierre-Yves Chibon d4bfa3
        except (ValueError, TypeError):
Pierre-Yves Chibon d4bfa3
            pass
Pierre-Yves Chibon d4bfa3
Pierre-Yves Chibon 9c2953
        if "refs/tags/%s" % branchname in list(repo_obj.references):
Pierre-Yves Chibon 9c2953
            ref = repo_obj.lookup_reference("refs/tags/%s" % branchname)
Pierre-Yves Chibon 91cec1
            commit = ref.peel(pygit2.Commit)
Pierre-Yves Chibon 6868c1
Pierre-Yves Chibon d4bfa3
        # If we're arriving here from the release page, we may have a Tag
Pierre-Yves Chibon d4bfa3
        # where we expected a commit, in this case, get the actual commit
Pierre-Yves Chibon d4bfa3
        if isinstance(commit, pygit2.Tag):
Pierre-Yves Chibon 91cec1
            commit = commit.peel(pygit2.Commit)
Pierre-Yves Chibon d4bfa3
            branchname = commit.oid.hex
Ghost-script fdcd15
    elif not repo_obj.is_empty and not repo_obj.head_is_unborn:
Ghost-script fdcd15
        branch = repo_obj.lookup_branch(repo_obj.head.shorthand)
Pierre-Yves Chibon 91cec1
        commit = branch.peel(pygit2.Commit)
Pierre-Yves Chibon db30ef
        branchname = branch.branch_name
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 34f46f
    if not repo_obj.is_empty and not repo_obj.head_is_unborn:
Pierre-Yves Chibon 34f46f
        head = repo_obj.head.shorthand
Pierre-Yves Chibon 34f46f
    else:
Pierre-Yves Chibon 34f46f
        head = None
Pierre-Yves Chibon 34f46f
Pierre-Yves Chibon 47950c
    try:
Pierre-Yves Chibon 9c2953
        page = int(flask.request.args.get("page", 1))
Abhijeet Kasurde f4bf50
    except (ValueError, TypeError):
Pierre-Yves Chibon 47950c
        page = 1
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 9c2953
    author = flask.request.args.get("author", None)
Pierre-Yves Chibon 2df018
    author_obj = None
Pierre-Yves Chibon 2df018
    if author:
Pierre-Yves Chibon 2df018
        try:
Pierre-Yves Chibon 930073
            author_obj = pagure.lib.query.get_user(flask.g.session, author)
Abhijeet Kasurde f4bf50
        except pagure.exceptions.PagureException:
Pierre-Yves Chibon 2df018
            pass
Pierre-Yves Chibon 2df018
        if not author_obj:
Pierre-Yves Chibon 9c2953
            flask.flash("No user found for the author: %s" % author, "error")
Pierre-Yves Chibon 2df018
Pierre-Yves Chibon 9c2953
    limit = pagure_config["ITEM_PER_PAGE"]
Pierre-Yves Chibon 47950c
    start = limit * (page - 1)
Pierre-Yves Chibon 47950c
    end = limit * page
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 47950c
    n_commits = 0
Pierre-Yves Chibon 47950c
    last_commits = []
Pierre-Yves Chibon d4bfa3
    if commit:
Slavek Kabrda 0dd0cd
        for commit in repo_obj.walk(commit.hex, pygit2.GIT_SORT_NONE):
Pierre-Yves Chibon 2df018
chocos10 6e4a4f
            # Filters the commits for a user
Pierre-Yves Chibon 2df018
            if author_obj:
Pierre-Yves Chibon 2df018
                tmp = False
Pierre-Yves Chibon 2df018
                for email in author_obj.emails:
Pierre-Yves Chibon 2df018
                    if email.email == commit.author.email:
Pierre-Yves Chibon 2df018
                        tmp = True
Pierre-Yves Chibon 2df018
                        break
Pierre-Yves Chibon 2df018
                if not tmp:
Pierre-Yves Chibon 2df018
                    continue
Pierre-Yves Chibon 2df018
Pierre-Yves Chibon c184e7
            if n_commits >= start and n_commits <= end:
Pierre-Yves Chibon c184e7
                last_commits.append(commit)
Pierre-Yves Chibon c184e7
            n_commits += 1
Pierre-Yves Chibon 47950c
vibhcool eb6723
    total_page = int(ceil(n_commits / float(limit)) if n_commits > 0 else 1)
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 47950c
    diff_commits = []
Ryan Lerch 3fb285
    diff_commits_full = []
Farhaan Bukhsh 72ffb0
    if repo.is_fork and repo.parent:
Patrick Uiterwijk 3f97f6
        parentname = repo.parent.repopath("main")
Pierre-Yves Chibon 2c9e9f
    else:
Patrick Uiterwijk 3f97f6
        parentname = repo.repopath("main")
Pierre-Yves Chibon 26dbc9
Pierre-Yves Chibon 2c9e9f
    orig_repo = pygit2.Repository(parentname)
Pierre-Yves Chibon acb942
Pierre-Yves Chibon 9c2953
    if (
Pierre-Yves Chibon 9c2953
        not repo_obj.is_empty
Pierre-Yves Chibon 9c2953
        and not orig_repo.is_empty
Pierre-Yves Chibon 9c2953
        and len(repo_obj.listall_branches()) > 1
Pierre-Yves Chibon 9c2953
    ):
Pierre-Yves Chibon 2c9e9f
Ghost-script fdcd15
        if not orig_repo.head_is_unborn:
Pierre-Yves Chibon 9c2953
            compare_branch = orig_repo.lookup_branch(orig_repo.head.shorthand)
Ghost-script fdcd15
        else:
Ghost-script fdcd15
            compare_branch = None
Pierre-Yves Chibon 0b2adf
clime 703035
        if compare_branch and branch:
Pierre-Yves Chibon 9c2953
            (
Pierre-Yves Chibon 9c2953
                diff,
Pierre-Yves Chibon 9c2953
                diff_commits_full,
Pierre-Yves Chibon 9c2953
                orig_commit,
Pierre-Yves Chibon 9c2953
            ) = pagure.lib.git.get_diff_info(
Pierre-Yves Chibon 9c2953
                repo_obj,
Pierre-Yves Chibon 9c2953
                orig_repo,
Pierre-Yves Chibon 9c2953
                branch.branch_name,
Pierre-Yves Chibon 9c2953
                compare_branch.branch_name,
Pierre-Yves Chibon 9c2953
            )
clime 703035
clime 703035
            for commit in diff_commits_full:
Pierre-Yves Chibon 1f8aee
                diff_commits.append(commit.oid.hex)
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 47950c
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "commits.html",
Pierre-Yves Chibon 9c2953
        select="commits",
Pierre-Yves Chibon 9c2953
        origin="view_commits",
Pierre-Yves Chibon 47950c
        repo=repo,
Pierre-Yves Chibon 47950c
        username=username,
Pierre-Yves Chibon 34f46f
        head=head,
Pierre-Yves Chibon 47950c
        branchname=branchname,
Pierre-Yves Chibon 47950c
        last_commits=last_commits,
Pierre-Yves Chibon 47950c
        diff_commits=diff_commits,
Ryan Lerch 3fb285
        diff_commits_full=diff_commits_full,
Ryan Lerch 3fb285
        number_of_commits=n_commits,
Pierre-Yves Chibon 47950c
        page=page,
Pierre-Yves Chibon 47950c
        total_page=total_page,
Pierre-Yves Chibon 9c2953
        flag_statuses_labels=json.dumps(pagure_config["FLAG_STATUSES_LABELS"]),
Pierre-Yves Chibon 47950c
    )
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/c/<commit1>..<commit2>/")</commit2></commit1></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/c/<commit1>..<commit2>")</commit2></commit1></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/c/<commit1>..<commit2>/")</commit2></commit1></repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/c/<commit1>..<commit2>")</commit2></commit1></repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/c/<commit1>..<commit2>/")</commit2></commit1></repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/c/<commit1>..<commit2>")</commit2></commit1></repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/c/<commit1>..<commit2>/")</commit2></commit1></repo></namespace></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/c/<commit1>..<commit2>")</commit2></commit1></repo></namespace></username>
Pierre-Yves Chibon 4501da
def compare_commits(repo, commit1, commit2, username=None, namespace=None):
Oliver Gutierrez 38f510
    """ Compares two commits for specified repo
Oliver Gutierrez 38f510
    """
Pierre-Yves Chibon 16572e
    repo = flask.g.repo
Pierre-Yves Chibon 16572e
    repo_obj = flask.g.repo_obj
Oliver Gutierrez 38f510
Oliver Gutierrez 38f510
    if not repo_obj.is_empty and not repo_obj.head_is_unborn:
Oliver Gutierrez 38f510
        head = repo_obj.head.shorthand
Oliver Gutierrez 38f510
    else:
Oliver Gutierrez 38f510
        head = None
Oliver Gutierrez 38f510
Oliver Gutierrez 38f510
    # Check commit1 and commit2 existence
Oliver Gutierrez 38f510
    commit1_obj = repo_obj.get(commit1)
Oliver Gutierrez 38f510
    commit2_obj = repo_obj.get(commit2)
Oliver Gutierrez 38f510
    if commit1_obj is None:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="First commit does not exist")
Oliver Gutierrez 38f510
    if commit2_obj is None:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Last commit does not exist")
Oliver Gutierrez 38f510
Oliver Gutierrez 9e99d9
    # Get commits diff data
Oliver Gutierrez 38f510
    diff = repo_obj.diff(commit1, commit2)
Oliver Gutierrez 38f510
Oliver Gutierrez 9e99d9
    # Get commits list
Oliver Gutierrez 9e99d9
    diff_commits = []
Slavek Kabrda 0dd0cd
    order = pygit2.GIT_SORT_NONE
Oliver Gutierrez 9e99d9
    first_commit = commit1
Oliver Gutierrez 9e99d9
    last_commit = commit2
Oliver Gutierrez 9e99d9
Pierre-Yves Chibon 53e4c2
    commits = [
Pierre-Yves Chibon 9c2953
        commit.oid.hex[: len(first_commit)]
Slavek Kabrda 0dd0cd
        for commit in repo_obj.walk(last_commit, pygit2.GIT_SORT_NONE)
Pierre-Yves Chibon 53e4c2
    ]
Oliver Gutierrez 9e99d9
Oliver Gutierrez 9e99d9
    if first_commit not in commits:
Oliver Gutierrez 9e99d9
        first_commit = commit2
Oliver Gutierrez 9e99d9
        last_commit = commit1
Oliver Gutierrez 9e99d9
Oliver Gutierrez 9e99d9
    for commit in repo_obj.walk(last_commit, order):
Oliver Gutierrez 9e99d9
        diff_commits.append(commit)
Oliver Gutierrez 9e99d9
Pierre-Yves Chibon 9c2953
        if commit.oid.hex == first_commit or commit.oid.hex.startswith(
Pierre-Yves Chibon 9c2953
            first_commit
Pierre-Yves Chibon 9c2953
        ):
Oliver Gutierrez 9e99d9
            break
Oliver Gutierrez 9e99d9
Oliver Gutierrez 9e99d9
    if first_commit == commit2:
Oliver Gutierrez 9e99d9
        diff_commits.reverse()
Oliver Gutierrez 9e99d9
Oliver Gutierrez 38f510
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "repo_comparecommits.html",
Pierre-Yves Chibon 9c2953
        select="commits",
Pierre-Yves Chibon 9c2953
        origin="compare_commits",
Oliver Gutierrez 38f510
        repo=repo,
Oliver Gutierrez 38f510
        username=username,
Oliver Gutierrez 38f510
        head=head,
Oliver Gutierrez 38f510
        commit1=commit1,
Oliver Gutierrez 38f510
        commit2=commit2,
Oliver Gutierrez 38f510
        diff=diff,
Oliver Gutierrez 38f510
        diff_commits=diff_commits,
Oliver Gutierrez 38f510
    )
Oliver Gutierrez 38f510
Oliver Gutierrez 38f510
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/blob/<path:identifier>/f/<path:filename>")</path:filename></path:identifier></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/blob/<path:identifier>/f/<path:filename>")</path:filename></path:identifier></repo></namespace>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/blob/<path:identifier>/f/<path:filename>"</path:filename></path:identifier></repo></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/blob/<path:identifier>/f/"</path:identifier></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    "<path:filename>"</path:filename>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 4501da
def view_file(repo, identifier, filename, username=None, namespace=None):
Pierre-Yves Chibon 47950c
    """ Displays the content of a file or a tree for the specified repo.
Pierre-Yves Chibon 47950c
    """
Pierre-Yves Chibon 16572e
    repo = flask.g.repo
Pierre-Yves Chibon 16572e
    repo_obj = flask.g.repo_obj
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon bc6cc4
    if repo_obj.is_empty:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Empty repo cannot have a file")
Pierre-Yves Chibon bc6cc4
Pierre-Yves Chibon 47950c
    if identifier in repo_obj.listall_branches():
Pierre-Yves Chibon 47950c
        branchname = identifier
Pierre-Yves Chibon 47950c
        branch = repo_obj.lookup_branch(identifier)
Pierre-Yves Chibon 91cec1
        commit = branch.peel(pygit2.Commit)
Pierre-Yves Chibon 47950c
    else:
Pierre-Yves Chibon 47950c
        try:
Pierre-Yves Chibon 47950c
            commit = repo_obj.get(identifier)
Pierre-Yves Chibon 47950c
            branchname = identifier
Pierre-Yves Chibon 47950c
        except ValueError:
Pierre-Yves Chibon 9c2953
            if "master" not in repo_obj.listall_branches():
Pierre-Yves Chibon c6cc5c
                flask.abort(404, description="Branch not found")
Pierre-Yves Chibon 47950c
            # If it's not a commit id then it's part of the filename
Pierre-Yves Chibon 47950c
            commit = repo_obj[repo_obj.head.target]
Pierre-Yves Chibon 9c2953
            branchname = "master"
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 5bb964
    if isinstance(commit, pygit2.Tag):
Pierre-Yves Chibon 91cec1
        commit = commit.peel(pygit2.Commit)
Pierre-Yves Chibon 5bb964
Pierre-Yves Chibon fec0c5
    tree = None
Pierre-Yves Chibon fec0c5
    if isinstance(commit, pygit2.Tree):
Pierre-Yves Chibon fec0c5
        tree = commit
Pierre-Yves Chibon fec0c5
    elif isinstance(commit, pygit2.Commit):
Pierre-Yves Chibon fec0c5
        tree = commit.tree
Pierre-Yves Chibon fec0c5
Pierre-Yves Chibon fec0c5
    if tree and commit and not isinstance(commit, pygit2.Blob):
Pierre-Yves Chibon f74707
        content = __get_file_in_tree(
Pierre-Yves Chibon 9c2953
            repo_obj, tree, filename.split("/"), bail_on_tree=True
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon f74707
        if not content:
Pierre-Yves Chibon c6cc5c
            flask.abort(404, description="File not found")
Pierre-Yves Chibon f74707
        content = repo_obj[content.oid]
Pierre-Yves Chibon f74707
    else:
Pierre-Yves Chibon f74707
        content = commit
Pierre-Yves Chibon f74707
Pierre-Yves Chibon 7c128e
    if not content:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="File not found")
Pierre-Yves Chibon 7c128e
Ryan Lerch 4c1bc5
    readme = None
Ryan Lerch 4c1bc5
    safe = False
Ryan Lerch 4c1bc5
    readme_ext = None
Pierre-Yves Chibon a443ef
    headers = {}
Patrick Uiterwijk 71124e
    huge = False
Patrick Uiterwijk 71124e
Patrick Uiterwijk 71124e
    isbinary = False
Pierre-Yves Chibon 9c2953
    if "data" in dir(content):
Patrick Uiterwijk 71124e
        isbinary = is_binary_string(content.data)
Ryan Lerch 4c1bc5
Pierre-Yves Chibon 47950c
    if isinstance(content, pygit2.Blob):
Pierre-Yves Chibon 9c2953
        rawtext = is_true(flask.request.args.get("text"))
Pierre-Yves Chibon 9c2953
        ext = filename[filename.rfind(".") :]
Pierre-Yves Chibon c9a40f
        if ext in (
Pierre-Yves Chibon 9c2953
            ".gif",
Pierre-Yves Chibon 9c2953
            ".png",
Pierre-Yves Chibon 9c2953
            ".bmp",
Pierre-Yves Chibon 9c2953
            ".tif",
Pierre-Yves Chibon 9c2953
            ".tiff",
Pierre-Yves Chibon 9c2953
            ".jpg",
Pierre-Yves Chibon 9c2953
            ".jpeg",
Pierre-Yves Chibon 9c2953
            ".ppm",
Pierre-Yves Chibon 9c2953
            ".pnm",
Pierre-Yves Chibon 9c2953
            ".pbm",
Pierre-Yves Chibon 9c2953
            ".pgm",
Pierre-Yves Chibon 9c2953
            ".webp",
Pierre-Yves Chibon 9c2953
            ".ico",
Pierre-Yves Chibon 9c2953
        ):
Pierre-Yves Chibon c9a40f
            try:
Aurélien Bompard 831553
                Image.open(BytesIO(content.data))
Pierre-Yves Chibon 9c2953
                output_type = "image"
Pierre-Yves Chibon c9a40f
            except IOError as err:
Pierre-Yves Chibon 9c2953
                _log.debug("Failed to load image %s, error: %s", filename, err)
Pierre-Yves Chibon 9c2953
                output_type = "binary"
Pierre-Yves Chibon 9c2953
        elif ext in (".rst", ".mk", ".md", ".markdown") and not rawtext:
Yves Martin 358b76
            content, safe = pagure.doc_utils.convert_readme(content.data, ext)
Pierre-Yves Chibon 9c2953
            output_type = "markup"
Pierre-Yves Chibon 9c2953
        elif "data" in dir(content) and not isbinary:
Pierre-Yves Chibon e81494
            file_content = None
Pierre-Yves Chibon 65d40a
            try:
Pierre-Yves Chibon 0c0047
                file_content = encoding_utils.decode(
Pierre-Yves Chibon 9c2953
                    ktc.to_bytes(content.data)
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 65d40a
            except pagure.exceptions.PagureException:
Pierre-Yves Chibon 65d40a
                # We cannot decode the file, so let's pretend it's a binary
Pierre-Yves Chibon 65d40a
                # file and let the user download it instead of displaying
Pierre-Yves Chibon 65d40a
                # it.
Pierre-Yves Chibon 9c2953
                output_type = "binary"
Pierre-Yves Chibon 100456
            if file_content is not None:
Pierre-Yves Chibon 9c2953
                output_type = "file"
Pierre-Yves Chibon 9c2953
                content = content.data.decode("utf-8")
Farhaan Bukhsh 9687ce
            else:
Pierre-Yves Chibon 9c2953
                output_type = "binary"
Patrick Uiterwijk 71124e
        elif not isbinary:
Pierre-Yves Chibon 9c2953
            output_type = "file"
Patrick Uiterwijk 71124e
            huge = True
Patrick Uiterwijk 71124e
            safe = False
Pierre-Yves Chibon 9c2953
            content = content.data.decode("utf-8")
Pierre-Yves Chibon c9a40f
        else:
Pierre-Yves Chibon 9c2953
            output_type = "binary"
Pierre-Yves Chibon c10f7e
    elif isinstance(content, pygit2.Commit):
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="File not found")
Pierre-Yves Chibon 47950c
    else:
Pierre-Yves Chibon 47950c
        content = sorted(content, key=lambda x: x.filemode)
Ryan Lerch 4c1bc5
        for i in content:
Ryan Lerch 4c1bc5
            name, ext = os.path.splitext(i.name)
Aurélien Bompard 619e2a
            if not isinstance(name, six.text_type):
Aurélien Bompard 619e2a
                name = name.decode("utf-8")
Pierre-Yves Chibon 9c2953
            if name == "README":
Ryan Lerch 4c1bc5
                readme_file = __get_file_in_tree(
Pierre-Yves Chibon 9c2953
                    repo_obj, content, [i.name]
Pierre-Yves Chibon 9c2953
                ).data
Ryan Lerch 4c1bc5
Ryan Lerch 4c1bc5
                readme, safe = pagure.doc_utils.convert_readme(
Pierre-Yves Chibon 9c2953
                    readme_file, ext
Pierre-Yves Chibon 9c2953
                )
Ryan Lerch 4c1bc5
Ryan Lerch 4c1bc5
                readme_ext = ext
Pierre-Yves Chibon 9c2953
        output_type = "tree"
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 9c2953
    if output_type == "binary":
Pierre-Yves Chibon 9c2953
        headers[str("Content-Disposition")] = "attachment"
Pierre-Yves Chibon bbcc6a
Pierre-Yves Chibon 9c2953
    return flask.Response(
Pierre-Yves Chibon 9c2953
        flask.stream_with_context(
Pierre-Yves Chibon 9c2953
            stream_template(
Pierre-Yves Chibon 9c2953
                flask.current_app,
Pierre-Yves Chibon 9c2953
                "file.html",
Pierre-Yves Chibon 9c2953
                select="tree",
Pierre-Yves Chibon 9c2953
                repo=repo,
Pierre-Yves Chibon 9c2953
                origin="view_file",
Pierre-Yves Chibon 9c2953
                username=username,
Pierre-Yves Chibon 9c2953
                branchname=branchname,
Pierre-Yves Chibon 9c2953
                filename=filename,
Pierre-Yves Chibon 9c2953
                content=content,
Pierre-Yves Chibon 9c2953
                output_type=output_type,
Pierre-Yves Chibon 9c2953
                readme=readme,
Pierre-Yves Chibon 9c2953
                readme_ext=readme_ext,
Pierre-Yves Chibon 9c2953
                safe=safe,
Pierre-Yves Chibon 9c2953
                huge=huge,
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 9c2953
        ),
Pierre-Yves Chibon bbcc6a
        200,
Pierre-Yves Chibon 9c2953
        headers,
Pierre-Yves Chibon 47950c
    )
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/raw/<path:identifier>")</path:identifier></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/raw/<path:identifier>")</path:identifier></repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/raw/<path:identifier>/f/<path:filename>")</path:filename></path:identifier></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/raw/<path:identifier>/f/<path:filename>")</path:filename></path:identifier></repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/raw/<path:identifier>")</path:identifier></repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/raw/<path:identifier>")</path:identifier></repo></namespace></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/raw/<path:identifier>/f/<path:filename>")</path:filename></path:identifier></repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/raw/<path:identifier>/f/"</path:identifier></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    "<path:filename>"</path:filename>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 4501da
def view_raw_file(
Pierre-Yves Chibon 9c2953
    repo, identifier, filename=None, username=None, namespace=None
Pierre-Yves Chibon 9c2953
):
Johan Cwiklinski 002118
    """ Displays the raw content of a file of a commit for the specified repo.
Johan Cwiklinski 740adc
    """
Pierre-Yves Chibon 16572e
    repo_obj = flask.g.repo_obj
Johan Cwiklinski 740adc
Pierre-Yves Chibon 346039
    if repo_obj.is_empty:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Empty repo cannot have a file")
Pierre-Yves Chibon 346039
Johan Cwiklinski 740adc
    if identifier in repo_obj.listall_branches():
Johan Cwiklinski 740adc
        branch = repo_obj.lookup_branch(identifier)
Pierre-Yves Chibon 91cec1
        commit = branch.peel(pygit2.Commit)
Johan Cwiklinski 740adc
    else:
Johan Cwiklinski 740adc
        try:
Johan Cwiklinski 740adc
            commit = repo_obj.get(identifier)
Johan Cwiklinski 740adc
        except ValueError:
Pierre-Yves Chibon 9c2953
            if "master" not in repo_obj.listall_branches():
Pierre-Yves Chibon c6cc5c
                flask.abort(404, description="Branch not found")
Johan Cwiklinski 740adc
            # If it's not a commit id then it's part of the filename
Johan Cwiklinski 740adc
            commit = repo_obj[repo_obj.head.target]
Johan Cwiklinski 740adc
Pierre-Yves Chibon 8da4af
    if not commit:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Commit %s not found" % (identifier))
Pierre-Yves Chibon 8da4af
Pierre-Yves Chibon 5bb964
    if isinstance(commit, pygit2.Tag):
Pierre-Yves Chibon 91cec1
        commit = commit.peel(pygit2.Commit)
Pierre-Yves Chibon 5bb964
Johan Cwiklinski 002118
    if filename:
Pierre-Yves Chibon 5500b2
        if isinstance(commit, pygit2.Blob):
Pierre-Yves Chibon 5500b2
            content = commit
Pierre-Yves Chibon 5500b2
        else:
Pierre-Yves Chibon 5500b2
            content = __get_file_in_tree(
Pierre-Yves Chibon 9c2953
                repo_obj, commit.tree, filename.split("/"), bail_on_tree=True
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 274dbb
        if not content or isinstance(content, pygit2.Tree):
Pierre-Yves Chibon c6cc5c
            flask.abort(404, description="File not found")
Johan Cwiklinski 002118
Johan Cwiklinski 002118
        data = repo_obj[content.oid].data
Johan Cwiklinski 002118
    else:
Johan Cwiklinski 002118
        if commit.parents:
Carlos Mogas da Silva dbd6dd
            # We need to take this not so nice road to ensure that the
Carlos Mogas da Silva dbd6dd
            # identifier retrieved from the URL is actually valid
Pierre-Yves Chibon 4ea07d
            try:
Pierre-Yves Chibon 9c2953
                parent = repo_obj.revparse_single("%s^" % identifier)
Pierre-Yves Chibon 4ea07d
                diff = repo_obj.diff(parent, commit)
Pierre-Yves Chibon 4ea07d
            except (KeyError, ValueError):
Pierre-Yves Chibon c6cc5c
                flask.abort(404, description="Identifier not found")
Johan Cwiklinski 002118
        else:
Johan Cwiklinski 002118
            # First commit in the repo
Johan Cwiklinski 002118
            diff = commit.tree.diff_to_tree(swap=True)
Johan Cwiklinski 002118
        data = diff.patch
Johan Cwiklinski 740adc
Pierre-Yves Chibon 42708f
    if not data:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="No content found")
Pierre-Yves Chibon 42708f
Shengjing Zhu c28196
    return (data, 200, pagure.lib.mimetype.get_type_headers(filename, data))
Johan Cwiklinski 740adc
Johan Cwiklinski 740adc
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/blame/<path:filename>")</path:filename></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/blame/<path:filename>")</path:filename></repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/blame/<path:filename>")</path:filename></repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/blame/<path:filename>")</path:filename></repo></namespace></username>
Pierre-Yves Chibon 833d1f
def view_blame_file(repo, filename, username=None, namespace=None):
Pierre-Yves Chibon 833d1f
    """ Displays the blame of a file or a tree for the specified repo.
Pierre-Yves Chibon 833d1f
    """
Pierre-Yves Chibon 833d1f
    repo = flask.g.repo
Pierre-Yves Chibon 833d1f
    repo_obj = flask.g.repo_obj
Pierre-Yves Chibon 833d1f
Julen Landa Alustiza c9c857
    branchname = flask.request.args.get("identifier")
Pierre-Yves Chibon 833d1f
Julen Landa Alustiza c9c857
    if repo_obj.is_empty:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Empty repo cannot have a file")
Pierre-Yves Chibon 833d1f
Julen Landa Alustiza c9c857
    if branchname is None:
Julen Landa Alustiza c9c857
        if repo_obj.head_is_unborn:
Julen Landa Alustiza c9c857
            flask.abort(
Julen Landa Alustiza c9c857
                404, description="Identifier is mandatory on unborn HEAD repos"
Julen Landa Alustiza c9c857
            )
Julen Landa Alustiza c9c857
Julen Landa Alustiza c9c857
        branchname = repo_obj.head.shorthand
Julen Landa Alustiza c9c857
        commit = repo_obj[repo_obj.head.target]
Julen Landa Alustiza c9c857
Pierre-Yves Chibon 8655c1
    else:
Julen Landa Alustiza c9c857
        if branchname in repo_obj.listall_branches():
Julen Landa Alustiza c9c857
            branch = repo_obj.lookup_branch(branchname)
Julen Landa Alustiza c9c857
            commit = branch.peel(pygit2.Commit)
Julen Landa Alustiza c9c857
        elif branchname in pagure.lib.git.get_git_tags(repo):
Julen Landa Alustiza c9c857
            branch = repo_obj.lookup_reference(
Julen Landa Alustiza c9c857
                "refs/tags/{}".format(branchname)
Julen Landa Alustiza c9c857
            )
Julen Landa Alustiza c9c857
            commit = branch.peel(pygit2.Commit)
Julen Landa Alustiza c9c857
        else:
Julen Landa Alustiza c9c857
            try:
Julen Landa Alustiza c9c857
                commit = repo_obj[branchname]
Julen Landa Alustiza c9c857
            except ValueError:
Julen Landa Alustiza c9c857
                flask.abort(
Julen Landa Alustiza c9c857
                    404, description="Cannot find specified identifier"
Julen Landa Alustiza c9c857
                )
Pierre-Yves Chibon 8655c1
Pierre-Yves Chibon 0e35e9
    if isinstance(commit, pygit2.Tag):
Pierre-Yves Chibon 91cec1
        commit = commit.peel(pygit2.Commit)
Pierre-Yves Chibon 0e35e9
Pierre-Yves Chibon 833d1f
    content = __get_file_in_tree(
Pierre-Yves Chibon 9c2953
        repo_obj, commit.tree, filename.split("/"), bail_on_tree=True
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 833d1f
    if not content:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="File not found")
Pierre-Yves Chibon 833d1f
Pierre-Yves Chibon 833d1f
    if not isinstance(content, pygit2.Blob):
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="File not found")
Pierre-Yves Chibon 833d1f
    if is_binary_string(content.data):
Pierre-Yves Chibon c6cc5c
        flask.abort(400, description="Binary files cannot be blamed")
Pierre-Yves Chibon 833d1f
Pierre-Yves Chibon 65d40a
    try:
Pierre-Yves Chibon 65d40a
        content = encoding_utils.decode(content.data)
Pierre-Yves Chibon 65d40a
    except pagure.exceptions.PagureException:
Pierre-Yves Chibon 65d40a
        # We cannot decode the file, so bail but warn the admins
Pierre-Yves Chibon 9c2953
        _log.exception("File could not be decoded")
Pierre-Yves Chibon c6cc5c
        flask.abort(500, description="File could not be decoded")
Pierre-Yves Chibon 65d40a
Pierre-Yves Chibon 8655c1
    blame = repo_obj.blame(filename, newest_commit=commit.oid.hex)
Pierre-Yves Chibon 833d1f
Pierre-Yves Chibon 833d1f
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "blame.html",
Pierre-Yves Chibon 9c2953
        select="tree",
Pierre-Yves Chibon 833d1f
        repo=repo,
Pierre-Yves Chibon 9c2953
        origin="view_file",
Pierre-Yves Chibon 833d1f
        username=username,
Pierre-Yves Chibon 833d1f
        filename=filename,
Pierre-Yves Chibon 833d1f
        branchname=branchname,
Pierre-Yves Chibon 833d1f
        content=content,
Pierre-Yves Chibon 9c2953
        output_type="blame",
Pierre-Yves Chibon 833d1f
        blame=blame,
Pierre-Yves Chibon 833d1f
    )
Pierre-Yves Chibon 833d1f
Pierre-Yves Chibon 833d1f
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/c/<commitid>/")</commitid></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/c/<commitid>")</commitid></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/c/<commitid>/")</commitid></repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/c/<commitid>")</commitid></repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/c/<commitid>/")</commitid></repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/c/<commitid>")</commitid></repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/c/<commitid>/")</commitid></repo></namespace></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/c/<commitid>")</commitid></repo></namespace></username>
Pierre-Yves Chibon 4501da
def view_commit(repo, commitid, username=None, namespace=None):
Pierre-Yves Chibon 47950c
    """ Render a commit in a repo
Pierre-Yves Chibon 47950c
    """
Pierre-Yves Chibon 16572e
    repo = flask.g.repo
Pierre-Yves Chibon d49b8c
    if not repo:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Project not found")
Pierre-Yves Chibon d49b8c
Pierre-Yves Chibon 16572e
    repo_obj = flask.g.repo_obj
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 9c2953
    branchname = flask.request.args.get("branch", None)
Vivek Anand 1ff64e
Pierre-Yves Chibon 9c2953
    splitview = flask.request.args.get("splitview", False)
Ryan Lerch e2f045
Pierre-Yves Chibon 9c2953
    if "splitview" in flask.request.args:
Ryan Lerch e2f045
        splitview = True
Ryan Lerch e2f045
    else:
Ryan Lerch e2f045
        splitview = False
Ryan Lerch e2f045
Vivek Anand 1ff64e
    if branchname and branchname not in repo_obj.listall_branches():
Vivek Anand d3485c
        branchname = None
Vivek Anand 1ff64e
Pierre-Yves Chibon 47950c
    try:
Pierre-Yves Chibon 47950c
        commit = repo_obj.get(commitid)
Pierre-Yves Chibon 47950c
    except ValueError:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Commit not found")
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 0a3e63
    if commit is None:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Commit not found")
Pierre-Yves Chibon 0a3e63
Pierre-Yves Chibon 66b80e
    if isinstance(commit, pygit2.Blob):
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Commit not found")
Pierre-Yves Chibon 66b80e
Pierre-Yves Chibon 47950c
    if commit.parents:
Carlos Mogas da Silva dbd6dd
        diff = repo_obj.diff(commit.parents[0], commit)
Pierre-Yves Chibon 47950c
    else:
Pierre-Yves Chibon 47950c
        # First commit in the repo
Pierre-Yves Chibon 47950c
        diff = commit.tree.diff_to_tree(swap=True)
Pierre-Yves Chibon 47950c
Ryan Lerch e2f045
    if diff:
Ryan Lerch e2f045
        diff.find_similar()
Ryan Lerch e2f045
Pierre-Yves Chibon 47950c
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "commit.html",
Pierre-Yves Chibon 9c2953
        select="commits",
Pierre-Yves Chibon 47950c
        repo=repo,
Vivek Anand 1ff64e
        branchname=branchname,
Pierre-Yves Chibon 47950c
        username=username,
Pierre-Yves Chibon 47950c
        commitid=commitid,
Pierre-Yves Chibon 47950c
        commit=commit,
Pierre-Yves Chibon 47950c
        diff=diff,
Ryan Lerch e2f045
        splitview=splitview,
Pierre-Yves Chibon 930073
        flags=pagure.lib.query.get_commit_flag(
Pierre-Yves Chibon 930073
            flask.g.session, repo, commitid
Pierre-Yves Chibon 930073
        ),
Pierre-Yves Chibon 47950c
    )
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/c/<commitid>.patch")</commitid></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/c/<commitid>.patch")</commitid></repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/c/<commitid>.patch")</commitid></repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/c/<commitid>.patch")</commitid></repo></namespace></username>
Pierre-Yves Chibon 4501da
def view_commit_patch(repo, commitid, username=None, namespace=None):
Pierre-Yves Chibon 74eefa
    """ Render a commit in a repo as patch
Pierre-Yves Chibon 74eefa
    """
Pierre-Yves Chibon 4b90cc
    return view_commit_patch_or_diff(
Pierre-Yves Chibon 9c2953
        repo, commitid, username, namespace, diff=False
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 4b90cc
Pierre-Yves Chibon 4b90cc
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/c/<commitid>.diff")</commitid></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/c/<commitid>.diff")</commitid></repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/c/<commitid>.diff")</commitid></repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/c/<commitid>.diff")</commitid></repo></namespace></username>
Pierre-Yves Chibon 4b90cc
def view_commit_diff(repo, commitid, username=None, namespace=None):
Pierre-Yves Chibon 4b90cc
    """ Render a commit in a repo as diff
Pierre-Yves Chibon 4b90cc
    """
Ryan Lerch e2f045
Pierre-Yves Chibon 9c2953
    is_js = is_true(flask.request.args.get("js"))
Ryan Lerch e2f045
Pierre-Yves Chibon 4b90cc
    return view_commit_patch_or_diff(
Pierre-Yves Chibon 9c2953
        repo, commitid, username, namespace, diff=True, is_js=is_js
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 4b90cc
Pierre-Yves Chibon 4b90cc
Pierre-Yves Chibon 4b90cc
def view_commit_patch_or_diff(
Pierre-Yves Chibon 9c2953
    repo, commitid, username=None, namespace=None, diff=False, is_js=False
Pierre-Yves Chibon 9c2953
):
Pierre-Yves Chibon 4b90cc
    """ Renders a commit either as a patch or as a diff. """
Pierre-Yves Chibon 4b90cc
Pierre-Yves Chibon 16572e
    repo_obj = flask.g.repo_obj
Pierre-Yves Chibon 74eefa
Ryan Lerch e2f045
    if is_js:
Pierre-Yves Chibon 9c2953
        errorresponse = flask.jsonify(
Pierre-Yves Chibon 9c2953
            {"code": "ERROR", "message": "Commit not found"}
Pierre-Yves Chibon 9c2953
        )
Ryan Lerch e2f045
        errorresponse.status_code = 404
Ryan Lerch e2f045
Pierre-Yves Chibon 74eefa
    try:
Pierre-Yves Chibon 74eefa
        commit = repo_obj.get(commitid)
Pierre-Yves Chibon 74eefa
    except ValueError:
Ryan Lerch e2f045
        if is_js:
Ryan Lerch e2f045
            return errorresponse
Ryan Lerch e2f045
        else:
Pierre-Yves Chibon c6cc5c
            flask.abort(404, description="Commit not found")
Pierre-Yves Chibon 2f0596
Pierre-Yves Chibon 2f0596
    if commit is None:
Ryan Lerch e2f045
        if is_js:
Ryan Lerch e2f045
            return errorresponse
Ryan Lerch e2f045
        else:
Pierre-Yves Chibon c6cc5c
            flask.abort(404, description="Commit not found")
Ryan Lerch e2f045
Ryan Lerch e2f045
    if is_js:
Pierre-Yves Chibon 86e455
        patches = pagure.lib.git.commit_to_patch(
Pierre-Yves Chibon 9c2953
            repo_obj, commit, diff_view=True, find_similar=True, separated=True
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 86e455
Pierre-Yves Chibon 86e455
        diffs = {}
Pierre-Yves Chibon 86e455
        for idx, patch in enumerate(patches):
Pierre-Yves Chibon 86e455
            diffs[idx + 1] = patch
Ryan Lerch e2f045
Ryan Lerch e2f045
        return flask.jsonify(diffs)
Ryan Lerch e2f045
    else:
Ryan Lerch e2f045
        patch = pagure.lib.git.commit_to_patch(
Pierre-Yves Chibon 9c2953
            repo_obj, commit, diff_view=diff
Pierre-Yves Chibon 9c2953
        )
Ryan Lerch e2f045
        return flask.Response(patch, content_type="text/plain;charset=UTF-8")
Pierre-Yves Chibon 74eefa
Pierre-Yves Chibon 74eefa
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/tree/")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/tree")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/tree/")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/tree")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/tree/<path:identifier>")</path:identifier></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/tree/<path:identifier>")</path:identifier></repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/tree/")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/tree")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/tree/")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/tree")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/tree/<path:identifier>")</path:identifier></repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/tree/<path:identifier>")</path:identifier></repo></namespace></username>
Pierre-Yves Chibon 4501da
def view_tree(repo, identifier=None, username=None, namespace=None):
Pierre-Yves Chibon 47950c
    """ Render the tree of the repo
Pierre-Yves Chibon 47950c
    """
Pierre-Yves Chibon 16572e
    repo = flask.g.repo
Pierre-Yves Chibon 16572e
    repo_obj = flask.g.repo_obj
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon c184e7
    branchname = None
Pierre-Yves Chibon c184e7
    content = None
Pierre-Yves Chibon c184e7
    output_type = None
Pierre-Yves Chibon d27f13
    commit = None
Pierre-Yves Chibon 0359fe
    readme = None
Pierre-Yves Chibon 0359fe
    safe = False
Pierre-Yves Chibon 0359fe
    readme_ext = None
Pierre-Yves Chibon c184e7
    if not repo_obj.is_empty:
Pierre-Yves Chibon c184e7
        if identifier in repo_obj.listall_branches():
Pierre-Yves Chibon 47950c
            branchname = identifier
Pierre-Yves Chibon c184e7
            branch = repo_obj.lookup_branch(identifier)
Pierre-Yves Chibon 91cec1
            commit = branch.peel(pygit2.Commit)
Pierre-Yves Chibon c184e7
        else:
Pierre-Yves Chibon c184e7
            try:
Pierre-Yves Chibon c184e7
                commit = repo_obj.get(identifier)
Pierre-Yves Chibon c184e7
                branchname = identifier
Pierre-Yves Chibon c184e7
            except (ValueError, TypeError):
Pierre-Yves Chibon c184e7
                # If it's not a commit id then it's part of the filename
Vivek Anand 692787
                if not repo_obj.head_is_unborn:
Vivek Anand 692787
                    branchname = repo_obj.head.shorthand
Pierre-Yves Chibon cef492
                    commit = repo_obj[repo_obj.head.target]
Pierre-Yves Chibon 0fb867
                    if identifier:
Pierre-Yves Chibon 0fb867
                        flask.flash(
Pierre-Yves Chibon 0fb867
                            "'%s' not found in the git repository, going back "
Pierre-Yves Chibon 0fb867
                            "to: %s" % (identifier, branchname),
Pierre-Yves Chibon 0fb867
                            "error",
Pierre-Yves Chibon 0fb867
                        )
Pierre-Yves Chibon b4fa1c
        # If we're arriving here from the release page, we may have a Tag
Pierre-Yves Chibon b4fa1c
        # where we expected a commit, in this case, get the actual commit
Pierre-Yves Chibon b4fa1c
        if isinstance(commit, pygit2.Tag):
Pierre-Yves Chibon 91cec1
            commit = commit.peel(pygit2.Commit)
Pierre-Yves Chibon d4bfa3
            branchname = commit.oid.hex
Pierre-Yves Chibon c184e7
Pierre-Yves Chibon a83847
        if commit and not isinstance(commit, pygit2.Blob):
Pierre-Yves Chibon d27f13
            content = sorted(commit.tree, key=lambda x: x.filemode)
Ryan Lerch 4c1bc5
            for i in commit.tree:
Ryan Lerch 4c1bc5
                name, ext = os.path.splitext(i.name)
Pierre-Yves Chibon 9c2953
                if name == "README":
Ryan Lerch 4c1bc5
                    readme_file = __get_file_in_tree(
Pierre-Yves Chibon 9c2953
                        repo_obj, commit.tree, [i.name]
Pierre-Yves Chibon 9c2953
                    ).data
Ryan Lerch 4c1bc5
Ryan Lerch 4c1bc5
                    readme, safe = pagure.doc_utils.convert_readme(
Pierre-Yves Chibon 9c2953
                        readme_file, ext
Pierre-Yves Chibon 9c2953
                    )
Ryan Lerch 4c1bc5
Ryan Lerch 4c1bc5
                    readme_ext = ext
Pierre-Yves Chibon 9c2953
        output_type = "tree"
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 47950c
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "file.html",
Pierre-Yves Chibon 9c2953
        select="tree",
Pierre-Yves Chibon 9c2953
        origin="view_tree",
Pierre-Yves Chibon 47950c
        repo=repo,
Pierre-Yves Chibon 47950c
        username=username,
Pierre-Yves Chibon 47950c
        branchname=branchname,
Pierre-Yves Chibon 9c2953
        filename="",
Pierre-Yves Chibon 47950c
        content=content,
Pierre-Yves Chibon 47950c
        output_type=output_type,
Ryan Lerch 4c1bc5
        readme=readme,
Ryan Lerch 4c1bc5
        readme_ext=readme_ext,
Ryan Lerch 4c1bc5
        safe=safe,
Pierre-Yves Chibon 47950c
    )
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 47950c
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/releases/")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/releases")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/releases/")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/releases")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/releases/")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/releases")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/releases/")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/releases")</repo></namespace></username>
Pierre-Yves Chibon 4501da
def view_tags(repo, username=None, namespace=None):
Pierre-Yves Chibon f63ab5
    """ Presents all the tags of the project.
Pierre-Yves Chibon f63ab5
    """
Pierre-Yves Chibon 16572e
    repo = flask.g.repo
Pierre-Yves Chibon f63ab5
    tags = pagure.lib.git.get_git_tags_objects(repo)
Pierre-Yves Chibon 0fcf17
Slavek Kabrda c3aef6
    upload_folder_path = pagure_config["UPLOAD_FOLDER_PATH"] or ""
Pierre-Yves Chibon 9c2953
    pagure_checksum = os.path.exists(
Patrick Uiterwijk 3f97f6
        os.path.join(upload_folder_path, repo.fullname, "CHECKSUMS")
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 36309a
Pierre-Yves Chibon f63ab5
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "releases.html",
Pierre-Yves Chibon 9c2953
        select="tags",
Pierre-Yves Chibon f63ab5
        username=username,
Pierre-Yves Chibon f63ab5
        repo=repo,
Clement Verna c99c18
        tags=tags,
Pierre-Yves Chibon 36309a
        pagure_checksum=pagure_checksum,
Pierre-Yves Chibon cda607
    )
Pierre-Yves Chibon cda607
Pierre-Yves Chibon 77bdcd
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/branches/")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/branches")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/branches/")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/branches")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/branches/")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/branches")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/branches/")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/branches")</repo></namespace></username>
Ryan Lerch 6d2e06
def view_branches(repo, username=None, namespace=None):
Ryan Lerch 6d2e06
    """ Branches
Ryan Lerch 6d2e06
    """
Ryan Lerch 6d2e06
    repo_db = flask.g.repo
Ryan Lerch 6d2e06
    repo_obj = flask.g.repo_obj
Ryan Lerch 6d2e06
Ryan Lerch 6d2e06
    if not repo_obj.is_empty and not repo_obj.head_is_unborn:
Ryan Lerch 6d2e06
        head = repo_obj.head.shorthand
Ryan Lerch 6d2e06
    else:
Ryan Lerch 6d2e06
        head = None
Ryan Lerch 6d2e06
Ryan Lerch 6d2e06
    if not repo_obj.is_empty and not repo_obj.head_is_unborn:
Ryan Lerch 6d2e06
        branchname = repo_obj.head.shorthand
Ryan Lerch 6d2e06
    else:
Ryan Lerch 6d2e06
        branchname = None
Ryan Lerch 6d2e06
Ryan Lerch 6d2e06
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "repo_branches.html",
Pierre-Yves Chibon 9c2953
        select="branches",
Ryan Lerch 6d2e06
        repo=repo_db,
Ryan Lerch 6d2e06
        username=username,
Ryan Lerch 6d2e06
        head=head,
Pierre-Yves Chibon 9c2953
        origin="view_repo",
Ryan Lerch 6d2e06
        branchname=branchname,
Ryan Lerch 6d2e06
    )
Ryan Lerch 6d2e06
Ryan Lerch 321fde
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/forks/")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/forks")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/forks/")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/forks")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/forks/")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/forks")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/forks/")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/forks")</repo></namespace></username>
Ryan Lerch 583102
def view_forks(repo, username=None, namespace=None):
Ryan Lerch 583102
    """ Forks
Ryan Lerch 583102
    """
Ryan Lerch 321fde
Ryan Lerch 583102
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "repo_forks.html", select="forks", username=username, repo=flask.g.repo
Ryan Lerch 583102
    )
Ryan Lerch 583102
Ryan Lerch 6d2e06
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/upload/", methods=("GET", "POST"))</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/upload", methods=("GET", "POST"))</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/upload/", methods=("GET", "POST"))</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/upload", methods=("GET", "POST"))</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/upload/", methods=("GET", "POST"))</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/upload", methods=("GET", "POST"))</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/upload/", methods=("GET", "POST")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/upload", methods=("GET", "POST")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon cf7f54
@login_required
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def new_release(repo, username=None, namespace=None):
Pierre-Yves Chibon cda607
    """ Upload a new release.
Pierre-Yves Chibon cda607
    """
Pierre-Yves Chibon 9c2953
    if not pagure_config.get("UPLOAD_FOLDER_PATH") or not pagure_config.get(
Pierre-Yves Chibon 9c2953
        "UPLOAD_FOLDER_URL"
Pierre-Yves Chibon 9c2953
    ):
Pierre-Yves Chibon 1791e7
        flask.abort(404)
Pierre-Yves Chibon 1791e7
Pierre-Yves Chibon 74dadb
    repo = flask.g.repo
Pierre-Yves Chibon cda607
Pierre-Yves Chibon cda607
    form = pagure.forms.UploadFileForm()
Pierre-Yves Chibon cda607
Pierre-Yves Chibon cda607
    if form.validate_on_submit():
Pierre-Yves Chibon 36309a
        filenames = []
Pierre-Yves Chibon 4c06f0
        error = False
Pierre-Yves Chibon 9c2953
        for filestream in flask.request.files.getlist("filestream"):
Pierre-Yves Chibon d68be6
            filename = werkzeug.secure_filename(filestream.filename)
Pierre-Yves Chibon 36309a
            filenames.append(filename)
Pierre-Yves Chibon d68be6
            try:
Pierre-Yves Chibon d68be6
                folder = os.path.join(
Pierre-Yves Chibon 9c2953
                    pagure_config["UPLOAD_FOLDER_PATH"], repo.fullname
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon d68be6
                if not os.path.exists(folder):
Pierre-Yves Chibon 70b432
                    os.makedirs(folder)
Pierre-Yves Chibon db5bf1
                dest = os.path.join(folder, filename)
Pierre-Yves Chibon db5bf1
                if os.path.exists(dest):
Pierre-Yves Chibon db5bf1
                    raise pagure.exceptions.PagureException(
Pierre-Yves Chibon 9c2953
                        "This tarball has already been uploaded"
Pierre-Yves Chibon 9c2953
                    )
Pierre-Yves Chibon 1a1f1e
Pierre-Yves Chibon 1a1f1e
                filestream.save(dest)
Pierre-Yves Chibon 1a1f1e
                flask.flash('File "%s" uploaded' % filename)
Pierre-Yves Chibon db5bf1
            except pagure.exceptions.PagureException as err:
Pierre-Yves Chibon d9dd52
                _log.debug(err)
Pierre-Yves Chibon 9c2953
                flask.flash(str(err), "error")
Pierre-Yves Chibon 4c06f0
                error = True
Pierre-Yves Chibon d68be6
            except Exception as err:  # pragma: no cover
Pierre-Yves Chibon 4635b5
                _log.exception(err)
Pierre-Yves Chibon 9c2953
                flask.flash("Upload failed", "error")
Pierre-Yves Chibon 4c06f0
                error = True
Pierre-Yves Chibon 4c06f0
Pierre-Yves Chibon 4c06f0
        if not error:
Pierre-Yves Chibon 4c06f0
            task = pagure.lib.tasks.update_checksums_file.delay(
Pierre-Yves Chibon 9c2953
                folder=folder, filenames=filenames
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 4c06f0
            _log.info(
Pierre-Yves Chibon 9c2953
                "Updating checksums for %s of project %s in task: %s"
Pierre-Yves Chibon 9c2953
                % (filenames, repo.fullname, task.id)
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 36309a
Pierre-Yves Chibon 9c2953
        return flask.redirect(
Pierre-Yves Chibon 9c2953
            flask.url_for(
Pierre-Yves Chibon 9c2953
                "ui_ns.view_tags",
Pierre-Yves Chibon 9c2953
                repo=repo.name,
Pierre-Yves Chibon 9c2953
                username=username,
Pierre-Yves Chibon 9c2953
                namespace=repo.namespace,
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon cda607
Pierre-Yves Chibon cda607
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "new_release.html",
Pierre-Yves Chibon 9c2953
        select="tags",
Pierre-Yves Chibon cda607
        username=username,
Pierre-Yves Chibon cda607
        repo=repo,
Pierre-Yves Chibon cda607
        form=form,
Pierre-Yves Chibon f63ab5
    )
Pierre-Yves Chibon f63ab5
Pierre-Yves Chibon f63ab5
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/settings/", methods=("GET", "POST"))</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/settings", methods=("GET", "POST"))</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/settings/", methods=("GET", "POST"))</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/settings", methods=("GET", "POST"))</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/settings/", methods=("GET", "POST"))</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/settings", methods=("GET", "POST"))</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/settings/", methods=("GET", "POST")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/settings", methods=("GET", "POST")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon cf7f54
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def view_settings(repo, username=None, namespace=None):
Pierre-Yves Chibon 0261ce
    """ Presents the settings of the project.
Pierre-Yves Chibon 0261ce
    """
Pierre-Yves Chibon 0812cb
Pierre-Yves Chibon 16572e
    repo = flask.g.repo
Pierre-Yves Chibon 16572e
    repo_obj = flask.g.repo_obj
Pierre-Yves Chibon 0261ce
Pierre-Yves Chibon 295cfb
    plugins = pagure.lib.plugins.get_plugin_names(
Pierre-Yves Chibon 9c2953
        pagure_config.get("DISABLED_PLUGINS")
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 930073
    tags = pagure.lib.query.get_tags_of_project(flask.g.session, repo)
Pierre-Yves Chibon 58eba3
Pierre-Yves Chibon 4d8ef3
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon fe5017
    tag_form = pagure.forms.AddIssueTagForm()
Ghost-script d50d9e
Ghost-script 966a39
    branches = repo_obj.listall_branches()
Ghost-script 966a39
    branches_form = pagure.forms.DefaultBranchForm(branches=branches)
Pierre-Yves Chibon dff667
    priority_form = pagure.forms.DefaultPriorityForm(
Pierre-Yves Chibon 9c2953
        priorities=repo.priorities.values()
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon dff667
Pierre-Yves Chibon 0261ce
    if form.validate_on_submit():
Pierre-Yves Chibon 4d8ef3
        settings = {}
Pierre-Yves Chibon 4d8ef3
        for key in flask.request.form:
Pierre-Yves Chibon 9c2953
            if key == "csrf_token":
Pierre-Yves Chibon 4d8ef3
                continue
Pierre-Yves Chibon 4d8ef3
            settings[key] = flask.request.form[key]
Pierre-Yves Chibon 0261ce
Pierre-Yves Chibon 0261ce
        try:
Pierre-Yves Chibon 930073
            message = pagure.lib.query.update_project_settings(
Pierre-Yves Chibon b130e5
                flask.g.session,
Pierre-Yves Chibon 0261ce
                repo=repo,
Pierre-Yves Chibon 4d8ef3
                settings=settings,
Pierre-Yves Chibon 67b177
                user=flask.g.fas_user.username,
Pierre-Yves Chibon 0261ce
            )
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 0261ce
            flask.flash(message)
Pierre-Yves Chibon 9c2953
            return flask.redirect(
Pierre-Yves Chibon 9c2953
                flask.url_for(
Pierre-Yves Chibon 9c2953
                    "ui_ns.view_repo",
Pierre-Yves Chibon 9c2953
                    username=username,
Pierre-Yves Chibon 9c2953
                    repo=repo.name,
Pierre-Yves Chibon 9c2953
                    namespace=repo.namespace,
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 2ac7df
        except pagure.exceptions.PagureException as msg:
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon d9dd52
            _log.debug(msg)
Pierre-Yves Chibon 9c2953
            flask.flash(str(msg), "error")
Pierre-Yves Chibon fa97f7
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 9c2953
            flask.flash(str(err), "error")
Ghost-script d50d9e
Ghost-script d50d9e
    if not repo_obj.is_empty and not repo_obj.head_is_unborn:
Ghost-script d50d9e
        branchname = repo_obj.head.shorthand
Ghost-script d50d9e
    else:
Ghost-script d50d9e
        branchname = None
Pierre-Yves Chibon c11edb
Pierre-Yves Chibon 9c2953
    if flask.request.method == "GET" and branchname:
Pierre-Yves Chibon 6780a1
        branches_form.branches.data = branchname
Pierre-Yves Chibon 6e51b2
        priority_form.priority.data = repo.default_priority
Pierre-Yves Chibon 6780a1
Pierre-Yves Chibon 0261ce
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "settings.html",
Pierre-Yves Chibon 9c2953
        select="settings",
Pierre-Yves Chibon 0261ce
        username=username,
Pierre-Yves Chibon 0261ce
        repo=repo,
Matt Prahl cbadc1
        access_users=repo.access_users,
Matt Prahl cbadc1
        access_groups=repo.access_groups,
Pierre-Yves Chibon 0261ce
        form=form,
Pierre-Yves Chibon 77cd34
        tag_form=tag_form,
Ghost-script 966a39
        branches_form=branches_form,
Pierre-Yves Chibon dff667
        priority_form=priority_form,
Pierre-Yves Chibon 77cd34
        tags=tags,
Pierre-Yves Chibon 58eba3
        plugins=plugins,
Pierre-Yves Chibon 53e4c2
        branchname=branchname,
Ryan Lerch 6d2e06
        pagure_admin=pagure.utils.is_admin(),
Pierre-Yves Chibon 0261ce
    )
Pierre-Yves Chibon 55a6e0
Pierre-Yves Chibon 55a6e0
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/settings/test_hook", methods=("GET", "POST"))</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/settings/test_hook", methods=("GET", "POST"))</repo></namespace>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/settings/test_hook", methods=("GET", "POST")</repo></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/settings/test_hook",</repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=("GET", "POST"),
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 8c8487
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 8c8487
def test_web_hook(repo, username=None, namespace=None):
Pierre-Yves Chibon 640383
    """ Endpoint that can be called to send a test message to the web-hook
Pierre-Yves Chibon 640383
    service allowing to test the web-hooks set.
Pierre-Yves Chibon 8c8487
    """
Pierre-Yves Chibon 8c8487
Pierre-Yves Chibon 8c8487
    repo = flask.g.repo
Pierre-Yves Chibon 8c8487
Pierre-Yves Chibon 8c8487
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon 8c8487
    if form.validate_on_submit():
Clement Verna df1eef
Clement Verna df1eef
        pagure.lib.notify.log(
Clement Verna df1eef
            project=repo,
Clement Verna df1eef
            topic="Test.notification",
Clement Verna df1eef
            msg={"content": "Test message"},
Pierre-Yves Chibon cc01b8
            webhook=True,
Clement Verna df1eef
        )
Clement Verna df1eef
        flask.flash("Notification triggered")
Pierre-Yves Chibon 8c8487
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            namespace=repo.namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#projectoptions-tab"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 8c8487
Pierre-Yves Chibon 8c8487
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/update", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/update", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/update", methods=["POST"])</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/update", methods=["POST"])</repo></namespace></username>
Pierre-Yves Chibon cf7f54
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def update_project(repo, username=None, namespace=None):
Pierre-Yves Chibon 64a70d
    """ Update the description of a project.
Pierre-Yves Chibon 64a70d
    """
Pierre-Yves Chibon ced1fc
Pierre-Yves Chibon 74dadb
    repo = flask.g.repo
farhaanbukhsh 83ccf7
Pierre-Yves Chibon 2e67a4
    form = pagure.forms.ProjectFormSimplified()
Pierre-Yves Chibon 64a70d
Pierre-Yves Chibon 64a70d
    if form.validate_on_submit():
Pierre-Yves Chibon 1878ce
Pierre-Yves Chibon 64a70d
        try:
Pierre-Yves Chibon 64a70d
            repo.description = form.description.data
Pierre-Yves Chibon 2e67a4
            repo.avatar_email = form.avatar_email.data.strip()
Pierre-Yves Chibon 2e67a4
            repo.url = form.url.data.strip()
Pierre-Yves Chibon 6efa08
            if repo.private:
Pierre-Yves Chibon 6efa08
                repo.private = form.private.data
Pierre-Yves Chibon 930073
            pagure.lib.query.update_tags(
Pierre-Yves Chibon 9c2953
                flask.g.session,
Pierre-Yves Chibon 9c2953
                repo,
Pierre-Yves Chibon 9c2953
                tags=[t.strip() for t in form.tags.data.split(",")],
Pierre-Yves Chibon 8f0ef0
                username=flask.g.fas_user.username,
Pierre-Yves Chibon 2e464a
            )
Pierre-Yves Chibon b130e5
            flask.g.session.add(repo)
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 9c2953
            flask.flash("Project updated")
Pierre-Yves Chibon fa97f7
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 9c2953
            flask.flash(str(err), "error")
Pierre-Yves Chibon e64870
    else:
Pierre-Yves Chibon e64870
        for field in form.errors:
Pierre-Yves Chibon e64870
            flask.flash(
Pierre-Yves Chibon 9c2953
                'Field "%s" errored with errors: %s'
Pierre-Yves Chibon 9c2953
                % (field, ", ".join(form.errors[field])),
Pierre-Yves Chibon 9c2953
                "error",
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 64a70d
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            namespace=repo.namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#projectdetails-tab"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 64a70d
Pierre-Yves Chibon 64a70d
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/update/priorities", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/update/priorities", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/update/priorities", methods=["POST"])</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/update/priorities", methods=["POST"]</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon ca0eec
@login_required
Clement Verna afe475
@has_issue_tracker
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def update_priorities(repo, username=None, namespace=None):
Pierre-Yves Chibon ca0eec
    """ Update the priorities of a project.
Pierre-Yves Chibon ca0eec
    """
Pierre-Yves Chibon ca0eec
Pierre-Yves Chibon 74dadb
    repo = flask.g.repo
Pierre-Yves Chibon ca0eec
Pierre-Yves Chibon ca0eec
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon ca0eec
Pierre-Yves Chibon ca0eec
    error = False
Pierre-Yves Chibon ca0eec
    if form.validate_on_submit():
Pierre-Yves Chibon ca0eec
        weights = [
Pierre-Yves Chibon 9c2953
            w.strip()
Pierre-Yves Chibon 9c2953
            for w in flask.request.form.getlist("priority_weigth")
Pierre-Yves Chibon ca0eec
            if w.strip()
Pierre-Yves Chibon ca0eec
        ]
Pierre-Yves Chibon ca0eec
        try:
Pierre-Yves Chibon ca0eec
            weights = [int(w) for w in weights]
Abhijeet Kasurde f4bf50
        except (ValueError, TypeError):
Pierre-Yves Chibon 9c2953
            flask.flash("Priorities weights must be numbers", "error")
Pierre-Yves Chibon ca0eec
            error = True
Pierre-Yves Chibon ca0eec
Pierre-Yves Chibon ca0eec
        titles = [
Pierre-Yves Chibon 9c2953
            p.strip()
Pierre-Yves Chibon 9c2953
            for p in flask.request.form.getlist("priority_title")
Pierre-Yves Chibon ca0eec
            if p.strip()
Pierre-Yves Chibon ca0eec
        ]
Pierre-Yves Chibon ca0eec
Pierre-Yves Chibon ca0eec
        if len(weights) != len(titles):
Pierre-Yves Chibon ca0eec
            flask.flash(
Pierre-Yves Chibon 9c2953
                "Priorities weights and titles are not of the same length",
Pierre-Yves Chibon 9c2953
                "error",
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon ca0eec
            error = True
Pierre-Yves Chibon ca0eec
Pierre-Yves Chibon bd9d21
        for weight in weights:
Pierre-Yves Chibon bd9d21
            if weights.count(weight) != 1:
Pierre-Yves Chibon bd9d21
                flask.flash(
Pierre-Yves Chibon 9c2953
                    "Priority weight %s is present %s times"
Pierre-Yves Chibon 9c2953
                    % (weight, weights.count(weight)),
Pierre-Yves Chibon 9c2953
                    "error",
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon bd9d21
                error = True
Pierre-Yves Chibon bd9d21
                break
Pierre-Yves Chibon bd9d21
Pierre-Yves Chibon bd9d21
        for title in titles:
Pierre-Yves Chibon bd9d21
            if titles.count(title) != 1:
Pierre-Yves Chibon bd9d21
                flask.flash(
Pierre-Yves Chibon 9c2953
                    "Priority %s is present %s times"
Pierre-Yves Chibon 9c2953
                    % (title, titles.count(title)),
Pierre-Yves Chibon 9c2953
                    "error",
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon bd9d21
                error = True
Pierre-Yves Chibon bd9d21
                break
Pierre-Yves Chibon bd9d21
Pierre-Yves Chibon ca0eec
        if not error:
Pierre-Yves Chibon ca0eec
            priorities = {}
Pierre-Yves Chibon 7b3aee
            if weights:
Pierre-Yves Chibon 7b3aee
                for cnt in range(len(weights)):
Pierre-Yves Chibon 7b3aee
                    priorities[weights[cnt]] = titles[cnt]
Pierre-Yves Chibon 9c2953
                priorities[""] = ""
Pierre-Yves Chibon ca0eec
            try:
Pierre-Yves Chibon ca0eec
                repo.priorities = priorities
Pierre-Yves Chibon 606ecb
                if repo.default_priority not in priorities.values():
Pierre-Yves Chibon 606ecb
                    flask.flash(
Pierre-Yves Chibon 9c2953
                        "Default priority reset as it is no longer one of "
Pierre-Yves Chibon 9c2953
                        "set priorities."
Pierre-Yves Chibon 9c2953
                    )
Pierre-Yves Chibon 606ecb
                    repo.default_priority = None
Pierre-Yves Chibon b130e5
                flask.g.session.add(repo)
Pierre-Yves Chibon b130e5
                flask.g.session.commit()
Pierre-Yves Chibon 9c2953
                flask.flash("Priorities updated")
Pierre-Yves Chibon ca0eec
            except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
                flask.g.session.rollback()
Pierre-Yves Chibon 9c2953
                flask.flash(str(err), "error")
Pierre-Yves Chibon ca0eec
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            namespace=repo.namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#priorities-tab"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon ca0eec
Pierre-Yves Chibon e49493
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/update/default_priority", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/update/default_priority", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/update/default_priority", methods=["POST"]</repo></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/update/default_priority",</repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon dff667
@login_required
Clement Verna afe475
@has_issue_tracker
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon dff667
def default_priority(repo, username=None, namespace=None):
Pierre-Yves Chibon dff667
    """ Update the default priority of a project.
Pierre-Yves Chibon dff667
    """
Pierre-Yves Chibon dff667
Pierre-Yves Chibon dff667
    repo = flask.g.repo
Pierre-Yves Chibon dff667
Pierre-Yves Chibon dff667
    form = pagure.forms.DefaultPriorityForm(
Pierre-Yves Chibon 9c2953
        priorities=repo.priorities.values()
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon dff667
Pierre-Yves Chibon dff667
    if form.validate_on_submit():
Pierre-Yves Chibon dff667
        priority = form.priority.data or None
Pierre-Yves Chibon dff667
        if priority in repo.priorities.values() or priority is None:
Pierre-Yves Chibon dff667
            repo.default_priority = priority
Pierre-Yves Chibon dff667
            try:
Pierre-Yves Chibon b130e5
                flask.g.session.add(repo)
Pierre-Yves Chibon b130e5
                flask.g.session.commit()
Pierre-Yves Chibon dff667
                if priority:
Pierre-Yves Chibon 9c2953
                    flask.flash("Default priority set to %s" % priority)
Pierre-Yves Chibon dff667
                else:
Pierre-Yves Chibon 9c2953
                    flask.flash("Default priority reset")
Pierre-Yves Chibon dff667
            except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
                flask.g.session.rollback()
Pierre-Yves Chibon 9c2953
                flask.flash(str(err), "error")
Pierre-Yves Chibon dff667
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            namespace=repo.namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#priorities-tab"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon dff667
Pierre-Yves Chibon dff667
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/update/milestones", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/update/milestones", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/update/milestones", methods=["POST"])</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/update/milestones", methods=["POST"]</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon ccf782
@login_required
Clement Verna afe475
@has_issue_tracker
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def update_milestones(repo, username=None, namespace=None):
Pierre-Yves Chibon ccf782
    """ Update the milestones of a project.
Pierre-Yves Chibon ccf782
    """
Pierre-Yves Chibon ccf782
Pierre-Yves Chibon 74dadb
    repo = flask.g.repo
Pierre-Yves Chibon ccf782
Pierre-Yves Chibon ccf782
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon ccf782
Pierre-Yves Chibon ccf782
    error = False
Pierre-Yves Chibon ccf782
    if form.validate_on_submit():
Pierre-Yves Chibon 9c2953
        redirect = flask.request.args.get("from")
Akanksha d86ac1
        milestones = flask.request.form.getlist("milestones")
Akanksha d86ac1
        miles = {}
Akanksha d86ac1
        keys = []
Pierre-Yves Chibon ccf782
Akanksha d86ac1
        for idx in milestones:
Akanksha d86ac1
Akanksha d86ac1
            milestone = flask.request.form.get(
Akanksha d86ac1
                "milestone_%s_name" % (idx), None
Akanksha d86ac1
            )
Akanksha d86ac1
Pierre-Yves Chibon 365671
            date = flask.request.form.get("milestone_%s_date" % (idx), None)
Akanksha d86ac1
Akanksha d86ac1
            active = (
Akanksha d86ac1
                True
Pierre-Yves Chibon 365671
                if flask.request.form.get("milestone_%s_active" % (idx))
Akanksha d86ac1
                else False
Akanksha d86ac1
            )
Pierre-Yves Chibon ccf782
Akanksha d86ac1
            if milestone and milestone.strip():
Akanksha d86ac1
                milestone = milestone.strip()
Akanksha d86ac1
                if milestone in miles:
Akanksha d86ac1
                    flask.flash(
Akanksha d86ac1
                        "Milestone %s is present multiple times" % milestone,
Akanksha d86ac1
                        "error",
Pierre-Yves Chibon 9c2953
                    )
Akanksha d86ac1
                    error = True
Akanksha d86ac1
                    break
Pierre-Yves Chibon 0619e5
Akanksha d86ac1
                miles[milestone] = {
Akanksha d86ac1
                    "date": date.strip() if date else None,
Akanksha d86ac1
                    "active": active,
Akanksha d86ac1
                }
Akanksha d86ac1
                keys.append(milestone)
Akanksha d86ac1
Akanksha d86ac1
        if not error:
Pierre-Yves Chibon ccf782
            try:
Pierre-Yves Chibon ccf782
                repo.milestones = miles
Pierre-Yves Chibon 0619e5
                repo.milestones_keys = keys
Pierre-Yves Chibon b130e5
                flask.g.session.add(repo)
Pierre-Yves Chibon b130e5
                flask.g.session.commit()
Pierre-Yves Chibon 9c2953
                flask.flash("Milestones updated")
Pierre-Yves Chibon ccf782
            except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
                flask.g.session.rollback()
Pierre-Yves Chibon 9c2953
                flask.flash(str(err), "error")
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon 9c2953
        if redirect == "issues":
Pierre-Yves Chibon 9c2953
            return flask.redirect(
Pierre-Yves Chibon 9c2953
                flask.url_for(
Pierre-Yves Chibon 9c2953
                    "ui_ns.view_issues",
Pierre-Yves Chibon 9c2953
                    username=username,
Pierre-Yves Chibon 9c2953
                    repo=repo.name,
Pierre-Yves Chibon 9c2953
                    namespace=namespace,
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon f9f2d5
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#roadmap-tab"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon ccf782
Pierre-Yves Chibon ccf782
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/default/branch/", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/default/branch/", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/default/branch/", methods=["POST"])</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/default/branch/", methods=["POST"]</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon cf7f54
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def change_ref_head(repo, username=None, namespace=None):
Ghost-script 966a39
    """ Change HEAD reference
Ghost-script 966a39
    """
Ghost-script 966a39
Pierre-Yves Chibon 16572e
    repo = flask.g.repo
Pierre-Yves Chibon 16572e
    repo_obj = flask.g.repo_obj
Ghost-script 966a39
Ghost-script d50d9e
    branches = repo_obj.listall_branches()
Ghost-script d50d9e
    form = pagure.forms.DefaultBranchForm(branches=branches)
Ghost-script d50d9e
Ghost-script d50d9e
    if form.validate_on_submit():
Ghost-script d50d9e
        branchname = form.branches.data
Ghost-script d50d9e
        try:
Julen Landa Alustiza 4de8f2
            pagure.lib.git.git_set_ref_head(project=repo, branch=branchname)
Pierre-Yves Chibon 9c2953
            flask.flash("Default branch updated to %s" % branchname)
Pierre-Yves Chibon cff1c9
        except Exception as err:  # pragma: no cover
Pierre-Yves Chibon 4635b5
            _log.exception(err)
Ghost-script 966a39
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#defaultbranch-tab"
Pierre-Yves Chibon 9c2953
    )
Ghost-script 966a39
Ghost-script 966a39
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/delete", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/delete", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/delete", methods=["POST"])</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/delete", methods=["POST"])</repo></namespace></username>
Pierre-Yves Chibon cf7f54
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def delete_repo(repo, username=None, namespace=None):
Pierre-Yves Chibon 55a6e0
    """ Delete the present project.
Pierre-Yves Chibon 55a6e0
    """
Pierre-Yves Chibon 3f19a5
    repo = flask.g.repo
Pierre-Yves Chibon 3f19a5
Pierre-Yves Chibon 9c2953
    del_project = pagure_config.get("ENABLE_DEL_PROJECTS", True)
Pierre-Yves Chibon 9c2953
    del_fork = pagure_config.get("ENABLE_DEL_FORKS", del_project)
Pierre-Yves Chibon 9c2953
    if (not repo.is_fork and not del_project) or (
Pierre-Yves Chibon 9c2953
        repo.is_fork and not del_fork
Pierre-Yves Chibon 9c2953
    ):
Pierre-Yves Chibon 86d0e0
        flask.abort(404)
Pierre-Yves Chibon 86d0e0
Pierre-Yves Chibon 1dc86f
    if repo.read_only:
Pierre-Yves Chibon 1dc86f
        flask.flash(
Pierre-Yves Chibon 9c2953
            "The ACLs of this project are being refreshed in the backend "
Pierre-Yves Chibon 9c2953
            "this prevents the project from being deleted. Please wait "
Pierre-Yves Chibon 9c2953
            "for this task to finish before trying again. Thanks!"
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        return flask.redirect(
Pierre-Yves Chibon 9c2953
            flask.url_for(
Pierre-Yves Chibon 9c2953
                "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
                repo=repo.name,
Pierre-Yves Chibon 9c2953
                username=username,
Pierre-Yves Chibon 9c2953
                namespace=namespace,
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 9c2953
            + "#deleteproject-tab"
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 1dc86f
Pierre-Yves Chibon 5b06f7
    task = pagure.lib.tasks.delete_project.delay(
Pierre-Yves Chibon b130e5
        namespace=repo.namespace,
Pierre-Yves Chibon b130e5
        name=repo.name,
Pierre-Yves Chibon b130e5
        user=repo.user.user if repo.is_fork else None,
Pierre-Yves Chibon 9c2953
        action_user=flask.g.fas_user.username,
Pierre-Yves Chibon 9c2953
    )
Aurélien Bompard a7f281
    return pagure.utils.wait_for_task(task)
Pierre-Yves Chibon 8782bc
Pierre-Yves Chibon 8782bc
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/hook_token", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/hook_token", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/hook_token", methods=["POST"])</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/hook_token", methods=["POST"]</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon cf7f54
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def new_repo_hook_token(repo, username=None, namespace=None):
Pierre-Yves Chibon e3ecd9
    """ Re-generate a hook token for the present project.
Pierre-Yves Chibon e3ecd9
    """
Pierre-Yves Chibon 9c2953
    if not pagure_config.get("WEBHOOK", False):
Pierre-Yves Chibon ec8a64
        flask.abort(404)
Pierre-Yves Chibon ec8a64
Clement Verna afe475
    repo = flask.g.repo
Pierre-Yves Chibon e3ecd9
Pierre-Yves Chibon 08f719
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon 08f719
    if not form.validate_on_submit():
Pierre-Yves Chibon c6cc5c
        flask.abort(400, description="Invalid request")
Pierre-Yves Chibon 08f719
Pierre-Yves Chibon e3ecd9
    try:
Pierre-Yves Chibon e3ecd9
        repo.hook_token = pagure.lib.login.id_generator(40)
Pierre-Yves Chibon b130e5
        flask.g.session.commit()
Pierre-Yves Chibon 9c2953
        flask.flash("New hook token generated")
Pierre-Yves Chibon fa97f7
    except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
        flask.g.session.rollback()
Pierre-Yves Chibon 4635b5
        _log.exception(err)
Pierre-Yves Chibon 9c2953
        flask.flash("Could not generate a new token for this project", "error")
Pierre-Yves Chibon e3ecd9
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#privatehookkey-tab"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon e3ecd9
Pierre-Yves Chibon e3ecd9
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/dropdeploykey/<int:keyid>", methods=["POST"])</int:keyid></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/dropdeploykey/<int:keyid>", methods=["POST"])</int:keyid></repo></namespace>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/dropdeploykey/<int:keyid>", methods=["POST"]</int:keyid></repo></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/dropdeploykey/<int:keyid>",</int:keyid></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Patrick Uiterwijk 9a7915
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Patrick Uiterwijk 9a7915
def remove_deploykey(repo, keyid, username=None, namespace=None):
Patrick Uiterwijk 9a7915
    """ Remove the specified deploy key from the project.
Patrick Uiterwijk 9a7915
    """
Patrick Uiterwijk 9a7915
Pierre-Yves Chibon 9c2953
    if not pagure_config.get("DEPLOY_KEY", True):
Pierre-Yves Chibon c6cc5c
        flask.abort(
Pierre-Yves Chibon c6cc5c
            404, description="This pagure instance disabled deploy keys"
Pierre-Yves Chibon c6cc5c
        )
Pierre-Yves Chibon 39f1dc
Patrick Uiterwijk 9a7915
    repo = flask.g.repo
Patrick Uiterwijk 9a7915
Patrick Uiterwijk 9a7915
    form = pagure.forms.ConfirmationForm()
Patrick Uiterwijk 9a7915
    if form.validate_on_submit():
Patrick Uiterwijk 9b237b
        found = False
Patrick Uiterwijk 9b237b
        for key in repo.deploykeys:
Patrick Uiterwijk 9b237b
            if key.id == keyid:
Patrick Uiterwijk 9b237b
                flask.g.session.delete(key)
Patrick Uiterwijk 9b237b
                found = True
Patrick Uiterwijk 9b237b
                break
Patrick Uiterwijk 9a7915
Patrick Uiterwijk 9b237b
        if not found:
Pierre-Yves Chibon 9c2953
            flask.flash("Deploy key does not exist in project.", "error")
Pierre-Yves Chibon 9c2953
            return flask.redirect(
Pierre-Yves Chibon 9c2953
                flask.url_for(
Pierre-Yves Chibon 9c2953
                    "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
                    repo=repo.name,
Pierre-Yves Chibon 9c2953
                    username=username,
Pierre-Yves Chibon 9c2953
                    namespace=repo.namespace,
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 9c2953
                + "#deploykeys-tab"
Patrick Uiterwijk 9a7915
            )
Patrick Uiterwijk 9a7915
Patrick Uiterwijk 9a7915
        try:
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 930073
            pagure.lib.query.create_deploykeys_ssh_keys_on_disk(
Pierre-Yves Chibon 9c2953
                repo, pagure_config.get("GITOLITE_KEYDIR", None)
Patrick Uiterwijk 9a7915
            )
Slavek Kabrda f68223
            pagure.lib.tasks.gitolite_post_compile_only.delay()
Pierre-Yves Chibon 9c2953
            flask.flash("Deploy key removed")
Patrick Uiterwijk 9a7915
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 4635b5
            _log.exception(err)
Pierre-Yves Chibon 9c2953
            flask.flash("Deploy key could not be removed", "error")
Patrick Uiterwijk 9a7915
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#deploykey-tab"
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk 9a7915
Patrick Uiterwijk 9a7915
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/dropuser/<int:userid>", methods=["POST"])</int:userid></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/dropuser/<int:userid>", methods=["POST"])</int:userid></repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/dropuser/<int:userid>", methods=["POST"])</int:userid></repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/dropuser/<int:userid>",</int:userid></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon cf7f54
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def remove_user(repo, userid, username=None, namespace=None):
Pierre-Yves Chibon 681845
    """ Remove the specified user from the project.
Pierre-Yves Chibon 681845
    """
Vivek Anand 58143d
Pierre-Yves Chibon 9c2953
    if not pagure_config.get("ENABLE_USER_MNGT", True):
Pierre-Yves Chibon c6cc5c
        flask.abort(
Pierre-Yves Chibon c6cc5c
            404,
Pierre-Yves Chibon c6cc5c
            description="User management not allowed in the pagure instance",
Pierre-Yves Chibon c6cc5c
        )
Vivek Anand 58143d
Pierre-Yves Chibon 3119c6
    repo = flask.g.repo
Pierre-Yves Chibon 681845
Pierre-Yves Chibon fe5017
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon a04944
    delete_themselves = False
Pierre-Yves Chibon 9dd7da
    if form.validate_on_submit():
Pierre-Yves Chibon 9dd7da
        try:
Pierre-Yves Chibon 930073
            user = pagure.lib.query.get_user_by_id(
Pierre-Yves Chibon 930073
                flask.g.session, int(userid)
Pierre-Yves Chibon 930073
            )
Pierre-Yves Chibon 59005a
            delete_themselves = user.username == flask.g.fas_user.username
Pierre-Yves Chibon 930073
            msg = pagure.lib.query.remove_user_of_project(
Pierre-Yves Chibon 9c2953
                flask.g.session, user, repo, flask.g.fas_user.username
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 59005a
            flask.flash(msg)
Pierre-Yves Chibon 9dd7da
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 4635b5
            _log.exception(err)
Pierre-Yves Chibon 9c2953
            flask.flash("User could not be removed", "error")
Pierre-Yves Chibon 59005a
        except pagure.exceptions.PagureException as err:
Pierre-Yves Chibon 9c2953
            flask.flash("%s" % err, "error")
Pierre-Yves Chibon 9c2953
            return flask.redirect(
Pierre-Yves Chibon 9c2953
                flask.url_for(
Pierre-Yves Chibon 9c2953
                    "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
                    repo=repo.name,
Pierre-Yves Chibon 9c2953
                    username=username,
Pierre-Yves Chibon 9c2953
                    namespace=repo.namespace,
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 9c2953
                + "#usersgroups-tab"
Pierre-Yves Chibon 59005a
            )
Pierre-Yves Chibon e1b7ed
Pierre-Yves Chibon 9c2953
    endpoint = "ui_ns.view_settings"
Pierre-Yves Chibon 9c2953
    tab = "#usersgroups-tab"
Pierre-Yves Chibon a04944
    if delete_themselves:
Pierre-Yves Chibon 9c2953
        endpoint = "ui_ns.view_repo"
Pierre-Yves Chibon 9c2953
        tab = ""
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            endpoint, repo=repo.name, username=username, namespace=namespace
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + tab
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/adddeploykey/", methods=("GET", "POST"))</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/adddeploykey", methods=("GET", "POST"))</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/adddeploykey/", methods=("GET", "POST"))</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/adddeploykey", methods=("GET", "POST"))</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/adddeploykey/", methods=("GET", "POST"))</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/adddeploykey", methods=("GET", "POST"))</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/adddeploykey/",</repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=("GET", "POST"),
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/adddeploykey", methods=("GET", "POST")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Patrick Uiterwijk 9a7915
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Patrick Uiterwijk 9a7915
def add_deploykey(repo, username=None, namespace=None):
Patrick Uiterwijk 9a7915
    """ Add the specified deploy key to the project.
Patrick Uiterwijk 9a7915
    """
Patrick Uiterwijk 9a7915
Pierre-Yves Chibon 9c2953
    if not pagure_config.get("DEPLOY_KEY", True):
Pierre-Yves Chibon c6cc5c
        flask.abort(
Pierre-Yves Chibon c6cc5c
            404, description="This pagure instance disabled deploy keys"
Pierre-Yves Chibon c6cc5c
        )
Pierre-Yves Chibon 39f1dc
Patrick Uiterwijk 9a7915
    repo = flask.g.repo
Patrick Uiterwijk 9a7915
Patrick Uiterwijk 9a7915
    form = pagure.forms.AddDeployKeyForm()
Patrick Uiterwijk 9a7915
Patrick Uiterwijk 9a7915
    if form.validate_on_submit():
Pierre-Yves Chibon 9efbd5
        user = _get_user(username=flask.g.fas_user.username)
Patrick Uiterwijk 9a7915
        try:
Pierre-Yves Chibon 930073
            msg = pagure.lib.query.add_sshkey_to_project_or_user(
Pierre-Yves Chibon 9c2953
                flask.g.session,
Patrick Uiterwijk 9a7915
                ssh_key=form.ssh_key.data,
Pierre-Yves Chibon 9efbd5
                creator=user,
Patrick Uiterwijk 9b237b
                project=repo,
Patrick Uiterwijk 9a7915
                pushaccess=form.pushaccess.data,
Patrick Uiterwijk 9a7915
            )
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 930073
            pagure.lib.query.create_deploykeys_ssh_keys_on_disk(
Pierre-Yves Chibon 9c2953
                repo, pagure_config.get("GITOLITE_KEYDIR", None)
Patrick Uiterwijk 9a7915
            )
Slavek Kabrda f68223
            pagure.lib.tasks.gitolite_post_compile_only.delay()
Patrick Uiterwijk 9a7915
            flask.flash(msg)
Pierre-Yves Chibon 9c2953
            return flask.redirect(
Pierre-Yves Chibon 9c2953
                flask.url_for(
Pierre-Yves Chibon 9c2953
                    "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
                    repo=repo.name,
Pierre-Yves Chibon 9c2953
                    username=username,
Pierre-Yves Chibon 9c2953
                    namespace=namespace,
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 9c2953
                + "#deploykey-tab"
Pierre-Yves Chibon 9c2953
            )
Patrick Uiterwijk 9a7915
        except pagure.exceptions.PagureException as msg:
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon d9dd52
            _log.debug(msg)
Pierre-Yves Chibon 9c2953
            flask.flash(str(msg), "error")
Patrick Uiterwijk 9a7915
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 4635b5
            _log.exception(err)
Pierre-Yves Chibon 9c2953
            flask.flash("Deploy key could not be added", "error")
Patrick Uiterwijk 9a7915
Patrick Uiterwijk 9a7915
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "add_deploykey.html", form=form, username=username, repo=repo
Patrick Uiterwijk 9a7915
    )
Patrick Uiterwijk 9a7915
Patrick Uiterwijk 9a7915
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/adduser/", methods=("GET", "POST"))</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/adduser", methods=("GET", "POST"))</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/adduser/", methods=("GET", "POST"))</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/adduser", methods=("GET", "POST"))</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/adduser/", methods=("GET", "POST"))</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/adduser", methods=("GET", "POST"))</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/adduser/", methods=("GET", "POST")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/adduser", methods=("GET", "POST")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon cf7f54
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def add_user(repo, username=None, namespace=None):
Pierre-Yves Chibon 761495
    """ Add the specified user to the project.
Pierre-Yves Chibon 8782bc
    """
Vivek Anand 58143d
Pierre-Yves Chibon 9c2953
    if not pagure_config.get("ENABLE_USER_MNGT", True):
Pierre-Yves Chibon 53e4c2
        flask.abort(
Pierre-Yves Chibon c6cc5c
            404,
Pierre-Yves Chibon c6cc5c
            description="User management is not allowed in this "
Pierre-Yves Chibon c6cc5c
            "pagure instance",
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 7be364
Pierre-Yves Chibon 3119c6
    repo = flask.g.repo
Pierre-Yves Chibon 8782bc
Pierre-Yves Chibon 9c2953
    user_to_update = flask.request.args.get("user", "").strip()
Vivek Anand 963f9a
    user_to_update_obj = None
Vivek Anand 5a7449
    user_access = None
Vivek Anand 963f9a
    if user_to_update:
Pierre-Yves Chibon 930073
        user_to_update_obj = pagure.lib.query.search_user(
Pierre-Yves Chibon 9c2953
            flask.g.session, username=user_to_update
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 930073
        user_access = pagure.lib.query.get_obj_access(
Pierre-Yves Chibon 9c2953
            flask.g.session, repo, user_to_update_obj
Pierre-Yves Chibon 9c2953
        )
Vivek Anand 963f9a
Vivek Anand 963f9a
    # The requested user is not found
Vivek Anand 963f9a
    if user_to_update_obj is None:
Vivek Anand 963f9a
        user_to_update = None
Vivek Anand 5a7449
        user_access = None
Vivek Anand 963f9a
Pierre-Yves Chibon fe5017
    form = pagure.forms.AddUserForm()
Pierre-Yves Chibon 8782bc
Pierre-Yves Chibon 8782bc
    if form.validate_on_submit():
Pierre-Yves Chibon 10f22f
        try:
Pierre-Yves Chibon 930073
            msg = pagure.lib.query.add_user_to_project(
Pierre-Yves Chibon 9c2953
                flask.g.session,
Pierre-Yves Chibon 9c2953
                repo,
Pierre-Yves Chibon ceb5d8
                new_user=form.user.data,
Pierre-Yves Chibon ceb5d8
                user=flask.g.fas_user.username,
Vivek Anand 967335
                access=form.access.data,
Pierre-Yves Chibon 9c2953
                required_groups=pagure_config.get("REQUIRED_GROUPS"),
Pierre-Yves Chibon ceb5d8
            )
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 274e60
            pagure.lib.git.generate_gitolite_acls(project=repo)
Pierre-Yves Chibon 10f22f
            flask.flash(msg)
Pierre-Yves Chibon 9c2953
            return flask.redirect(
Pierre-Yves Chibon 9c2953
                flask.url_for(
Pierre-Yves Chibon 9c2953
                    "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
                    repo=repo.name,
Pierre-Yves Chibon 9c2953
                    username=username,
Pierre-Yves Chibon 9c2953
                    namespace=namespace,
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 9c2953
                + "#usersgroups-tab"
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon fe5017
        except pagure.exceptions.PagureException as msg:
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon d9dd52
            _log.debug(msg)
Pierre-Yves Chibon 9c2953
            flask.flash(str(msg), "error")
Pierre-Yves Chibon 5c5e6b
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 4635b5
            _log.exception(err)
Pierre-Yves Chibon 9c2953
            flask.flash("User could not be added", "error")
Pierre-Yves Chibon 8782bc
Pierre-Yves Chibon 930073
    access_levels = pagure.lib.query.get_access_levels(flask.g.session)
Pierre-Yves Chibon 8782bc
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "add_user.html",
Pierre-Yves Chibon 8782bc
        form=form,
Pierre-Yves Chibon 8782bc
        username=username,
Pierre-Yves Chibon 8782bc
        repo=repo,
Vivek Anand 967335
        access_levels=access_levels,
Vivek Anand 963f9a
        user_to_update=user_to_update,
Vivek Anand 5a7449
        user_access=user_access,
Pierre-Yves Chibon 8782bc
    )
Pierre-Yves Chibon 25c04d
Pierre-Yves Chibon 25c04d
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/dropgroup/<int:groupid>", methods=["POST"])</int:groupid></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/dropgroup/<int:groupid>", methods=["POST"])</int:groupid></repo></namespace>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/dropgroup/<int:groupid>", methods=["POST"]</int:groupid></repo></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/dropgroup/<int:groupid>",</int:groupid></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 761d06
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def remove_group_project(repo, groupid, username=None, namespace=None):
Pierre-Yves Chibon 761d06
    """ Remove the specified group from the project.
Pierre-Yves Chibon 761d06
    """
Vivek Anand 58143d
Pierre-Yves Chibon 9c2953
    if not pagure_config.get("ENABLE_USER_MNGT", True):
Pierre-Yves Chibon 53e4c2
        flask.abort(
Pierre-Yves Chibon c6cc5c
            404,
Pierre-Yves Chibon c6cc5c
            description="User management is not allowed in this "
Pierre-Yves Chibon c6cc5c
            "pagure instance",
Pierre-Yves Chibon 9c2953
        )
Vivek Anand 58143d
Pierre-Yves Chibon 3119c6
    repo = flask.g.repo
Pierre-Yves Chibon 761d06
Pierre-Yves Chibon 761d06
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon 761d06
    if form.validate_on_submit():
Pierre-Yves Chibon 761d06
        grpids = [grp.id for grp in repo.groups]
Pierre-Yves Chibon 761d06
Pierre-Yves Chibon 761d06
        if groupid not in grpids:
Pierre-Yves Chibon 761d06
            flask.flash(
Pierre-Yves Chibon 9c2953
                "Group does not seem to be part of this project", "error"
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 9c2953
            return flask.redirect(
Pierre-Yves Chibon 9c2953
                flask.url_for(
Pierre-Yves Chibon 9c2953
                    "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
                    repo=repo.name,
Pierre-Yves Chibon 9c2953
                    username=username,
Pierre-Yves Chibon 9c2953
                    namespace=namespace,
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 9c2953
                + "#usersgroups-tab"
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 761d06
Pierre-Yves Chibon 761d06
        for grp in repo.groups:
Pierre-Yves Chibon 761d06
            if grp.id == groupid:
Pierre-Yves Chibon 761d06
                repo.groups.remove(grp)
Pierre-Yves Chibon 761d06
                break
Pierre-Yves Chibon 761d06
        try:
Vivek Anand 9888e8
            # Mark the project as read_only, celery will unmark it
Pierre-Yves Chibon 930073
            pagure.lib.query.update_read_only_mode(
Pierre-Yves Chibon 9c2953
                flask.g.session, repo, read_only=True
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 274e60
            pagure.lib.git.generate_gitolite_acls(project=repo)
Pierre-Yves Chibon 9c2953
            flask.flash("Group removed")
Pierre-Yves Chibon 761d06
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 4635b5
            _log.exception(err)
Pierre-Yves Chibon 9c2953
            flask.flash("Group could not be removed", "error")
Pierre-Yves Chibon 761d06
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#usersgroups-tab"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 761d06
Pierre-Yves Chibon 761d06
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/addgroup/", methods=("GET", "POST"))</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/addgroup", methods=("GET", "POST"))</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/addgroup/", methods=("GET", "POST"))</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/addgroup", methods=("GET", "POST"))</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/addgroup/", methods=("GET", "POST"))</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/addgroup", methods=("GET", "POST"))</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/addgroup/", methods=("GET", "POST")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/addgroup", methods=("GET", "POST")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon cf7f54
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def add_group_project(repo, username=None, namespace=None):
Pierre-Yves Chibon 761495
    """ Add the specified group to the project.
Pierre-Yves Chibon 2e56e5
    """
Vivek Anand 58143d
Pierre-Yves Chibon 9c2953
    if not pagure_config.get("ENABLE_USER_MNGT", True):
Pierre-Yves Chibon 53e4c2
        flask.abort(
Pierre-Yves Chibon c6cc5c
            404,
Pierre-Yves Chibon c6cc5c
            description="User management is not allowed in this "
Pierre-Yves Chibon c6cc5c
            "pagure instance",
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 7be364
Pierre-Yves Chibon 3119c6
    repo = flask.g.repo
Pierre-Yves Chibon 2e56e5
Pierre-Yves Chibon 9c2953
    group_to_update = flask.request.args.get("group", "").strip()
Vivek Anand 963f9a
    group_to_update_obj = None
Vivek Anand 5a7449
    group_access = None
Vivek Anand 963f9a
    if group_to_update:
Pierre-Yves Chibon 930073
        group_to_update_obj = pagure.lib.query.search_groups(
Pierre-Yves Chibon 9c2953
            flask.g.session, group_name=group_to_update
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 930073
        group_access = pagure.lib.query.get_obj_access(
Pierre-Yves Chibon 9c2953
            flask.g.session, repo, group_to_update_obj
Pierre-Yves Chibon 9c2953
        )
Vivek Anand 963f9a
Vivek Anand 963f9a
    # The requested group is not found
Vivek Anand 963f9a
    if group_to_update_obj is None:
Vivek Anand 963f9a
        group_to_update = None
Vivek Anand 5a7449
        group_access = None
Vivek Anand 963f9a
Pierre-Yves Chibon 2e56e5
    form = pagure.forms.AddGroupForm()
Pierre-Yves Chibon 2e56e5
Pierre-Yves Chibon 2e56e5
    if form.validate_on_submit():
Pierre-Yves Chibon 2e56e5
        try:
Pierre-Yves Chibon 930073
            msg = pagure.lib.query.add_group_to_project(
Pierre-Yves Chibon 9c2953
                flask.g.session,
Pierre-Yves Chibon 9c2953
                repo,
Pierre-Yves Chibon 2e56e5
                new_group=form.group.data,
Pierre-Yves Chibon 2e56e5
                user=flask.g.fas_user.username,
Vivek Anand 967335
                access=form.access.data,
Pierre-Yves Chibon 9c2953
                create=pagure_config.get("ENABLE_GROUP_MNGT", False),
Pierre-Yves Chibon b130e5
                is_admin=pagure.utils.is_admin(),
Pierre-Yves Chibon 2e56e5
            )
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 274e60
            pagure.lib.git.generate_gitolite_acls(project=repo)
Pierre-Yves Chibon 2e56e5
            flask.flash(msg)
Pierre-Yves Chibon 9c2953
            return flask.redirect(
Pierre-Yves Chibon 9c2953
                flask.url_for(
Pierre-Yves Chibon 9c2953
                    "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
                    repo=repo.name,
Pierre-Yves Chibon 9c2953
                    username=username,
Pierre-Yves Chibon 9c2953
                    namespace=namespace,
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 9c2953
                + "#usersgroups-tab"
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 2e56e5
        except pagure.exceptions.PagureException as msg:
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon d9dd52
            _log.debug(msg)
Pierre-Yves Chibon 9c2953
            flask.flash(str(msg), "error")
Pierre-Yves Chibon 2e56e5
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 4635b5
            _log.exception(err)
Pierre-Yves Chibon 9c2953
            flask.flash("Group could not be added", "error")
Pierre-Yves Chibon 2e56e5
Pierre-Yves Chibon 930073
    access_levels = pagure.lib.query.get_access_levels(flask.g.session)
Pierre-Yves Chibon 2e56e5
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "add_group_project.html",
Pierre-Yves Chibon 2e56e5
        form=form,
Pierre-Yves Chibon 2e56e5
        username=username,
Pierre-Yves Chibon 2e56e5
        repo=repo,
Vivek Anand 967335
        access_levels=access_levels,
Vivek Anand 963f9a
        group_to_update=group_to_update,
Vivek Anand 5a7449
        group_access=group_access,
Pierre-Yves Chibon 2e56e5
    )
Pierre-Yves Chibon 2e56e5
Pierre-Yves Chibon 2e56e5
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/regenerate", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/regenerate", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/regenerate", methods=["POST"])</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/regenerate", methods=["POST"]</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon cf7f54
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def regenerate_git(repo, username=None, namespace=None):
Pierre-Yves Chibon 25c04d
    """ Regenerate the specified git repo with the content in the project.
Pierre-Yves Chibon 25c04d
    """
Pierre-Yves Chibon 25c04d
Pierre-Yves Chibon 74dadb
    repo = flask.g.repo
Pierre-Yves Chibon 25c04d
Pierre-Yves Chibon 9c2953
    regenerate = flask.request.form.get("regenerate")
Pierre-Yves Chibon 9c2953
    if not regenerate or regenerate.lower() not in ["tickets", "requests"]:
Pierre-Yves Chibon c6cc5c
        flask.abort(
Pierre-Yves Chibon c6cc5c
            400,
Pierre-Yves Chibon c6cc5c
            description="You can only regenerate tickest or requests repos",
Pierre-Yves Chibon c6cc5c
        )
Pierre-Yves Chibon 25c04d
Pierre-Yves Chibon 25c04d
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon 25c04d
    if form.validate_on_submit():
Pierre-Yves Chibon 9c2953
        if regenerate.lower() == "requests" and repo.settings.get(
Pierre-Yves Chibon 9c2953
            "pull_requests"
Pierre-Yves Chibon 9c2953
        ):
Vivek Anand 8ced04
Vivek Anand 8ced04
            # delete the requests repo and reinit
Vivek Anand 8ced04
            # in case there are no requests
Vivek Anand 8ced04
            if len(repo.requests) == 0:
Vivek Anand 8ced04
                pagure.lib.git.reinit_git(
Pierre-Yves Chibon 9c2953
                    project=repo, repofolder=pagure_config["REQUESTS_FOLDER"]
Vivek Anand 8ced04
                )
Pierre-Yves Chibon 25c04d
            for request in repo.requests:
Pierre-Yves Chibon 25c04d
                pagure.lib.git.update_git(
Pierre-Yves Chibon 9c2953
                    request,
Pierre-Yves Chibon 9c2953
                    repo=repo,
Pierre-Yves Chibon 9c2953
                    repofolder=pagure_config["REQUESTS_FOLDER"],
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 9c2953
            flask.flash("Requests git repo updated")
Pierre-Yves Chibon b8f582
Pierre-Yves Chibon 9c2953
        elif (
Pierre-Yves Chibon 9c2953
            regenerate.lower() == "tickets"
Pierre-Yves Chibon 9c2953
            and repo.settings.get("issue_tracker")
Pierre-Yves Chibon 9c2953
            and pagure_config.get("ENABLE_TICKETS")
Pierre-Yves Chibon 9c2953
        ):
Vivek Anand 8ced04
Vivek Anand 8ced04
            # delete the ticket repo and reinit
Vivek Anand 8ced04
            # in case there are no tickets
Vivek Anand 8ced04
            if len(repo.issues) == 0:
Vivek Anand 8ced04
                pagure.lib.git.reinit_git(
Pierre-Yves Chibon 9c2953
                    project=repo, repofolder=pagure_config["TICKETS_FOLDER"]
Vivek Anand 8ced04
                )
Pierre-Yves Chibon 25c04d
            for ticket in repo.issues:
Pierre-Yves Chibon 25c04d
                pagure.lib.git.update_git(
Pierre-Yves Chibon 9c2953
                    ticket,
Pierre-Yves Chibon 9c2953
                    repo=repo,
Pierre-Yves Chibon 9c2953
                    repofolder=pagure_config["TICKETS_FOLDER"],
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 9c2953
            flask.flash("Tickets git repo updated")
Pierre-Yves Chibon 25c04d
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#regen-tab"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 110198
Pierre-Yves Chibon 110198
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/token/new/", methods=("GET", "POST"))</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/token/new", methods=("GET", "POST"))</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/token/new/", methods=("GET", "POST"))</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/token/new", methods=("GET", "POST"))</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/token/new/", methods=("GET", "POST"))</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/token/new", methods=("GET", "POST"))</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/token/new/", methods=("GET", "POST")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/token/new", methods=("GET", "POST")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon cf7f54
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Pierre-Yves Chibon 4501da
def add_token(repo, username=None, namespace=None):
Pierre-Yves Chibon 110198
    """ Add a token to a specified project.
Pierre-Yves Chibon 110198
    """
Pierre-Yves Chibon 110198
Pierre-Yves Chibon 16572e
    repo = flask.g.repo
Pierre-Yves Chibon 110198
Vivek Anand 967335
    if not flask.g.repo_committer:
Pierre-Yves Chibon 0ae8d3
        flask.abort(
Pierre-Yves Chibon c6cc5c
            403,
Pierre-Yves Chibon c6cc5c
            description="You are not allowed to change the settings for "
Pierre-Yves Chibon c6cc5c
            "this project",
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 0ae8d3
Pierre-Yves Chibon 930073
    acls = pagure.lib.query.get_acls(
Pierre-Yves Chibon 9c2953
        flask.g.session, restrict=pagure_config.get("USER_ACLS")
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 110198
    form = pagure.forms.NewTokenForm(acls=acls)
Pierre-Yves Chibon 110198
Pierre-Yves Chibon 110198
    if form.validate_on_submit():
Pierre-Yves Chibon 110198
        try:
Pierre-Yves Chibon 696f19
            pagure.lib.query.add_token_to_user(
Pierre-Yves Chibon b130e5
                flask.g.session,
Pierre-Yves Chibon 110198
                repo,
Pierre-Yves Chibon 60a786
                description=form.description.data.strip() or None,
Pierre-Yves Chibon 110198
                acls=form.acls.data,
Pierre-Yves Chibon 110198
                username=flask.g.fas_user.username,
Pierre-Yves Chibon 110198
            )
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 696f19
            flask.flash("Token created")
Pierre-Yves Chibon 9c2953
            return flask.redirect(
Pierre-Yves Chibon 9c2953
                flask.url_for(
Pierre-Yves Chibon 9c2953
                    "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
                    repo=repo.name,
Pierre-Yves Chibon 9c2953
                    username=username,
Pierre-Yves Chibon 9c2953
                    namespace=namespace,
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 9c2953
                + "#apikeys-tab"
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 110198
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 4635b5
            _log.exception(err)
Pierre-Yves Chibon 9c2953
            flask.flash("API token could not be added", "error")
Pierre-Yves Chibon 110198
Pradeep CE (cep) 9d305f
    # When form is displayed after an empty submission, show an error.
Pierre-Yves Chibon 9c2953
    if form.errors.get("acls"):
Pierre-Yves Chibon 9c2953
        flask.flash("You must select at least one permission.", "error")
Pradeep CE (cep) 9d305f
Pierre-Yves Chibon 110198
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "add_token.html",
Pierre-Yves Chibon 9c2953
        select="settings",
Pierre-Yves Chibon 110198
        form=form,
Pierre-Yves Chibon 110198
        acls=acls,
Pierre-Yves Chibon 110198
        username=username,
Pierre-Yves Chibon 110198
        repo=repo,
Pierre-Yves Chibon 110198
    )
Pierre-Yves Chibon e649cf
Pierre-Yves Chibon e649cf
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/token/renew/<token_id>", methods=["POST"])</token_id></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/token/renew/<token_id>", methods=["POST"])</token_id></repo></namespace>
Pierre-Yves Chibon c8e85f
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/token/renew/<token_id>", methods=["POST"]</token_id></repo></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon c8e85f
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/token/renew/<token_id>",</token_id></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon c8e85f
@login_required
Pierre-Yves Chibon c8e85f
@is_admin_sess_timedout
Pierre-Yves Chibon c8e85f
@is_repo_admin
Pierre-Yves Chibon c8e85f
def renew_api_token(repo, token_id, username=None, namespace=None):
Pierre-Yves Chibon c8e85f
    """ Renew a token to a specified project.
Pierre-Yves Chibon c8e85f
    """
Pierre-Yves Chibon c8e85f
Pierre-Yves Chibon c8e85f
    repo = flask.g.repo
Pierre-Yves Chibon c8e85f
Pierre-Yves Chibon 930073
    token = pagure.lib.query.get_api_token(flask.g.session, token_id)
Pierre-Yves Chibon c8e85f
Pierre-Yves Chibon 9c2953
    if (
Pierre-Yves Chibon 9c2953
        not token
Pierre-Yves Chibon 9c2953
        or token.project.fullname != repo.fullname
Pierre-Yves Chibon 9c2953
        or token.user.username != flask.g.fas_user.username
Pierre-Yves Chibon 9c2953
    ):
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Token not found")
Pierre-Yves Chibon c8e85f
Pierre-Yves Chibon c8e85f
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon c8e85f
Pierre-Yves Chibon c8e85f
    if form.validate_on_submit():
Pierre-Yves Chibon c8e85f
        acls = [acl.name for acl in token.acls]
Pierre-Yves Chibon c8e85f
        try:
Pierre-Yves Chibon 696f19
            pagure.lib.query.add_token_to_user(
Pierre-Yves Chibon c8e85f
                flask.g.session,
Pierre-Yves Chibon c8e85f
                repo,
Pierre-Yves Chibon c8e85f
                description=token.description or None,
Pierre-Yves Chibon c8e85f
                acls=acls,
Pierre-Yves Chibon c8e85f
                username=flask.g.fas_user.username,
Pierre-Yves Chibon c8e85f
            )
Pierre-Yves Chibon c8e85f
            flask.g.session.commit()
Pierre-Yves Chibon 696f19
            flask.flash("Token created")
Pierre-Yves Chibon 9c2953
            return flask.redirect(
Pierre-Yves Chibon 9c2953
                flask.url_for(
Pierre-Yves Chibon 9c2953
                    "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
                    repo=repo.name,
Pierre-Yves Chibon 9c2953
                    username=username,
Pierre-Yves Chibon 9c2953
                    namespace=namespace,
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 9c2953
                + "#apikeys-tab"
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon c8e85f
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon c8e85f
            flask.g.session.rollback()
Pierre-Yves Chibon c8e85f
            _log.exception(err)
Pierre-Yves Chibon 9c2953
            flask.flash("API token could not be renewed", "error")
Pierre-Yves Chibon c8e85f
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#apikeys-tab"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon c8e85f
Pierre-Yves Chibon c8e85f
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/token/revoke/<token_id>", methods=["POST"])</token_id></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/token/revoke/<token_id>", methods=["POST"])</token_id></repo></namespace>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/token/revoke/<token_id>", methods=["POST"]</token_id></repo></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/token/revoke/<token_id>",</token_id></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon cf7f54
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def revoke_api_token(repo, token_id, username=None, namespace=None):
Pierre-Yves Chibon e649cf
    """ Revokie a token to a specified project.
Pierre-Yves Chibon e649cf
    """
Pierre-Yves Chibon e649cf
Pierre-Yves Chibon 16572e
    repo = flask.g.repo
Pierre-Yves Chibon e649cf
Pierre-Yves Chibon 930073
    token = pagure.lib.query.get_api_token(flask.g.session, token_id)
Pierre-Yves Chibon e649cf
Pierre-Yves Chibon 9c2953
    if (
Pierre-Yves Chibon 9c2953
        not token
Pierre-Yves Chibon 9c2953
        or token.project.fullname != repo.fullname
Pierre-Yves Chibon 9c2953
        or token.user.username != flask.g.fas_user.username
Pierre-Yves Chibon 9c2953
    ):
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Token not found")
Pierre-Yves Chibon e649cf
Pierre-Yves Chibon e649cf
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon e649cf
Pierre-Yves Chibon e649cf
    if form.validate_on_submit():
Pierre-Yves Chibon e649cf
        try:
Pierre-Yves Chibon e3dee7
            if token.expiration >= datetime.datetime.utcnow():
Pierre-Yves Chibon e3dee7
                token.expiration = datetime.datetime.utcnow()
Pierre-Yves Chibon b130e5
                flask.g.session.add(token)
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 9c2953
            flask.flash("Token revoked")
Pierre-Yves Chibon e649cf
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 4635b5
            _log.exception(err)
Mary Kate Fain a16918
            message = flask.Markup(
Mary Kate Fain a16918
                "Token could not be revoked,"
Mary Kate Fain a16918
                ' please contact an administrator'
Pierre-Yves Chibon 9c2953
            )
Mary Kate Fain a16918
            flask.flash(message, "error")
Pierre-Yves Chibon e649cf
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#apikeys-tab"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 7ff840
Pierre-Yves Chibon 7ff840
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/<repo>/edit/<path:branchname>/f/<path:filename>", methods=("GET", "POST")</path:filename></path:branchname></repo>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/<namespace>/<repo>/edit/<path:branchname>/f/<path:filename>",</path:filename></path:branchname></repo></namespace>
Pierre-Yves Chibon 9c2953
    methods=("GET", "POST"),
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/edit/<path:branchname>/f/<path:filename>",</path:filename></path:branchname></repo></username>
Pierre-Yves Chibon 9c2953
    methods=("GET", "POST"),
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/edit/<path:branchname>/f/"</path:branchname></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    "<path:filename>",</path:filename>
Pierre-Yves Chibon 9c2953
    methods=("GET", "POST"),
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon cf7f54
@login_required
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 4501da
def edit_file(repo, branchname, filename, username=None, namespace=None):
Pierre-Yves Chibon 7ff840
    """ Edit a file online.
Pierre-Yves Chibon 7ff840
    """
Pierre-Yves Chibon 16572e
    repo = flask.g.repo
Pierre-Yves Chibon 16572e
    repo_obj = flask.g.repo_obj
Pierre-Yves Chibon 7ff840
Pierre-Yves Chibon 930073
    user = pagure.lib.query.search_user(
Pierre-Yves Chibon 9c2953
        flask.g.session, username=flask.g.fas_user.username
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 383b8e
Pierre-Yves Chibon 7ff840
    if repo_obj.is_empty:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Empty repo cannot have a file")
Pierre-Yves Chibon 7ff840
Pierre-Yves Chibon d3f55d
    form = pagure.forms.EditFileForm(emails=user.emails)
Pierre-Yves Chibon d3f55d
Pierre-Yves Chibon 7ff840
    branch = None
Pierre-Yves Chibon 7ff840
    if branchname in repo_obj.listall_branches():
Pierre-Yves Chibon 7ff840
        branch = repo_obj.lookup_branch(branchname)
Pierre-Yves Chibon 91cec1
        commit = branch.peel(pygit2.Commit)
Pierre-Yves Chibon 7ff840
    else:
Pierre-Yves Chibon c6cc5c
        flask.abort(400, description="Invalid branch specified")
Pierre-Yves Chibon 7ff840
Pierre-Yves Chibon 7ff840
    if form.validate_on_submit():
Pierre-Yves Chibon 7ff840
        try:
Aurélien Bompard a7f281
            task = pagure.lib.tasks.update_file_in_git.delay(
Patrick Uiterwijk 8cb224
                repo.name,
Patrick Uiterwijk 8cb224
                repo.namespace,
Patrick Uiterwijk fb0175
                repo.user.username if repo.is_fork else None,
Pierre-Yves Chibon 7ff840
                branch=branchname,
Pierre-Yves Chibon d3f55d
                branchto=form.branch.data,
Pierre-Yves Chibon 7ff840
                filename=filename,
Pierre-Yves Chibon 7ff840
                content=form.content.data,
Pierre-Yves Chibon 9c2953
                message="%s\n\n%s"
Pierre-Yves Chibon 9c2953
                % (
Pierre-Yves Chibon 7ff840
                    form.commit_title.data.strip(),
Pierre-Yves Chibon 9c2953
                    form.commit_message.data.strip(),
Pierre-Yves Chibon 7ff840
                ),
Pierre-Yves Chibon 715218
                username=user.username,
Pierre-Yves Chibon 383b8e
                email=form.email.data,
Aurélien Bompard a7f281
            )
Aurélien Bompard a7f281
            return pagure.utils.wait_for_task(task)
Pierre-Yves Chibon 7ff840
        except pagure.exceptions.PagureException as err:  # pragma: no cover
Pierre-Yves Chibon 4635b5
            _log.exception(err)
Pierre-Yves Chibon 9c2953
            flask.flash("Commit could not be done", "error")
Pierre-Yves Chibon 7ff840
            data = form.content.data
Pierre-Yves Chibon 9c2953
    elif flask.request.method == "GET":
Pierre-Yves Chibon 4148e0
        form.email.data = user.default_email
Pierre-Yves Chibon 7ff840
        content = __get_file_in_tree(
Pierre-Yves Chibon 9c2953
            repo_obj, commit.tree, filename.split("/")
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 7ff840
        if not content or isinstance(content, pygit2.Tree):
Pierre-Yves Chibon c6cc5c
            flask.abort(404, description="File not found")
Pierre-Yves Chibon 3836a7
Pierre-Yves Chibon 801c6f
        if is_binary_string(content.data):
Pierre-Yves Chibon c6cc5c
            flask.abort(400, description="Cannot edit binary files")
Pierre-Yves Chibon 03b973
Pierre-Yves Chibon a443ef
        try:
Pierre-Yves Chibon 9c2953
            data = repo_obj[content.oid].data.decode("utf-8")
Pierre-Yves Chibon a443ef
        except UnicodeDecodeError:  # pragma: no cover
Pierre-Yves Chibon a443ef
            # In theory we shouldn't reach here since we check if the file
Pierre-Yves Chibon a443ef
            # is binary with `is_binary_string()` above
Pierre-Yves Chibon c6cc5c
            flask.abort(400, description="Cannot edit binary files")
Pierre-Yves Chibon a443ef
Pierre-Yves Chibon 7ff840
    else:
Aurélien Bompard 831553
        data = form.content.data
Aurélien Bompard 619e2a
        if not isinstance(data, six.text_type):
Pierre-Yves Chibon 9c2953
            data = data.decode("utf-8")
Pierre-Yves Chibon 7ff840
Pierre-Yves Chibon 7ff840
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "edit_file.html",
Pierre-Yves Chibon 9c2953
        select="tree",
Pierre-Yves Chibon 7ff840
        repo=repo,
Pierre-Yves Chibon 7ff840
        username=username,
Pierre-Yves Chibon 7ff840
        branchname=branchname,
Pierre-Yves Chibon 7ff840
        data=data,
Pierre-Yves Chibon 7ff840
        filename=filename,
Pierre-Yves Chibon 7ff840
        form=form,
Pierre-Yves Chibon 383b8e
        user=user,
Pierre-Yves Chibon 7ff840
    )
Pierre-Yves Chibon a541e0
Pierre-Yves Chibon a541e0
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/b/<path:branchname>/delete", methods=["POST"])</path:branchname></repo>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/<namespace>/<repo>/b/<path:branchname>/delete", methods=["POST"]</path:branchname></repo></namespace>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/b/<path:branchname>/delete", methods=["POST"]</path:branchname></repo></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/b/<path:branchname>/delete",</path:branchname></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon cf7f54
@login_required
Pierre-Yves Chibon 4501da
def delete_branch(repo, branchname, username=None, namespace=None):
Pierre-Yves Chibon a541e0
    """ Delete the branch of a project.
Pierre-Yves Chibon a541e0
    """
Pierre-Yves Chibon 9c2953
    if not flask.g.repo.is_fork and not pagure_config.get(
Pierre-Yves Chibon 9c2953
        "ALLOW_DELETE_BRANCH", True
Pierre-Yves Chibon 9c2953
    ):
Pierre-Yves Chibon c6cc5c
        flask.abort(
Pierre-Yves Chibon c6cc5c
            404,
Pierre-Yves Chibon c6cc5c
            description="This pagure instance does not allow branch deletion",
Pierre-Yves Chibon c6cc5c
        )
Pierre-Yves Chibon 1ee8ed
Pierre-Yves Chibon 16572e
    repo_obj = flask.g.repo_obj
Pierre-Yves Chibon a541e0
Vivek Anand 967335
    if not flask.g.repo_committer:
Pierre-Yves Chibon a541e0
        flask.abort(
Pierre-Yves Chibon c6cc5c
            403,
Pierre-Yves Chibon c6cc5c
            description="You are not allowed to delete branch for "
Pierre-Yves Chibon c6cc5c
            "this project",
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon a541e0
Pierre-Yves Chibon 5aa4e8
    if six.PY2:
Pierre-Yves Chibon 5aa4e8
        branchname = branchname.encode("utf-8")
Pierre-Yves Chibon 5aa4e8
Pierre-Yves Chibon 9c2953
    if branchname == "master":
Pierre-Yves Chibon c6cc5c
        flask.abort(
Pierre-Yves Chibon c6cc5c
            403, description="You are not allowed to delete the master branch"
Pierre-Yves Chibon c6cc5c
        )
Pierre-Yves Chibon a541e0
Pierre-Yves Chibon 16572e
    if branchname not in repo_obj.listall_branches():
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Branch not found")
Pierre-Yves Chibon a541e0
Pierre-Yves Chibon 9c2953
    task = pagure.lib.tasks.delete_branch.delay(
Pierre-Yves Chibon 9c2953
        repo, namespace, username, branchname
Pierre-Yves Chibon 9c2953
    )
Aurélien Bompard a7f281
    return pagure.utils.wait_for_task(task)
Pierre-Yves Chibon 4501da
Pierre-Yves Chibon 4501da
Pierre-Yves Chibon 9c2953
@UI_NS.route("/docs/<repo>/")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/docs/<repo>/<path:filename>")</path:filename></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/docs/<namespace>/<repo>/")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/docs/<namespace>/<repo>/<path:filename>")</path:filename></repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/docs/fork/<username>/<repo>/")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/docs/fork/<username>/<namespace>/<repo>/<path:filename>")</path:filename></repo></namespace></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/docs/fork/<username>/<repo>/")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/docs/fork/<username>/<namespace>/<repo>/<path:filename>")</path:filename></repo></namespace></username>
Pierre-Yves Chibon 4501da
def view_docs(repo, username=None, filename=None, namespace=None):
Pierre-Yves Chibon 4699f0
    """ Display the documentation
Pierre-Yves Chibon 4699f0
    """
Pierre-Yves Chibon 45aebf
    repo = flask.g.repo
Pierre-Yves Chibon 0171c3
Pierre-Yves Chibon 9c2953
    if not pagure_config.get("DOC_APP_URL"):
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="This pagure instance has no doc server")
Pierre-Yves Chibon 39a3da
Pierre-Yves Chibon 4699f0
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "docs.html",
Pierre-Yves Chibon 9c2953
        select="docs",
Pierre-Yves Chibon 45aebf
        repo=repo,
Pierre-Yves Chibon 4699f0
        username=username,
Pierre-Yves Chibon 4699f0
        filename=filename,
Pierre-Yves Chibon 9c2953
        endpoint="view_docs",
Pierre-Yves Chibon 4699f0
    )
Ryan Lerch 1ee5ad
Pierre-Yves Chibon 0fcf17
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/activity/")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/activity")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/activity/")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/activity")</repo></namespace>
Pierre-Yves Chibon 4501da
def view_project_activity(repo, namespace=None):
Ryan Lerch 8eb9dd
    """ Display the activity feed
Ryan Lerch 1ee5ad
    """
Ryan Lerch 8eb9dd
Pierre-Yves Chibon 9c2953
    if not pagure_config.get("DATAGREPPER_URL"):
Ryan Lerch 8eb9dd
        flask.abort(404)
Ryan Lerch 8eb9dd
Pierre-Yves Chibon 45aebf
    repo = flask.g.repo
Ryan Lerch 1ee5ad
Pierre-Yves Chibon 9c2953
    return flask.render_template("activity.html", repo=repo)
Gaurav Kumar 00f2c8
Pierre-Yves Chibon 0fcf17
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/stargazers/")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/stargazers/")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/stargazers/")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/stargazers/")</repo></namespace></username>
Vivek Anand f019f5
def view_stargazers(repo, username=None, namespace=None):
Pierre-Yves Chibon 9c2953
    """ View all the users who have starred the project """
Vivek Anand f019f5
Vivek Anand f019f5
    stargazers = flask.g.repo.stargazers
Vivek Anand f019f5
    users = [star.user for star in stargazers]
Vivek Anand f019f5
    return flask.render_template(
Ryan Lerch e360a1
        "repo_stargazers.html",
Ryan Lerch e360a1
        repo=flask.g.repo,
Ryan Lerch e360a1
        username=username,
Ryan Lerch e360a1
        namespace=namespace,
Patrick Uiterwijk 3f97f6
        users=users,
Pierre-Yves Chibon 9c2953
    )
Vivek Anand f019f5
Vivek Anand f019f5
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/star/<star>", methods=["POST"])</star></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/star/<star>", methods=["POST"])</star></repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/star/<star>", methods=["POST"])</star></repo></namespace>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/star/<star>", methods=["POST"]</star></repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Vivek Anand f019f5
@login_required
Vivek Anand f019f5
def star_project(repo, star, username=None, namespace=None):
Pierre-Yves Chibon 9c2953
    """ Star or Unstar a project
Vivek Anand bd4dd9
Vivek Anand bd4dd9
    :arg repo: string representing the project which has to be starred or
Vivek Anand bd4dd9
    unstarred.
Vivek Anand bd4dd9
    :arg star: either '0' or '1' for unstar and star respectively
Vivek Anand bd4dd9
    :arg username: string representing the user the fork of whose is being
Vivek Anand bd4dd9
    starred or unstarred.
Vivek Anand bd4dd9
    :arg namespace: namespace of the project if any
Pierre-Yves Chibon 9c2953
    """
Vivek Anand f019f5
Pierre-Yves Chibon 9c2953
    return_point = flask.url_for("ui_ns.index")
Pierre-Yves Chibon 9c2953
    if flask.request.referrer is not None and pagure.utils.is_safe_url(
Pierre-Yves Chibon 9c2953
        flask.request.referrer
Pierre-Yves Chibon 9c2953
    ):
Vivek Anand f019f5
        return_point = flask.request.referrer
Vivek Anand f019f5
Vivek Anand f019f5
    form = pagure.forms.ConfirmationForm()
Vivek Anand f019f5
    if not form.validate_on_submit():
Vivek Anand f019f5
        flask.abort(400)
Vivek Anand f019f5
Pierre-Yves Chibon 9c2953
    if star not in ["0", "1"]:
Vivek Anand f019f5
        flask.abort(400)
Vivek Anand f019f5
Vivek Anand f019f5
    try:
Pierre-Yves Chibon 930073
        msg = pagure.lib.query.update_star_project(
Pierre-Yves Chibon b130e5
            flask.g.session,
Vivek Anand f019f5
            user=flask.g.fas_user.username,
Vivek Anand f019f5
            repo=flask.g.repo,
Vivek Anand f019f5
            star=star,
Vivek Anand f019f5
        )
Pierre-Yves Chibon b130e5
        flask.g.session.commit()
Vivek Anand f019f5
        flask.flash(msg)
Vivek Anand f019f5
    except SQLAlchemyError:
Pierre-Yves Chibon 9c2953
        flask.flash("Could not star the project")
Vivek Anand f019f5
Vivek Anand f019f5
    return flask.redirect(return_point)
Vivek Anand f019f5
Vivek Anand f019f5
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/watch/settings/<watch>", methods=["POST"])</watch></repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/watch/settings/<watch>", methods=["POST"])</watch></repo></namespace>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/watch/settings/<watch>", methods=["POST"]</watch></repo></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/watch/settings/<watch>",</watch></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Gaurav Kumar c65751
@login_required
Pierre-Yves Chibon 4501da
def watch_repo(repo, watch, username=None, namespace=None):
Matt Prahl b49f93
    """ Marked for watching or unwatching
Gaurav Kumar 00f2c8
    """
Pierre-Yves Chibon 4501da
Pierre-Yves Chibon 9c2953
    return_point = flask.url_for("ui_ns.index")
Pierre-Yves Chibon b130e5
    if pagure.utils.is_safe_url(flask.request.referrer):
Gaurav Kumar 604af6
        return_point = flask.request.referrer
Gaurav Kumar 00f2c8
Gaurav Kumar 604af6
    form = pagure.forms.ConfirmationForm()
Gaurav Kumar 604af6
    if not form.validate_on_submit():
Gaurav Kumar 604af6
        flask.abort(400)
Gaurav Kumar 00f2c8
Pierre-Yves Chibon 9c2953
    if "%s" % watch not in ["0", "1", "2", "3", "-1"]:
Gaurav Kumar 604af6
        flask.abort(400)
Gaurav Kumar 604af6
Gaurav Kumar 604af6
    try:
Pierre-Yves Chibon 930073
        msg = pagure.lib.query.update_watch_status(
Pierre-Yves Chibon 9c2953
            flask.g.session, flask.g.repo, flask.g.fas_user.username, watch
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon b130e5
        flask.g.session.commit()
Gaurav Kumar 604af6
        flask.flash(msg)
Gaurav Kumar 604af6
    except pagure.exceptions.PagureException as msg:
Pierre-Yves Chibon d9dd52
        _log.debug(msg)
Pierre-Yves Chibon 9c2953
        flask.flash(str(msg), "error")
Gaurav Kumar 00f2c8
Gaurav Kumar 604af6
    return flask.redirect(return_point)
Pierre-Yves Chibon 080c15
Pierre-Yves Chibon 080c15
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/update/public_notif", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/public_notif", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/public_notif", methods=["POST"])</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/public_notif", methods=["POST"]</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 080c15
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 080c15
def update_public_notifications(repo, username=None, namespace=None):
Pierre-Yves Chibon 080c15
    """ Update the public notification settings of a project.
Pierre-Yves Chibon 080c15
    """
Pierre-Yves Chibon 080c15
Pierre-Yves Chibon 080c15
    repo = flask.g.repo
Pierre-Yves Chibon 080c15
Pierre-Yves Chibon 080c15
    form = pagure.forms.PublicNotificationForm()
Pierre-Yves Chibon 080c15
Pierre-Yves Chibon 080c15
    if form.validate_on_submit():
Pierre-Yves Chibon 080c15
        issue_notifs = [
Pierre-Yves Chibon 9c2953
            w.strip() for w in form.issue_notifs.data.split(",") if w.strip()
Pierre-Yves Chibon 080c15
        ]
Pierre-Yves Chibon 080c15
        pr_notifs = [
Pierre-Yves Chibon 9c2953
            w.strip() for w in form.pr_notifs.data.split(",") if w.strip()
Pierre-Yves Chibon 080c15
        ]
Pierre-Yves Chibon 080c15
Pierre-Yves Chibon 080c15
        try:
Pierre-Yves Chibon 080c15
            notifs = repo.notifications
Pierre-Yves Chibon 9c2953
            notifs["issues"] = issue_notifs
Pierre-Yves Chibon 9c2953
            notifs["requests"] = pr_notifs
Pierre-Yves Chibon 080c15
            repo.notifications = notifs
Pierre-Yves Chibon 080c15
Pierre-Yves Chibon b130e5
            flask.g.session.add(repo)
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 9c2953
            flask.flash("Project updated")
Pierre-Yves Chibon 080c15
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 9c2953
            flask.flash(str(err), "error")
Pierre-Yves Chibon e1cd0d
    else:
Pierre-Yves Chibon e1cd0d
        flask.flash(
Pierre-Yves Chibon 9c2953
            "Unable to adjust one or more of the email provided", "error"
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 080c15
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            namespace=repo.namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#publicnotifications-tab"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 827c77
Pierre-Yves Chibon 827c77
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/update/close_status", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/update/close_status", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/update/close_status", methods=["POST"])</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/update/close_status", methods=["POST"]</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 827c77
@login_required
Clement Verna afe475
@has_issue_tracker
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 827c77
def update_close_status(repo, username=None, namespace=None):
Pierre-Yves Chibon 827c77
    """ Update the close_status of a project.
Pierre-Yves Chibon 827c77
    """
Pierre-Yves Chibon 827c77
Pierre-Yves Chibon 827c77
    repo = flask.g.repo
Pierre-Yves Chibon 827c77
Pierre-Yves Chibon 827c77
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon 827c77
Pierre-Yves Chibon 827c77
    if form.validate_on_submit():
Pierre-Yves Chibon 827c77
        close_status = [
Pierre-Yves Chibon 9c2953
            w.strip()
Pierre-Yves Chibon 9c2953
            for w in flask.request.form.getlist("close_status")
Pierre-Yves Chibon 827c77
            if w.strip()
Pierre-Yves Chibon 827c77
        ]
Pierre-Yves Chibon 827c77
        try:
Pierre-Yves Chibon 827c77
            repo.close_status = close_status
Pierre-Yves Chibon b130e5
            flask.g.session.add(repo)
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 9c2953
            flask.flash("List of close status updated")
Pierre-Yves Chibon 827c77
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 9c2953
            flask.flash(str(err), "error")
Lubomír Sedlář 9871f9
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#closestatus-tab"
Pierre-Yves Chibon 9c2953
    )
Lubomír Sedlář 9871f9
Lubomír Sedlář 9871f9
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/update/quick_replies", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/update/quick_replies", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/update/quick_replies", methods=["POST"])</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/update/quick_replies",</repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Lubomír Sedlář 9871f9
@login_required
Clement Verna 36168f
@has_issue_tracker
Clement Verna 36168f
@has_pr_enabled
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Lubomír Sedlář 9871f9
def update_quick_replies(repo, username=None, namespace=None):
Lubomír Sedlář 9871f9
    """ Update the quick_replies of a project.
Lubomír Sedlář 9871f9
    """
Lubomír Sedlář 9871f9
Lubomír Sedlář 9871f9
    repo = flask.g.repo
Lubomír Sedlář 9871f9
Pierre-Yves Chibon 9c2953
    if not repo.settings.get("pull_requests", True):
Pierre-Yves Chibon c6cc5c
        flask.abort(
Pierre-Yves Chibon c6cc5c
            404, description="Pull requests are disabled for this project"
Pierre-Yves Chibon c6cc5c
        )
Lubomír Sedlář 9871f9
Lubomír Sedlář 9871f9
    form = pagure.forms.ConfirmationForm()
Lubomír Sedlář 9871f9
Lubomír Sedlář 9871f9
    if form.validate_on_submit():
Lubomír Sedlář 9871f9
        quick_replies = [
Pierre-Yves Chibon 9c2953
            w.strip()
Pierre-Yves Chibon 9c2953
            for w in flask.request.form.getlist("quick_reply")
Lubomír Sedlář 9871f9
            if w.strip()
Lubomír Sedlář 9871f9
        ]
Lubomír Sedlář 9871f9
        try:
Lubomír Sedlář 9871f9
            repo.quick_replies = quick_replies
Pierre-Yves Chibon b130e5
            flask.g.session.add(repo)
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 9c2953
            flask.flash("List of quick replies updated")
Lubomír Sedlář 9871f9
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 9c2953
            flask.flash(str(err), "error")
Pierre-Yves Chibon 827c77
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#quickreplies-tab"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 3841b3
Pierre-Yves Chibon 3841b3
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/update/custom_keys", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/update/custom_keys", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/update/custom_keys", methods=["POST"])</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/update/custom_keys", methods=["POST"]</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 3841b3
@login_required
Clement Verna afe475
@has_issue_tracker
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon 3841b3
def update_custom_keys(repo, username=None, namespace=None):
Pierre-Yves Chibon 3841b3
    """ Update the custom_keys of a project.
Pierre-Yves Chibon 3841b3
    """
Pierre-Yves Chibon 3841b3
Pierre-Yves Chibon 3841b3
    repo = flask.g.repo
Pierre-Yves Chibon 3841b3
Pierre-Yves Chibon 3841b3
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon 3841b3
Pierre-Yves Chibon 3841b3
    if form.validate_on_submit():
Pierre-Yves Chibon 3841b3
        custom_keys = [
Pierre-Yves Chibon 9c2953
            w.strip()
Pierre-Yves Chibon 9c2953
            for w in flask.request.form.getlist("custom_keys")
Pierre-Yves Chibon 3841b3
            if w.strip()
Pierre-Yves Chibon 3841b3
        ]
Pierre-Yves Chibon 3841b3
        custom_keys_type = [
Pierre-Yves Chibon 9c2953
            w.strip()
Pierre-Yves Chibon 9c2953
            for w in flask.request.form.getlist("custom_keys_type")
Pierre-Yves Chibon 3841b3
            if w.strip()
Pierre-Yves Chibon 3841b3
        ]
Mark Reynolds e18f6c
        custom_keys_data = [
Pierre-Yves Chibon 9c2953
            w.strip() for w in flask.request.form.getlist("custom_keys_data")
Mark Reynolds e18f6c
        ]
Mark Reynolds a8f1ac
        custom_keys_notify = []
Mark Reynolds a8f1ac
        for idx in range(len(custom_keys)):
Aurélien Bompard 619e2a
            custom_keys_notify.append(
Pierre-Yves Chibon 9c2953
                "%s"
Pierre-Yves Chibon 9c2953
                % flask.request.form.get("custom_keys_notify-%s" % (idx + 1))
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 3841b3
Pierre-Yves Chibon 3841b3
        try:
Pierre-Yves Chibon 930073
            msg = pagure.lib.query.set_custom_key_fields(
Pierre-Yves Chibon 9c2953
                flask.g.session,
Pierre-Yves Chibon 9c2953
                repo,
Pierre-Yves Chibon 9c2953
                custom_keys,
Pierre-Yves Chibon 9c2953
                custom_keys_type,
Pierre-Yves Chibon 9c2953
                custom_keys_data,
Pierre-Yves Chibon 9c2953
                custom_keys_notify,
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 3841b3
            flask.flash(msg)
Pierre-Yves Chibon 3841b3
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 9c2953
            flask.flash(str(err), "error")
Pierre-Yves Chibon 3841b3
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#customfields-tab"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon abf91e
Pierre-Yves Chibon abf91e
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/delete/report", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/delete/report", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/delete/report", methods=["POST"])</repo></username>
Pierre-Yves Chibon b130e5
@UI_NS.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/delete/report", methods=["POST"]</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon abf91e
@login_required
Clement Verna afe475
@has_issue_tracker
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon abf91e
def delete_report(repo, username=None, namespace=None):
Pierre-Yves Chibon abf91e
    """ Delete a report from a project.
Pierre-Yves Chibon abf91e
    """
Pierre-Yves Chibon abf91e
Pierre-Yves Chibon abf91e
    repo = flask.g.repo
Pierre-Yves Chibon abf91e
Pierre-Yves Chibon abf91e
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon abf91e
Pierre-Yves Chibon abf91e
    if form.validate_on_submit():
Pierre-Yves Chibon 9c2953
        report = flask.request.form.get("report")
Pierre-Yves Chibon abf91e
        reports = repo.reports
Pierre-Yves Chibon abf91e
        if report not in reports:
Pierre-Yves Chibon 9c2953
            flask.flash("Unknown report: %s" % report, "error")
Pierre-Yves Chibon abf91e
        else:
Pierre-Yves Chibon 6d4fc2
            del reports[report]
Pierre-Yves Chibon abf91e
            repo.reports = reports
Pierre-Yves Chibon abf91e
            try:
Pierre-Yves Chibon b130e5
                flask.g.session.add(repo)
Pierre-Yves Chibon b130e5
                flask.g.session.commit()
Pierre-Yves Chibon 9c2953
                flask.flash("List of reports updated")
Pierre-Yves Chibon abf91e
            except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
                flask.g.session.rollback()
Pierre-Yves Chibon 9c2953
                flask.flash(str(err), "error")
Pierre-Yves Chibon abf91e
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_settings",
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
        + "#reports-tab"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon fd7da8
Pierre-Yves Chibon fd7da8
Patrick Uiterwijk 3f97f6
@UI_NS.route("/<repo>/torepospanner", methods=["POST"])</repo>
Patrick Uiterwijk 3f97f6
@UI_NS.route("/<namespace>/<repo>/torepospanner", methods=["POST"])</repo></namespace>
Patrick Uiterwijk 3f97f6
@UI_NS.route("/fork/<username>/<repo>/torepospanner", methods=["POST"])</repo></username>
Patrick Uiterwijk 3f97f6
@UI_NS.route(
Patrick Uiterwijk 3f97f6
    "/fork/<username>/<namespace>/<repo>/torepospanner", methods=["POST"]</repo></namespace></username>
Patrick Uiterwijk 3f97f6
)
Patrick Uiterwijk 3f97f6
@login_required
Patrick Uiterwijk 3f97f6
@is_admin_sess_timedout
Patrick Uiterwijk 3f97f6
@is_repo_admin
Patrick Uiterwijk 3f97f6
def move_to_repospanner(repo, username=None, namespace=None):
Patrick Uiterwijk 3f97f6
    """ Give a project to someone else.
Patrick Uiterwijk 3f97f6
    """
Patrick Uiterwijk 3f97f6
    repo = flask.g.repo
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
    if not pagure.utils.is_admin():
Patrick Uiterwijk 3f97f6
        flask.abort(
Pierre-Yves Chibon c6cc5c
            403,
Pierre-Yves Chibon c6cc5c
            description="You are not allowed to transfer this project "
Pierre-Yves Chibon c6cc5c
            "to repoSpanner",
Patrick Uiterwijk 3f97f6
        )
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
    if not pagure_config.get("REPOSPANNER_ADMIN_MIGRATION"):
Pierre-Yves Chibon c6cc5c
        flask.abort(
Pierre-Yves Chibon c6cc5c
            403, description="It is not allowed to request migration of a repo"
Pierre-Yves Chibon c6cc5c
        )
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
    form = pagure.forms.ConfirmationForm()
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
    if form.validate_on_submit():
Patrick Uiterwijk 3f97f6
        region = flask.request.form.get("region", "").strip()
Patrick Uiterwijk 3f97f6
        if not region:
Pierre-Yves Chibon c6cc5c
            flask.abort(404, description="No target region specified")
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        if region not in pagure_config.get("REPOSPANNER_REGIONS"):
Pierre-Yves Chibon c6cc5c
            flask.abort(404, description="Invalid region specified")
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        _log.info(
Patrick Uiterwijk 3f97f6
            "Repo %s requested to be migrated to repoSpanner region %s",
Patrick Uiterwijk 3f97f6
            repo.fullname,
Patrick Uiterwijk 3f97f6
            region,
Patrick Uiterwijk 3f97f6
        )
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        task = pagure.lib.tasks.move_to_repospanner.delay(
Patrick Uiterwijk 3f97f6
            repo.name, namespace, username, region
Patrick Uiterwijk 3f97f6
        )
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        return pagure.utils.wait_for_task(
Patrick Uiterwijk 3f97f6
            task,
Patrick Uiterwijk 3f97f6
            prev=flask.url_for(
Patrick Uiterwijk 3f97f6
                "ui_ns.view_repo",
Patrick Uiterwijk 3f97f6
                username=username,
Patrick Uiterwijk 3f97f6
                repo=repo.name,
Patrick Uiterwijk 3f97f6
                namespace=namespace,
Patrick Uiterwijk 3f97f6
            ),
Patrick Uiterwijk 3f97f6
        )
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
    return flask.redirect(
Patrick Uiterwijk 3f97f6
        flask.url_for(
Patrick Uiterwijk 3f97f6
            "ui_ns.view_repo",
Patrick Uiterwijk 3f97f6
            username=username,
Patrick Uiterwijk 3f97f6
            repo=repo.name,
Patrick Uiterwijk 3f97f6
            namespace=namespace,
Patrick Uiterwijk 3f97f6
        )
Patrick Uiterwijk 3f97f6
    )
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/give", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/give", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/give", methods=["POST"])</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/give", methods=["POST"])</repo></namespace></username>
Pierre-Yves Chibon fd7da8
@login_required
Clement Verna 91fd11
@is_admin_sess_timedout
Clement Verna 91fd11
@is_repo_admin
Pierre-Yves Chibon fd7da8
def give_project(repo, username=None, namespace=None):
Pierre-Yves Chibon fd7da8
    """ Give a project to someone else.
Pierre-Yves Chibon fd7da8
    """
Pierre-Yves Chibon 9c2953
    if not pagure_config.get("ENABLE_GIVE_PROJECTS", True):
Pierre-Yves Chibon fd7da8
        flask.abort(404)
Pierre-Yves Chibon fd7da8
Pierre-Yves Chibon fd7da8
    repo = flask.g.repo
Pierre-Yves Chibon fd7da8
Pierre-Yves Chibon 9c2953
    if (
Pierre-Yves Chibon 9c2953
        flask.g.fas_user.username != repo.user.user
Pierre-Yves Chibon 9c2953
        and not pagure.utils.is_admin()
Pierre-Yves Chibon 9c2953
    ):
Pierre-Yves Chibon c6cc5c
        flask.abort(
Pierre-Yves Chibon c6cc5c
            403, description="You are not allowed to give this project"
Pierre-Yves Chibon c6cc5c
        )
Pierre-Yves Chibon fd7da8
Pierre-Yves Chibon fd7da8
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon fd7da8
Pierre-Yves Chibon fd7da8
    if form.validate_on_submit():
Pierre-Yves Chibon 9c2953
        new_username = flask.request.form.get("user", "").strip()
Pierre-Yves Chibon 6f43f3
        if not new_username:
Pierre-Yves Chibon c6cc5c
            flask.abort(404, description="No user specified")
Pierre-Yves Chibon 930073
        new_owner = pagure.lib.query.search_user(
Pierre-Yves Chibon 9c2953
            flask.g.session, username=new_username
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon fd7da8
        if not new_owner:
Pierre-Yves Chibon c6cc5c
            flask.abort(
Pierre-Yves Chibon c6cc5c
                404, description="No such user %s found" % new_username
Pierre-Yves Chibon c6cc5c
            )
Pierre-Yves Chibon 02088b
Pierre-Yves Chibon 02088b
        failed = False
Pierre-Yves Chibon fd7da8
        try:
mprahl 8f40ee
            old_main_admin = repo.user.user
Pierre-Yves Chibon 930073
            pagure.lib.query.set_project_owner(
Pierre-Yves Chibon 9c2953
                flask.g.session,
Pierre-Yves Chibon 9c2953
                repo,
Pierre-Yves Chibon 9c2953
                new_owner,
Pierre-Yves Chibon 9c2953
                required_groups=pagure_config.get("REQUIRED_GROUPS"),
Pierre-Yves Chibon 411690
            )
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 411690
        except pagure.exceptions.PagureException as msg:
Pierre-Yves Chibon 02088b
            failed = True
Pierre-Yves Chibon 411690
            flask.g.session.rollback()
Pierre-Yves Chibon 411690
            _log.debug(msg)
Pierre-Yves Chibon 9c2953
            flask.flash(str(msg), "error")
Pierre-Yves Chibon 4ec145
        except SQLAlchemyError:  # pragma: no cover
Pierre-Yves Chibon 02088b
            failed = True
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon ff8c8b
            flask.flash(
Pierre-Yves Chibon 9c2953
                "Due to a database error, this project could not be "
Pierre-Yves Chibon 9c2953
                "transferred.",
Pierre-Yves Chibon 9c2953
                "error",
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon 02088b
        if not failed:
Pierre-Yves Chibon 02088b
            try:
Pierre-Yves Chibon 02088b
                # If the person doing the action is the former main admin, keep
Pierre-Yves Chibon 02088b
                # them as admins
Pierre-Yves Chibon 02088b
                if flask.g.fas_user.username == old_main_admin:
Pierre-Yves Chibon 02088b
                    pagure.lib.query.add_user_to_project(
Pierre-Yves Chibon 02088b
                        flask.g.session,
Pierre-Yves Chibon 02088b
                        repo,
Pierre-Yves Chibon 02088b
                        new_user=flask.g.fas_user.username,
Pierre-Yves Chibon 02088b
                        user=flask.g.fas_user.username,
Pierre-Yves Chibon 02088b
                    )
Pierre-Yves Chibon 02088b
                flask.g.session.commit()
Pierre-Yves Chibon 02088b
            except pagure.exceptions.PagureException as msg:
Pierre-Yves Chibon 02088b
                flask.g.session.rollback()
Pierre-Yves Chibon 02088b
                _log.debug(msg)
Pierre-Yves Chibon 02088b
            except SQLAlchemyError:  # pragma: no cover
Pierre-Yves Chibon 02088b
                flask.g.session.rollback()
Pierre-Yves Chibon 02088b
                flask.flash(
Pierre-Yves Chibon 02088b
                    "Due to a database error, this access could not be "
Pierre-Yves Chibon 02088b
                    "entirely set.",
Pierre-Yves Chibon 02088b
                    "error",
Pierre-Yves Chibon 02088b
                )
Pierre-Yves Chibon 02088b
Pierre-Yves Chibon 02088b
            pagure.lib.git.generate_gitolite_acls(project=repo)
Pierre-Yves Chibon 02088b
            flask.flash(
Pierre-Yves Chibon 02088b
                "The project has been transferred to %s" % new_username
Pierre-Yves Chibon 02088b
            )
Pierre-Yves Chibon 02088b
Pierre-Yves Chibon 9c2953
    return flask.redirect(
Pierre-Yves Chibon 9c2953
        flask.url_for(
Pierre-Yves Chibon 9c2953
            "ui_ns.view_repo",
Pierre-Yves Chibon 9c2953
            username=username,
Pierre-Yves Chibon 9c2953
            repo=repo.name,
Pierre-Yves Chibon 9c2953
            namespace=namespace,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/dowait/")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/dowait")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/dowait/")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/dowait")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/dowait/")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/dowait")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/dowait/")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/dowait")</repo></namespace></username>
Patrick Uiterwijk 7b9080
def project_dowait(repo, username=None, namespace=None):
Patrick Uiterwijk 7b9080
    """ Schedules a task that just waits 10 seconds for testing locking.
Patrick Uiterwijk 7b9080
Patrick Uiterwijk 7b9080
    This is not available unless ALLOW_PROJECT_DOWAIT is set to True, which
Patrick Uiterwijk 7b9080
    should only ever be done in test instances.
Patrick Uiterwijk 7b9080
    """
Pierre-Yves Chibon 9c2953
    if not pagure_config.get("ALLOW_PROJECT_DOWAIT", False):
Pierre-Yves Chibon c6cc5c
        flask.abort(401, description="No")
Patrick Uiterwijk 7b9080
Aurélien Bompard a7f281
    task = pagure.lib.tasks.project_dowait.delay(
Pierre-Yves Chibon 9c2953
        name=repo, namespace=namespace, user=username
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk 7b9080
Aurélien Bompard a7f281
    return pagure.utils.wait_for_task(task)
Pierre-Yves Chibon 716362
Pierre-Yves Chibon 716362
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/stats/")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<repo>/stats")</repo>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/stats/")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/<namespace>/<repo>/stats")</repo></namespace>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/stats/")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<repo>/stats")</repo></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/stats/")</repo></namespace></username>
Pierre-Yves Chibon 9c2953
@UI_NS.route("/fork/<username>/<namespace>/<repo>/stats")</repo></namespace></username>
Pierre-Yves Chibon 716362
def view_stats(repo, username=None, namespace=None):
Pierre-Yves Chibon 716362
    """ Displays some statistics about the specified repo.
Pierre-Yves Chibon 716362
    """
Pierre-Yves Chibon 716362
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "repo_stats.html", select="stats", username=username, repo=flask.g.repo
Pierre-Yves Chibon 716362
    )
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
@UI_NS.route("/<repo>/update/tags", methods=["POST"])</repo>
Pierre-Yves Chibon d36429
@UI_NS.route("/<namespace>/<repo>/update/tags", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon d36429
@login_required
Pierre-Yves Chibon d36429
@is_repo_admin
Pierre-Yves Chibon d86b5c
@has_issue_or_pr_enabled
Pierre-Yves Chibon d36429
def update_tags(repo, username=None, namespace=None):
Pierre-Yves Chibon d36429
    """ Update the tags of a project.
Pierre-Yves Chibon d36429
    """
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
    repo = flask.g.repo
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
    form = pagure.forms.ConfirmationForm()
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
    error = False
Pierre-Yves Chibon d36429
    if form.validate_on_submit():
Pierre-Yves Chibon d36429
        # Uniquify and order preserving
Pierre-Yves Chibon d36429
        seen = set()
Pierre-Yves Chibon d36429
        tags = [
Pierre-Yves Chibon d36429
            tag.strip()
Pierre-Yves Chibon d36429
            for tag in flask.request.form.getlist("tag")
Pierre-Yves Chibon d36429
            if tag.strip()
Pierre-Yves Chibon d36429
            and tag.strip() not in seen  # noqa
Pierre-Yves Chibon d36429
            and not seen.add(tag.strip())
Pierre-Yves Chibon d36429
        ]
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
        tag_descriptions = [
Pierre-Yves Chibon d36429
            desc.strip()
Pierre-Yves Chibon d36429
            for desc in flask.request.form.getlist("tag_description")
Pierre-Yves Chibon d36429
        ]
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
        # Uniquify and order preserving
Pierre-Yves Chibon d36429
        colors = [
Pierre-Yves Chibon d36429
            col.strip()
Pierre-Yves Chibon d36429
            for col in flask.request.form.getlist("tag_color")
Pierre-Yves Chibon d36429
            if col.strip()
Pierre-Yves Chibon d36429
        ]
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
        pattern = re.compile(pagure.forms.TAGS_REGEX, re.IGNORECASE)
Pierre-Yves Chibon d36429
        for tag in tags:
Pierre-Yves Chibon d36429
            if not pattern.match(tag):
Pierre-Yves Chibon d36429
                flask.flash(
Pierre-Yves Chibon d36429
                    "Tag: %s contains one or more invalid characters" % tag,
Pierre-Yves Chibon d36429
                    "error",
Pierre-Yves Chibon d36429
                )
Pierre-Yves Chibon d36429
                error = True
Pierre-Yves Chibon d36429
Karsten Hopp b310af
        color_pattern = re.compile(r"^#\w{3,6}$")
Pierre-Yves Chibon d36429
        for color in colors:
Pierre-Yves Chibon d36429
            if not color_pattern.match(color):
Pierre-Yves Chibon d36429
                flask.flash(
Pierre-Yves Chibon d36429
                    "Color: %s does not match the expected pattern" % color,
Pierre-Yves Chibon d36429
                    "error",
Pierre-Yves Chibon d36429
                )
Pierre-Yves Chibon d36429
                error = True
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
        if not (len(tags) == len(colors) == len(tag_descriptions)):
Pierre-Yves Chibon d36429
            error = True
Pierre-Yves Chibon d36429
            # Store the lengths because we are going to use them a lot
Pierre-Yves Chibon d36429
            len_tags = len(tags)
Pierre-Yves Chibon d36429
            len_tag_descriptions = len(tag_descriptions)
Pierre-Yves Chibon d36429
            len_colors = len(colors)
Pierre-Yves Chibon d36429
            error_message = "Error: Incomplete request. "
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
            if len_colors > len_tags or len_tag_descriptions > len_tags:
Pierre-Yves Chibon d36429
                error_message += "One or more tag fields missing."
Pierre-Yves Chibon d36429
            elif len_colors < len_tags:
Pierre-Yves Chibon d36429
                error_message += "One or more tag color fields missing."
Pierre-Yves Chibon d36429
            elif len_tag_descriptions < len_tags:
Pierre-Yves Chibon d36429
                error_message += "One or more tag description fields missing."
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
            flask.flash(error_message, "error")
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
        if not error:
Pierre-Yves Chibon d36429
            known_tags = [tag.tag for tag in repo.tags_colored]
Pierre-Yves Chibon d36429
            for idx, tag in enumerate(tags):
Pierre-Yves Chibon d36429
                if tag in known_tags:
Pierre-Yves Chibon d36429
                    flask.flash("Duplicated tag: %s" % tag, "error")
Pierre-Yves Chibon d36429
                    break
Pierre-Yves Chibon d36429
                try:
Pierre-Yves Chibon 930073
                    pagure.lib.query.new_tag(
Pierre-Yves Chibon d36429
                        flask.g.session,
Pierre-Yves Chibon d36429
                        tag,
Pierre-Yves Chibon d36429
                        tag_descriptions[idx],
Pierre-Yves Chibon d36429
                        colors[idx],
Pierre-Yves Chibon d36429
                        repo.id,
Pierre-Yves Chibon d36429
                    )
Pierre-Yves Chibon d36429
                    flask.g.session.commit()
Pierre-Yves Chibon d36429
                    flask.flash("Tags updated")
Pierre-Yves Chibon d36429
                except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon d36429
                    flask.g.session.rollback()
Pierre-Yves Chibon d36429
                    flask.flash(str(err), "error")
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
    return flask.redirect(
Pierre-Yves Chibon d36429
        flask.url_for(
Pierre-Yves Chibon d36429
            "ui_ns.view_settings",
Pierre-Yves Chibon d36429
            username=username,
Pierre-Yves Chibon d36429
            repo=repo.name,
Pierre-Yves Chibon d36429
            namespace=namespace,
Pierre-Yves Chibon d36429
        )
Pierre-Yves Chibon d36429
        + "#projecttags-tab"
Pierre-Yves Chibon d36429
    )
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
@UI_NS.route("/<repo>/droptag/", methods=["POST"])</repo>
Pierre-Yves Chibon d36429
@UI_NS.route("/<namespace>/<repo>/droptag/", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon d36429
@UI_NS.route("/fork/<username>/<repo>/droptag/", methods=["POST"])</repo></username>
Pierre-Yves Chibon d36429
@UI_NS.route("/fork/<username>/<namespace>/<repo>/droptag/", methods=["POST"])</repo></namespace></username>
Pierre-Yves Chibon d36429
@login_required
Pierre-Yves Chibon d36429
@is_repo_admin
Pierre-Yves Chibon d86b5c
@has_issue_or_pr_enabled
Pierre-Yves Chibon d36429
def remove_tag(repo, username=None, namespace=None):
Pierre-Yves Chibon d36429
    """ Remove the specified tag, associated with the issues, from the project.
Pierre-Yves Chibon d36429
    """
Pierre-Yves Chibon d36429
    repo = flask.g.repo
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
    form = pagure.forms.DeleteIssueTagForm()
Pierre-Yves Chibon d36429
    if form.validate_on_submit():
Pierre-Yves Chibon d36429
        tags = form.tag.data
Pierre-Yves Chibon d36429
        tags = [tag.strip() for tag in tags.split(",")]
Pierre-Yves Chibon d36429
Pierre-Yves Chibon 930073
        msgs = pagure.lib.query.remove_tags(
Pierre-Yves Chibon d36429
            flask.g.session, repo, tags, user=flask.g.fas_user.username
Pierre-Yves Chibon d36429
        )
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
        try:
Pierre-Yves Chibon d36429
            flask.g.session.commit()
Pierre-Yves Chibon d36429
            for msg in msgs:
Pierre-Yves Chibon d36429
                flask.flash(msg)
Pierre-Yves Chibon d36429
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon d36429
            flask.g.session.rollback()
Pierre-Yves Chibon d36429
            _log.error(err)
Pierre-Yves Chibon d36429
            flask.flash("Could not remove tag: %s" % ",".join(tags), "error")
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
    return flask.redirect(
Pierre-Yves Chibon d36429
        flask.url_for(
Pierre-Yves Chibon d36429
            "ui_ns.view_settings",
Pierre-Yves Chibon d36429
            repo=repo.name,
Pierre-Yves Chibon d36429
            username=username,
Pierre-Yves Chibon d36429
            namespace=repo.namespace,
Pierre-Yves Chibon d36429
        )
Pierre-Yves Chibon d36429
        + "#projecttags-tab"
Pierre-Yves Chibon d36429
    )
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
@UI_NS.route("/<repo>/tag/<tag>/edit/", methods=("GET", "POST"))</tag></repo>
Pierre-Yves Chibon d36429
@UI_NS.route("/<repo>/tag/<tag>/edit", methods=("GET", "POST"))</tag></repo>
Pierre-Yves Chibon d36429
@UI_NS.route("/<namespace>/<repo>/tag/<tag>/edit/", methods=("GET", "POST"))</tag></repo></namespace>
Pierre-Yves Chibon d36429
@UI_NS.route("/<namespace>/<repo>/tag/<tag>/edit", methods=("GET", "POST"))</tag></repo></namespace>
Pierre-Yves Chibon d36429
@UI_NS.route(
Pierre-Yves Chibon d36429
    "/fork/<username>/<repo>/tag/<tag>/edit/", methods=("GET", "POST")</tag></repo></username>
Pierre-Yves Chibon d36429
)
Pierre-Yves Chibon d36429
@UI_NS.route("/fork/<username>/<repo>/tag/<tag>/edit", methods=("GET", "POST"))</tag></repo></username>
Pierre-Yves Chibon d36429
@UI_NS.route(
Pierre-Yves Chibon d36429
    "/fork/<username>/<namespace>/<repo>/tag/<tag>/edit/",</tag></repo></namespace></username>
Pierre-Yves Chibon d36429
    methods=("GET", "POST"),
Pierre-Yves Chibon d36429
)
Pierre-Yves Chibon d36429
@UI_NS.route(
Pierre-Yves Chibon d36429
    "/fork/<username>/<namespace>/<repo>/tag/<tag>/edit",</tag></repo></namespace></username>
Pierre-Yves Chibon d36429
    methods=("GET", "POST"),
Pierre-Yves Chibon d36429
)
Pierre-Yves Chibon d36429
@login_required
Pierre-Yves Chibon d36429
@is_repo_admin
Pierre-Yves Chibon d86b5c
@has_issue_or_pr_enabled
Pierre-Yves Chibon d36429
def edit_tag(repo, tag, username=None, namespace=None):
Pierre-Yves Chibon d36429
    """ Edit the specified tag associated with the issues of a project.
Pierre-Yves Chibon d36429
    """
Pierre-Yves Chibon d36429
    repo = flask.g.repo
Pierre-Yves Chibon d36429
Pierre-Yves Chibon 930073
    tags = pagure.lib.query.get_tags_of_project(flask.g.session, repo)
Pierre-Yves Chibon d36429
    if not tags:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Project has no tags to edit")
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
    # Check the tag exists, and get its old/original color
Pierre-Yves Chibon 930073
    tagobj = pagure.lib.query.get_colored_tag(flask.g.session, tag, repo.id)
Pierre-Yves Chibon d36429
    if not tagobj:
Pierre-Yves Chibon c6cc5c
        flask.abort(404, description="Tag %s not found in this project" % tag)
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
    form = pagure.forms.AddIssueTagForm()
Pierre-Yves Chibon d36429
    if form.validate_on_submit():
Pierre-Yves Chibon d36429
        new_tag = form.tag.data
Pierre-Yves Chibon d36429
        new_tag_description = form.tag_description.data
Pierre-Yves Chibon d36429
        new_tag_color = form.tag_color.data
Pierre-Yves Chibon d36429
Pierre-Yves Chibon 930073
        msgs = pagure.lib.query.edit_issue_tags(
Pierre-Yves Chibon d36429
            flask.g.session,
Pierre-Yves Chibon d36429
            repo,
Pierre-Yves Chibon d36429
            tagobj,
Pierre-Yves Chibon d36429
            new_tag,
Pierre-Yves Chibon d36429
            new_tag_description,
Pierre-Yves Chibon d36429
            new_tag_color,
Pierre-Yves Chibon d36429
            user=flask.g.fas_user.username,
Pierre-Yves Chibon d36429
        )
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
        try:
Pierre-Yves Chibon d36429
            flask.g.session.commit()
Pierre-Yves Chibon d36429
            for msg in msgs:
Pierre-Yves Chibon d36429
                flask.flash(msg)
Pierre-Yves Chibon d36429
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon d36429
            flask.g.session.rollback()
Pierre-Yves Chibon d36429
            _log.error(err)
Pierre-Yves Chibon d36429
            flask.flash("Could not edit tag: %s" % tag, "error")
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
        return flask.redirect(
Pierre-Yves Chibon d36429
            flask.url_for(
Pierre-Yves Chibon d36429
                "ui_ns.view_settings",
Pierre-Yves Chibon d36429
                repo=repo.name,
Pierre-Yves Chibon d36429
                username=username,
Pierre-Yves Chibon d36429
                namespace=repo.namespace,
Pierre-Yves Chibon d36429
            )
Pierre-Yves Chibon d36429
            + "#projecttags-tab"
Pierre-Yves Chibon d36429
        )
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
    elif flask.request.method == "GET":
Pierre-Yves Chibon d36429
        tag_color = tagobj.tag_color
Pierre-Yves Chibon d36429
        if tag_color == "DeepSkyBlue":
Pierre-Yves Chibon d36429
            tag_color = "#00bfff"
Pierre-Yves Chibon d36429
        form.tag_color.data = tag_color
Pierre-Yves Chibon d36429
        form.tag_description.data = tagobj.tag_description
Pierre-Yves Chibon d36429
        form.tag.data = tag
Pierre-Yves Chibon d36429
Pierre-Yves Chibon d36429
    return flask.render_template(
Pierre-Yves Chibon d36429
        "edit_tag.html", username=username, repo=repo, form=form, tagname=tag
Pierre-Yves Chibon d36429
    )
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
@UI_NS.route("/<repo>/archive/<ref>/<name>.tar")</name></ref></repo>
Pierre-Yves Chibon ded1fa
@UI_NS.route("/<namespace>/<repo>/archive/<ref>/<name>.tar")</name></ref></repo></namespace>
Pierre-Yves Chibon ded1fa
@UI_NS.route("/fork/<username>/<repo>/archive/<ref>/<name>.tar")</name></ref></repo></username>
Pierre-Yves Chibon ded1fa
@UI_NS.route("/fork/<username>/<namespace>/<repo>/archive/<ref>/<name>.tar")</name></ref></repo></namespace></username>
Pierre-Yves Chibon ded1fa
def get_project_archive_tar(repo, ref, name, namespace=None, username=None):
Pierre-Yves Chibon ded1fa
    """ Generate an archive or redirect the user to where it already exists
Pierre-Yves Chibon ded1fa
    """
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    return generate_project_archive(
Pierre-Yves Chibon ded1fa
        repo,
Pierre-Yves Chibon ded1fa
        ref,
Pierre-Yves Chibon ded1fa
        name,
Pierre-Yves Chibon ded1fa
        extension="tar",
Pierre-Yves Chibon ded1fa
        namespace=namespace,
Pierre-Yves Chibon ded1fa
        username=username,
Pierre-Yves Chibon ded1fa
    )
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
@UI_NS.route("/<repo>/archive/<ref>/<name>.tar.gz")</name></ref></repo>
Pierre-Yves Chibon ded1fa
@UI_NS.route("/<namespace>/<repo>/archive/<ref>/<name>.tar.gz")</name></ref></repo></namespace>
Pierre-Yves Chibon ded1fa
@UI_NS.route("/fork/<username>/<repo>/archive/<ref>/<name>.tar.gz")</name></ref></repo></username>
Pierre-Yves Chibon ded1fa
@UI_NS.route("/fork/<username>/<namespace>/<repo>/archive/<ref>/<name>.tar.gz")</name></ref></repo></namespace></username>
Pierre-Yves Chibon ded1fa
def get_project_archive_tar_gz(repo, ref, name, namespace=None, username=None):
Pierre-Yves Chibon ded1fa
    """ Generate an archive or redirect the user to where it already exists
Pierre-Yves Chibon ded1fa
    """
Pierre-Yves Chibon ded1fa
    return generate_project_archive(
Pierre-Yves Chibon ded1fa
        repo,
Pierre-Yves Chibon ded1fa
        ref,
Pierre-Yves Chibon ded1fa
        name,
Pierre-Yves Chibon ded1fa
        extension="tar.gz",
Pierre-Yves Chibon ded1fa
        namespace=namespace,
Pierre-Yves Chibon ded1fa
        username=username,
Pierre-Yves Chibon ded1fa
    )
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
@UI_NS.route("/<repo>/archive/<ref>/<name>.zip")</name></ref></repo>
Pierre-Yves Chibon ded1fa
@UI_NS.route("/<namespace>/<repo>/archive/<ref>/<name>.zip")</name></ref></repo></namespace>
Pierre-Yves Chibon ded1fa
@UI_NS.route("/fork/<username>/<repo>/archive/<ref>/<name>.zip")</name></ref></repo></username>
Pierre-Yves Chibon ded1fa
@UI_NS.route("/fork/<username>/<namespace>/<repo>/archive/<ref>/<name>.zip")</name></ref></repo></namespace></username>
Pierre-Yves Chibon ded1fa
def get_project_archive_zip(repo, ref, name, namespace=None, username=None):
Pierre-Yves Chibon ded1fa
    """ Generate an archive or redirect the user to where it already exists
Pierre-Yves Chibon ded1fa
    """
Pierre-Yves Chibon ded1fa
    return generate_project_archive(
Pierre-Yves Chibon ded1fa
        repo,
Pierre-Yves Chibon ded1fa
        ref,
Pierre-Yves Chibon ded1fa
        name,
Pierre-Yves Chibon ded1fa
        extension="zip",
Pierre-Yves Chibon ded1fa
        namespace=namespace,
Pierre-Yves Chibon ded1fa
        username=username,
Pierre-Yves Chibon ded1fa
    )
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
def generate_project_archive(
Pierre-Yves Chibon ded1fa
    repo, ref, name, extension, namespace=None, username=None
Pierre-Yves Chibon ded1fa
):
Pierre-Yves Chibon ded1fa
    """ Generate an archive or redirect the user to where it already
Pierre-Yves Chibon ded1fa
    exists.
Pierre-Yves Chibon ded1fa
    """
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    archive_folder = pagure_config.get("ARCHIVE_FOLDER")
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    if not archive_folder:
Pierre-Yves Chibon ded1fa
        _log.debug("No ARCHIVE_FOLDER specified in the configuration")
Pierre-Yves Chibon ded1fa
        flask.abort(
Pierre-Yves Chibon ded1fa
            404,
Pierre-Yves Chibon c6cc5c
            description="This pagure instance isn't configured to support "
Pierre-Yves Chibon c6cc5c
            "this feature",
Pierre-Yves Chibon 0ed488
        )
Pierre-Yves Chibon ded1fa
    if not os.path.exists(archive_folder):
Pierre-Yves Chibon ded1fa
        _log.debug("No ARCHIVE_FOLDER could not be found on disk")
Pierre-Yves Chibon c6cc5c
        flask.abort(
Pierre-Yves Chibon c6cc5c
            500,
Pierre-Yves Chibon c6cc5c
            description="Incorrect configuration, please contact your admin",
Pierre-Yves Chibon c6cc5c
        )
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    extensions = ["tar.gz", "tar", "zip"]
Pierre-Yves Chibon ded1fa
    if extension not in extensions:
Pierre-Yves Chibon ded1fa
        _log.debug("%s no in %s", extension, extensions)
Pierre-Yves Chibon c6cc5c
        flask.abort(400, description="Invalid archive format specified")
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    name = werkzeug.secure_filename(name)
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    repo_obj = flask.g.repo_obj
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    ref_string = "refs/tags/%s" % ref
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    commit = None
Pierre-Yves Chibon ded1fa
    tag = None
Pierre-Yves Chibon ded1fa
    if ref_string in repo_obj.listall_references():
Pierre-Yves Chibon ded1fa
        reference = repo_obj.lookup_reference(ref_string)
Pierre-Yves Chibon ded1fa
        tag = repo_obj[reference.target]
Pierre-Yves Chibon 7c59e9
        if isinstance(tag, pygit2.Tag):
Pierre-Yves Chibon 7c59e9
            commit = tag.peel(pygit2.Commit)
Pierre-Yves Chibon 7c59e9
        elif isinstance(tag, pygit2.Commit):
Pierre-Yves Chibon 7c59e9
            commit = tag
Pierre-Yves Chibon 7c59e9
        else:
Pierre-Yves Chibon 7c59e9
            _log.debug("Found %s instead of a tag", tag)
Pierre-Yves Chibon c6cc5c
            flask.abort(400, description="Invalid reference provided")
Pierre-Yves Chibon ded1fa
    else:
Pierre-Yves Chibon ded1fa
        try:
Pierre-Yves Chibon ded1fa
            commit = repo_obj.get(ref)
Pierre-Yves Chibon ded1fa
        except ValueError:
Pierre-Yves Chibon c6cc5c
            flask.abort(404, description="Invalid commit provided")
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    if not isinstance(commit, pygit2.Commit):
Pierre-Yves Chibon c6cc5c
        flask.abort(400, description="Invalid reference specified")
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    tag_path = ""
Pierre-Yves Chibon ded1fa
    tag_filename = None
Pierre-Yves Chibon ded1fa
    if tag:
Pierre-Yves Chibon ded1fa
        tag_filename = werkzeug.secure_filename(ref)
Pierre-Yves Chibon ded1fa
        tag_path = os.path.join("tags", tag_filename)
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    path = os.path.join(
Pierre-Yves Chibon ded1fa
        archive_folder,
Pierre-Yves Chibon ded1fa
        flask.g.repo.fullname,
Pierre-Yves Chibon ded1fa
        tag_path,
Pierre-Yves Chibon ded1fa
        commit.oid.hex,
Pierre-Yves Chibon ded1fa
        "%s.%s" % (name, extension),
Pierre-Yves Chibon ded1fa
    )
Pierre-Yves Chibon ded1fa
    headers = {
Pierre-Yves Chibon ded1fa
        str("Content-Disposition"): "attachment",
Pierre-Yves Chibon ded1fa
        str("Content-Type"): "application/x-gzip",
Pierre-Yves Chibon ded1fa
    }
Pierre-Yves Chibon ded1fa
    if os.path.exists(path):
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
        def _send_data():
Pierre-Yves Chibon ded1fa
            with open(path, "rb") as stream:
Pierre-Yves Chibon ded1fa
                yield stream.read()
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
        _log.info("Sending the existing archive")
Pierre-Yves Chibon ded1fa
        return flask.Response(
Pierre-Yves Chibon ded1fa
            flask.stream_with_context(_send_data()), headers=headers
Pierre-Yves Chibon ded1fa
        )
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    _log.info("Re-generating the archive")
Pierre-Yves Chibon ded1fa
    task = pagure.lib.tasks.generate_archive.delay(
Pierre-Yves Chibon ded1fa
        repo,
Pierre-Yves Chibon ded1fa
        namespace=namespace,
Pierre-Yves Chibon ded1fa
        username=username,
Pierre-Yves Chibon ded1fa
        commit=commit.oid.hex,
Pierre-Yves Chibon ded1fa
        tag=tag_filename,
Pierre-Yves Chibon ded1fa
        name=name,
Pierre-Yves Chibon ded1fa
        archive_fmt=extension,
Pierre-Yves Chibon ded1fa
    )
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    def _wait_for_task_and_send_data():
Pierre-Yves Chibon ded1fa
        while not task.ready():
Pierre-Yves Chibon ded1fa
            import time
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
            _log.info("waiting")
Pierre-Yves Chibon ded1fa
            time.sleep(0.5)
Pierre-Yves Chibon ded1fa
        with open(path, "rb") as stream:
Pierre-Yves Chibon ded1fa
            yield stream.read()
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    _log.info("Sending the existing archive")
Pierre-Yves Chibon ded1fa
    return flask.Response(
Pierre-Yves Chibon ded1fa
        flask.stream_with_context(_wait_for_task_and_send_data()),
Pierre-Yves Chibon ded1fa
        headers=headers,
Pierre-Yves Chibon ded1fa
    )
Pierre-Yves Chibon ded1fa
Pierre-Yves Chibon ded1fa
    return pagure.utils.wait_for_task(task)