From e7f9bca2630d709b18714dd491d4b3c3c98a9553 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Aug 21 2019 13:58:14 +0000 Subject: Rename the file pagure_distgit.py to plugin.py so it doesn't conflict Signed-off-by: Pierre-Yves Chibon --- diff --git a/pagure_distgit/pagure_distgit.py b/pagure_distgit/pagure_distgit.py deleted file mode 100644 index b153b26..0000000 --- a/pagure_distgit/pagure_distgit.py +++ /dev/null @@ -1,212 +0,0 @@ -# -*- coding: utf-8 -*- - -""" - (c) 2019 - Copyright Red Hat Inc - - Authors: - Pierre-Yves Chibon - -""" - -from __future__ import unicode_literals, print_function -import datetime -import logging - -import flask -import requests -from sqlalchemy.exc import SQLAlchemyError - -import pagure.utils -from pagure.api import api_method, APIERROR, api_login_required -from pagure.api.utils import _get_repo, _check_token - -import pagure_distgit.forms -from pagure_distgit import model - - -_log = logging.getLogger(__name__) - -DISTGIT_NS = flask.Blueprint( - "distgit_ns", __name__, url_prefix="/_dg", template_folder="templates" -) - - -@DISTGIT_NS.route("/anitya//", methods=["GET"]) -def anitya_get_endpoint(namespace, repo): - """ Returns the current status of the monitoring in anitya of this package. - """ - repo = flask.g.repo - output = {"monitoring": "no-monitoring"} - if repo.anitya: - output = {"monitoring": repo.anitya.anitya_status} - return flask.jsonify(output) - - -@DISTGIT_NS.route("/anitya//", methods=["PATCH"]) -@api_login_required(acls=["modify_project"]) -@api_method -def anitya_patch_endpoint(namespace, repo): - """ Updates the current status of the monitoring in anitya of this package. - """ - - repo = _get_repo(repo, namespace=namespace) - _check_token(repo, project_token=False) - - is_site_admin = pagure.utils.is_admin() - admins = [u.username for u in repo.get_project_users("admin")] - # Only allow the main admin, the admins of the project, and Pagure site - # admins to modify projects' monitoring, even if the user has the right - # ACLs on their token - if ( - flask.g.fas_user.username not in admins - and flask.g.fas_user.username != repo.user.username - and not is_site_admin - ): - raise pagure.exceptions.APIError( - 401, error_code=APIERROR.EMODIFYPROJECTNOTALLOWED - ) - - form = pagure_distgit.forms.AnityaForm(csrf_enabled=False) - if form.validate_on_submit(): - try: - if repo.anitya: - repo.anitya.anitya_status = form.anitya_status.data - else: - repo = model.PagureAnitya( - project_id=repo.id, anitya_status=form.anitya_status.data - ) - flask.g.session.add(repo) - flask.g.session.commit() - except SQLAlchemyError as err: # pragma: no cover - flask.g.session.rollback() - _log.exception(err) - raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) - else: - raise pagure.exceptions.APIError( - 400, error_code=APIERROR.EINVALIDREQ, errors=form.errors - ) - - return anitya_get_endpoint(namespace, repo.name) - - -def _is_active_in_pdc(name, namespace): - """ Queries PDC and return whether the project is active on the master - branch in PDC or not. - """ - pdc_url = flask.current_app.config.get("PDC_URL") - if not pdc_url: - raise pagure.exceptions.APIError( - 500, - error_code=APIERROR.ENOCODE, - error="This pagure instance has no PDC_URL configured, please inform" - " your pagure administrators" - ) - else: - pdc_url = "%s/rest_api/v1/component-branches/" % pdc_url.rstrip("/") - - _log.debug("Based PDC url: %s", pdc_url) - - to_pdc_namespace = { - "rpms": "rpm", - "modules": "module", - "container": "container", - } - to_pdc_namespace = flask.current_app.config.get("PDC_NAMESPACES") \ - or to_pdc_namespace - - try: - pdc_namespace = to_pdc_namespace[namespace] - except: - raise pagure.exceptions.APIError( - 500, - error_code=APIERROR.ENOCODE, - error="Namespace: %s could not be converted to a PDC namespace" % - namespace - ) - - url = "%s?global_component=%s&name=master&type=%s" % ( - pdc_url, name, pdc_namespace) - - _log.info("Querying PDC at: %s", url) - try: - req = requests.get(url, timeout=(30, 30)) - except requests.RequestException as err: - raise pagure.exceptions.APIError( - 500, - error_code=APIERROR.ENOCODE, - error="An error occured while querying pdc: %s" % err - ) - - try: - data = req.json() - except: - raise pagure.exceptions.APIError( - 500, - error_code=APIERROR.ENOCODE, - error="The output of %s could not be converted to JSON" % req.url - ) - - _log.info("%s/%s is active: %s", namespace, name, data["results"][0]["active"]) - return data["results"][0]["active"] == True - - -@DISTGIT_NS.route("/take_orphan//", methods=["POST"]) -@api_login_required(acls=["modify_project"]) -@api_method -def take_orphan_endpoint(namespace, repo): - """ Updates the current point of contact of orphan packages. - """ - _log.info("Received a request to unorphan: %s/%s", namespace, repo) - - repo = _get_repo(repo, namespace=namespace) - _check_token(repo, project_token=False) - - user_obj = pagure.lib.query.get_user( - flask.g.session, flask.g.fas_user.username - ) - if not user_obj: - raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOUSER) - - if repo.user.user != "orphan": - raise pagure.exceptions.APIError( - 401, error_code=APIERROR.EMODIFYPROJECTNOTALLOWED - ) - - user_grps = set(user_obj.groups) - req_grps = set(['packager']) - if not user_grps.intersection(req_grps): - raise pagure.exceptions.APIError( - 403, - error_code=APIERROR.ENOTHIGHENOUGH, - errors="You must be a packager to adopt a package.", - ) - - # Check if the project is retired in PDC - if not _is_active_in_pdc(repo.name, repo.namespace): - raise pagure.exceptions.APIError( - 400, - error_code=APIERROR.EINVALIDREQ, - errors="This project has been retired and cannot be unorphaned " - "here, please open a releng ticket for it.", - ) - - try: - repo.user = user_obj - flask.g.session.add(repo) - flask.g.session.commit() - except SQLAlchemyError as err: # pragma: no cover - flask.g.session.rollback() - _log.exception(err) - raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) - - pagure.lib.notify.log( - project, - topic="project.adopt", - msg=dict( - project=repo.to_json(public=True), agent=user_obj.username - ), - ) - - output = {"point_of_contact": repo.user.user} - - return flask.jsonify(output) diff --git a/pagure_distgit/plugin.py b/pagure_distgit/plugin.py new file mode 100644 index 0000000..b153b26 --- /dev/null +++ b/pagure_distgit/plugin.py @@ -0,0 +1,212 @@ +# -*- coding: utf-8 -*- + +""" + (c) 2019 - Copyright Red Hat Inc + + Authors: + Pierre-Yves Chibon + +""" + +from __future__ import unicode_literals, print_function +import datetime +import logging + +import flask +import requests +from sqlalchemy.exc import SQLAlchemyError + +import pagure.utils +from pagure.api import api_method, APIERROR, api_login_required +from pagure.api.utils import _get_repo, _check_token + +import pagure_distgit.forms +from pagure_distgit import model + + +_log = logging.getLogger(__name__) + +DISTGIT_NS = flask.Blueprint( + "distgit_ns", __name__, url_prefix="/_dg", template_folder="templates" +) + + +@DISTGIT_NS.route("/anitya//", methods=["GET"]) +def anitya_get_endpoint(namespace, repo): + """ Returns the current status of the monitoring in anitya of this package. + """ + repo = flask.g.repo + output = {"monitoring": "no-monitoring"} + if repo.anitya: + output = {"monitoring": repo.anitya.anitya_status} + return flask.jsonify(output) + + +@DISTGIT_NS.route("/anitya//", methods=["PATCH"]) +@api_login_required(acls=["modify_project"]) +@api_method +def anitya_patch_endpoint(namespace, repo): + """ Updates the current status of the monitoring in anitya of this package. + """ + + repo = _get_repo(repo, namespace=namespace) + _check_token(repo, project_token=False) + + is_site_admin = pagure.utils.is_admin() + admins = [u.username for u in repo.get_project_users("admin")] + # Only allow the main admin, the admins of the project, and Pagure site + # admins to modify projects' monitoring, even if the user has the right + # ACLs on their token + if ( + flask.g.fas_user.username not in admins + and flask.g.fas_user.username != repo.user.username + and not is_site_admin + ): + raise pagure.exceptions.APIError( + 401, error_code=APIERROR.EMODIFYPROJECTNOTALLOWED + ) + + form = pagure_distgit.forms.AnityaForm(csrf_enabled=False) + if form.validate_on_submit(): + try: + if repo.anitya: + repo.anitya.anitya_status = form.anitya_status.data + else: + repo = model.PagureAnitya( + project_id=repo.id, anitya_status=form.anitya_status.data + ) + flask.g.session.add(repo) + flask.g.session.commit() + except SQLAlchemyError as err: # pragma: no cover + flask.g.session.rollback() + _log.exception(err) + raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) + else: + raise pagure.exceptions.APIError( + 400, error_code=APIERROR.EINVALIDREQ, errors=form.errors + ) + + return anitya_get_endpoint(namespace, repo.name) + + +def _is_active_in_pdc(name, namespace): + """ Queries PDC and return whether the project is active on the master + branch in PDC or not. + """ + pdc_url = flask.current_app.config.get("PDC_URL") + if not pdc_url: + raise pagure.exceptions.APIError( + 500, + error_code=APIERROR.ENOCODE, + error="This pagure instance has no PDC_URL configured, please inform" + " your pagure administrators" + ) + else: + pdc_url = "%s/rest_api/v1/component-branches/" % pdc_url.rstrip("/") + + _log.debug("Based PDC url: %s", pdc_url) + + to_pdc_namespace = { + "rpms": "rpm", + "modules": "module", + "container": "container", + } + to_pdc_namespace = flask.current_app.config.get("PDC_NAMESPACES") \ + or to_pdc_namespace + + try: + pdc_namespace = to_pdc_namespace[namespace] + except: + raise pagure.exceptions.APIError( + 500, + error_code=APIERROR.ENOCODE, + error="Namespace: %s could not be converted to a PDC namespace" % + namespace + ) + + url = "%s?global_component=%s&name=master&type=%s" % ( + pdc_url, name, pdc_namespace) + + _log.info("Querying PDC at: %s", url) + try: + req = requests.get(url, timeout=(30, 30)) + except requests.RequestException as err: + raise pagure.exceptions.APIError( + 500, + error_code=APIERROR.ENOCODE, + error="An error occured while querying pdc: %s" % err + ) + + try: + data = req.json() + except: + raise pagure.exceptions.APIError( + 500, + error_code=APIERROR.ENOCODE, + error="The output of %s could not be converted to JSON" % req.url + ) + + _log.info("%s/%s is active: %s", namespace, name, data["results"][0]["active"]) + return data["results"][0]["active"] == True + + +@DISTGIT_NS.route("/take_orphan//", methods=["POST"]) +@api_login_required(acls=["modify_project"]) +@api_method +def take_orphan_endpoint(namespace, repo): + """ Updates the current point of contact of orphan packages. + """ + _log.info("Received a request to unorphan: %s/%s", namespace, repo) + + repo = _get_repo(repo, namespace=namespace) + _check_token(repo, project_token=False) + + user_obj = pagure.lib.query.get_user( + flask.g.session, flask.g.fas_user.username + ) + if not user_obj: + raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOUSER) + + if repo.user.user != "orphan": + raise pagure.exceptions.APIError( + 401, error_code=APIERROR.EMODIFYPROJECTNOTALLOWED + ) + + user_grps = set(user_obj.groups) + req_grps = set(['packager']) + if not user_grps.intersection(req_grps): + raise pagure.exceptions.APIError( + 403, + error_code=APIERROR.ENOTHIGHENOUGH, + errors="You must be a packager to adopt a package.", + ) + + # Check if the project is retired in PDC + if not _is_active_in_pdc(repo.name, repo.namespace): + raise pagure.exceptions.APIError( + 400, + error_code=APIERROR.EINVALIDREQ, + errors="This project has been retired and cannot be unorphaned " + "here, please open a releng ticket for it.", + ) + + try: + repo.user = user_obj + flask.g.session.add(repo) + flask.g.session.commit() + except SQLAlchemyError as err: # pragma: no cover + flask.g.session.rollback() + _log.exception(err) + raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR) + + pagure.lib.notify.log( + project, + topic="project.adopt", + msg=dict( + project=repo.to_json(public=True), agent=user_obj.username + ), + ) + + output = {"point_of_contact": repo.user.user} + + return flask.jsonify(output)