Blob Blame Raw
# -*- coding: utf-8 -*-

"""
 (c) 2014-2017 - Copyright Red Hat Inc

 Authors:
   Pierre-Yves Chibon <pingou@pingoured.fr>
   Farhaan Bukhsh <farhaan.bukhsh@gmail.com>

"""

# pylint: disable=too-many-branches

from __future__ import unicode_literals, absolute_import

import logging

import flask
from flask import Markup

from sqlalchemy.exc import SQLAlchemyError

import pagure.exceptions
import pagure.forms
import pagure.lib.plugins
from pagure.exceptions import FileNotFoundException
from pagure.ui import UI_NS
from pagure.utils import login_required
from pagure.decorators import is_repo_admin


_log = logging.getLogger(__name__)


@UI_NS.route("/<repo>/settings/<plugin>/", methods=("GET", "POST"))
@UI_NS.route("/<repo>/settings/<plugin>", methods=("GET", "POST"))
@UI_NS.route("/<namespace>/<repo>/settings/<plugin>/", methods=("GET", "POST"))
@UI_NS.route("/<namespace>/<repo>/settings/<plugin>", methods=("GET", "POST"))
@UI_NS.route("/<repo>/settings/<plugin>/<int:full>/", methods=("GET", "POST"))
@UI_NS.route("/<repo>/settings/<plugin>/<int:full>", methods=("GET", "POST"))
@UI_NS.route(
    "/<namespace>/<repo>/settings/<plugin>/<int:full>/",
    methods=("GET", "POST"),
)
@UI_NS.route(
    "/<namespace>/<repo>/settings/<plugin>/<int:full>", methods=("GET", "POST")
)
@UI_NS.route(
    "/fork/<username>/<repo>/settings/<plugin>/", methods=("GET", "POST")
)
@UI_NS.route(
    "/fork/<username>/<namespace>/<repo>/settings/<plugin>/",
    methods=("GET", "POST"),
)
@UI_NS.route(
    "/fork/<username>/<repo>/settings/<plugin>", methods=("GET", "POST")
)
@UI_NS.route(
    "/fork/<username>/<namespace>/<repo>/settings/<plugin>",
    methods=("GET", "POST"),
)
@UI_NS.route(
    "/fork/<username>/<repo>/settings/<plugin>/<int:full>/",
    methods=("GET", "POST"),
)
@UI_NS.route(
    "/fork/<username>/<namespace>/<repo>/settings/<plugin>/<int:full>/",
    methods=("GET", "POST"),
)
@UI_NS.route(
    "/fork/<username>/<repo>/settings/<plugin>/<int:full>",
    methods=("GET", "POST"),
)
@UI_NS.route(
    "/fork/<username>/<namespace>/<repo>/settings/<plugin>/<int:full>",
    methods=("GET", "POST"),
)
@login_required
@is_repo_admin
def view_plugin(repo, plugin, username=None, namespace=None, full=True):
    """ Presents the settings of the project.
    """
    repo = flask.g.repo

    # Private repos are not allowed to leak information outside so disabling CI
    # enables us to keep the repos totally discreate and prevents from leaking
    # information outside
    if repo.private and plugin == "Pagure CI":
        flask.abort(404, description="Plugin disabled")

    if plugin in pagure.config.config.get("DISABLED_PLUGINS", []):
        flask.abort(404, description="Plugin disabled")

    if plugin == "default":
        flask.abort(403, description="This plugin cannot be changed")

    plugin = pagure.lib.plugins.get_plugin(plugin)
    fields = []
    new = True
    dbobj = plugin.db_object()

    if hasattr(repo, plugin.backref):
        dbobj = getattr(repo, plugin.backref)

        # There should always be only one, but let's double check
        if dbobj:
            new = False
        else:
            dbobj = plugin.db_object()

    form = plugin.form(obj=dbobj)
    for field in plugin.form_fields:
        fields.append(getattr(form, field))

    form_fields_readonly = []
    if hasattr(plugin, "form_fields_readonly"):
        form_fields_readonly = plugin.form_fields_readonly

    if form.validate_on_submit():
        form.populate_obj(obj=dbobj)

        if new:
            dbobj.project_id = repo.id
            flask.g.session.add(dbobj)
        try:
            flask.g.session.flush()
        except SQLAlchemyError:  # pragma: no cover
            flask.g.session.rollback()
            _log.exception("Could not add plugin %s", plugin.name)
            message = Markup(
                "Could not add plugin,"
                ' please <a href="/about">contact an administrator</a>'
            )
            flask.flash(message % plugin.name)

            return flask.render_template(
                "plugin.html",
                select="settings",
                full=full,
                repo=repo,
                username=username,
                namespace=namespace,
                plugin=plugin,
                form=form,
                fields=fields,
            )

        # Compute the ci_hook active value in function
        # of the active PR and active commit values.
        if hasattr(form, "active_pr") and hasattr(form, "active_commit"):
            if form.active_pr.data or form.active_commit.data:
                form.active.data = True

        if form.active.data:
            try:
                # Set up the main script if necessary
                plugin.set_up(repo)
                # Install the plugin itself
                plugin.install(repo, dbobj)
                flask.flash("Hook %s activated" % plugin.name)
            except FileNotFoundException as err:
                flask.g.session.rollback()
                _log.exception(err)
                flask.abort(404, description="No git repo found")
        else:
            try:
                plugin.remove(repo)
            except FileNotFoundException as err:
                flask.g.session.rollback()
                _log.exception(err)
                flask.abort(404, description="No git repo found")
            flask.g.session.delete(dbobj)
            flask.flash("Hook %s deactivated" % plugin.name)

        flask.g.session.commit()

        return flask.redirect(
            flask.url_for(
                "ui_ns.view_settings",
                repo=repo.name,
                username=username,
                namespace=namespace,
            )
        )

    return flask.render_template(
        "plugin.html",
        select="settings",
        full=full,
        repo=repo,
        namespace=namespace,
        username=username,
        plugin=plugin,
        form=form,
        fields=fields,
        form_fields_readonly=form_fields_readonly,
    )