Blame pagure/api/__init__.py

Pierre-Yves Chibon 33b534
# -*- coding: utf-8 -*-
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 0537b7
"""
Pierre-Yves Chibon 602511
 (c) 2015-2016 - Copyright Red Hat Inc
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 0537b7
 Authors:
Pierre-Yves Chibon 0537b7
   Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 0537b7
API namespace version 0.
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 0537b7
"""
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 22a554
# pylint: disable=invalid-name
Pierre-Yves Chibon 22a554
# pylint: disable=too-few-public-methods
Pierre-Yves Chibon 22a554
# pylint: disable=too-many-locals
Pierre-Yves Chibon 602511
Pierre-Yves Chibon 67d1cc
from __future__ import unicode_literals, absolute_import
Aurélien Bompard dcf6f6
Pierre-Yves Chibon ea3e81
import codecs
Pierre-Yves Chibon a4d473
import functools
Pierre-Yves Chibon b130e5
import logging
Pierre-Yves Chibon ea3e81
import os
Pierre-Yves Chibon a4d473
Pierre-Yves Chibon ea3e81
import docutils
Pierre-Yves Chibon 23d3ff
import enum
Pierre-Yves Chibon ea3e81
import flask
Pierre-Yves Chibon ea3e81
import markupsafe
Peter Oliver 80bd6d
from six.moves.urllib_parse import urljoin
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 9c2953
API = flask.Blueprint("api_ns", __name__, url_prefix="/api/0")
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 930073
import pagure.lib.query  # noqa: E402
Patrick Uiterwijk e56b25
import pagure.lib.tasks  # noqa: E402
Pierre-Yves Chibon b130e5
from pagure.config import config as pagure_config  # noqa: E402
Pierre-Yves Chibon de6f12
from pagure.doc_utils import load_doc, modify_rst, modify_html  # noqa: E402
Pierre-Yves Chibon de6f12
from pagure.exceptions import APIError  # noqa: E402
Slavek Kabrda 984d0f
from pagure.utils import authenticated, check_api_acls  # noqa: E402
Pierre-Yves Chibon b130e5
Pierre-Yves Chibon b130e5
Pierre-Yves Chibon b130e5
_log = logging.getLogger(__name__)
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon ea3e81
def preload_docs(endpoint):
Pierre-Yves Chibon 9c2953
    """ Utility to load an RST file and turn it into fancy HTML. """
Pierre-Yves Chibon ea3e81
Pierre-Yves Chibon ea3e81
    here = os.path.dirname(os.path.abspath(__file__))
Pierre-Yves Chibon 9c2953
    fname = os.path.join(here, "..", "doc", endpoint + ".rst")
Pierre-Yves Chibon 9c2953
    with codecs.open(fname, "r", "utf-8") as stream:
Pierre-Yves Chibon 602511
        rst = stream.read()
Pierre-Yves Chibon ea3e81
Pierre-Yves Chibon ea3e81
    rst = modify_rst(rst)
Pierre-Yves Chibon ea3e81
    api_docs = docutils.examples.html_body(rst)
Pierre-Yves Chibon ea3e81
    api_docs = modify_html(api_docs)
Pierre-Yves Chibon ea3e81
    api_docs = markupsafe.Markup(api_docs)
Pierre-Yves Chibon ea3e81
    return api_docs
Pierre-Yves Chibon ea3e81
Pierre-Yves Chibon ea3e81
Pierre-Yves Chibon 9c2953
APIDOC = preload_docs("api")
Pierre-Yves Chibon ea3e81
Pierre-Yves Chibon ea3e81
Pierre-Yves Chibon 23d3ff
class APIERROR(enum.Enum):
Pierre-Yves Chibon 23d3ff
    """ Clast listing as Enum all the possible error thrown by the API.
Pierre-Yves Chibon 23d3ff
    """
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon 9c2953
    ENOCODE = "Variable message describing the issue"
Pierre-Yves Chibon 9c2953
    ENOPROJECT = "Project not found"
Pierre-Yves Chibon 9c2953
    ENOPROJECTS = "No projects found"
Pierre-Yves Chibon 9c2953
    ETRACKERDISABLED = "Issue tracker disabled for this project"
Pierre-Yves Chibon 9c2953
    EDBERROR = (
Pierre-Yves Chibon 9c2953
        "An error occurred at the database level and prevent the "
Pierre-Yves Chibon 9c2953
        + "action from reaching completion"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
    EINVALIDREQ = "Invalid or incomplete input submitted"
Pierre-Yves Chibon 9c2953
    EINVALIDTOK = (
Pierre-Yves Chibon 9c2953
        "Invalid or expired token. Please visit %s to get or "
Pierre-Yves Chibon 9c2953
        "renew your API token."
Pierre-Yves Chibon 9c2953
        % urljoin(pagure_config["APP_URL"], "settings#api-keys")
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
    ENOISSUE = "Issue not found"
Pierre-Yves Chibon 9c2953
    EISSUENOTALLOWED = "You are not allowed to view this issue"
Pierre-Yves Chibon 9c2953
    EPULLREQUESTSDISABLED = (
Pierre-Yves Chibon 9c2953
        "Pull-Request have been deactivated for this " "project"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
    ENOREQ = "Pull-Request not found"
Pierre-Yves Chibon 9c2953
    ENOPRCLOSE = (
Pierre-Yves Chibon 87b46d
        "You are not allowed to merge/close pull-request for this project"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
    EPRSCORE = (
Pierre-Yves Chibon 9c2953
        "This request does not have the minimum review score "
Pierre-Yves Chibon 9c2953
        "necessary to be merged"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
    ENOTASSIGNEE = "Only the assignee can merge this review"
Pierre-Yves Chibon 9c2953
    ENOTASSIGNED = "This request must be assigned to be merged"
Pierre-Yves Chibon 9c2953
    ENOUSER = "No such user found"
Pierre-Yves Chibon 9c2953
    ENOCOMMENT = "Comment not found"
Pierre-Yves Chibon 9c2953
    ENEWPROJECTDISABLED = (
Pierre-Yves Chibon 87b46d
        "Creating project have been disabled for this instance"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
    ETIMESTAMP = "Invalid timestamp format"
Pierre-Yves Chibon 9c2953
    EDATETIME = "Invalid datetime format"
Pierre-Yves Chibon 9c2953
    EINVALIDISSUEFIELD = "Invalid custom field submitted"
Pierre-Yves Chibon 9c2953
    EINVALIDISSUEFIELD_LINK = (
Pierre-Yves Chibon 87b46d
        "Invalid custom field submitted, the value is not a link"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
    EINVALIDPRIORITY = "Invalid priority submitted"
Pierre-Yves Chibon 9c2953
    ENOGROUP = "Group not found"
Pierre-Yves Chibon 9c2953
    ENOTMAINADMIN = "Only the main admin can set the main admin of a project"
Pierre-Yves Chibon 9c2953
    EMODIFYPROJECTNOTALLOWED = "You are not allowed to modify this project"
Pierre-Yves Chibon 9c2953
    EINVALIDPERPAGEVALUE = "The per_page value must be between 1 and 100"
Pierre-Yves Chibon 9c2953
    EGITERROR = "An error occurred during a git operation"
Pierre-Yves Chibon 9c2953
    ENOCOMMIT = "No such commit found in this repository"
Pierre-Yves Chibon 9c2953
    ENOTHIGHENOUGH = (
Pierre-Yves Chibon 87b46d
        "You do not have sufficient permissions to perform this action"
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
    ENOSIGNEDOFF = (
Pierre-Yves Chibon 9c2953
        "This repo enforces that all commits are signed off "
Pierre-Yves Chibon 9c2953
        "by their author."
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
    ETRACKERREADONLY = "The issue tracker of this project is read-only"
Pierre-Yves Chibon c67f41
    ENOPRSTATS = "No statistics could be computed for this PR"
Pierre-Yves Chibon 977684
Pierre-Yves Chibon 977684
Pierre-Yves Chibon b130e5
def get_authorized_api_project(session, repo, user=None, namespace=None):
Pierre-Yves Chibon 9c2953
    """ Helper function to get an authorized_project with optional lock. """
Pierre-Yves Chibon 930073
    repo = pagure.lib.query.get_authorized_project(
Pierre-Yves Chibon 9c2953
        flask.g.session, repo, user=user, namespace=namespace
Pierre-Yves Chibon 9c2953
    )
Patrick Uiterwijk eabc8e
    flask.g.repo = repo
Patrick Uiterwijk eabc8e
    return repo
Patrick Uiterwijk eabc8e
Patrick Uiterwijk eabc8e
Slavek Kabrda 727932
def get_request_data():
Slavek Kabrda 727932
    return flask.request.form or flask.request.get_json() or {}
Slavek Kabrda 727932
Slavek Kabrda 727932
Pierre-Yves Chibon 976463
def api_login_required(acls=None):
Pierre-Yves Chibon 9c2953
    """ Decorator used to indicate that authentication is required for some
Pierre-Yves Chibon 3e6692
    API endpoint.
Pierre-Yves Chibon 9c2953
    """
Pierre-Yves Chibon 976463
Pierre-Yves Chibon 602511
    def decorator(function):
Pierre-Yves Chibon 9c2953
        """ The decorator of the function """
Pierre-Yves Chibon 976463
Pierre-Yves Chibon 602511
        @functools.wraps(function)
Pierre-Yves Chibon 976463
        def decorated_function(*args, **kwargs):
Pierre-Yves Chibon 9c2953
            """ Actually does the job with the arguments provided. """
Pierre-Yves Chibon 976463
Pierre-Yves Chibon 5ec12b
            response = check_api_acls(acls)
Pierre-Yves Chibon 5ec12b
            if response:
Pierre-Yves Chibon 5ec12b
                return response
Pierre-Yves Chibon 602511
            return function(*args, **kwargs)
Pierre-Yves Chibon 976463
Pierre-Yves Chibon 5ec12b
        return decorated_function
Pierre-Yves Chibon 976463
Pierre-Yves Chibon 976463
    return decorator
Pierre-Yves Chibon a4d473
Pierre-Yves Chibon a4d473
Pierre-Yves Chibon cd7658
def api_login_optional(acls=None):
Pierre-Yves Chibon 9c2953
    """ Decorator used to indicate that authentication is optional for some
Pierre-Yves Chibon cd7658
    API endpoint.
Pierre-Yves Chibon 9c2953
    """
Pierre-Yves Chibon cd7658
Pierre-Yves Chibon 602511
    def decorator(function):
Pierre-Yves Chibon 9c2953
        """ The decorator of the function """
Pierre-Yves Chibon cd7658
Pierre-Yves Chibon 602511
        @functools.wraps(function)
Pierre-Yves Chibon cd7658
        def decorated_function(*args, **kwargs):
Pierre-Yves Chibon 9c2953
            """ Actually does the job with the arguments provided. """
Pierre-Yves Chibon cd7658
Pierre-Yves Chibon 0030f0
            response = check_api_acls(acls, optional=True)
Pierre-Yves Chibon 0030f0
            if response:
Pierre-Yves Chibon 0030f0
                return response
Pierre-Yves Chibon 602511
            return function(*args, **kwargs)
Pierre-Yves Chibon cd7658
Pierre-Yves Chibon cd7658
        return decorated_function
Pierre-Yves Chibon cd7658
Pierre-Yves Chibon cd7658
    return decorator
Pierre-Yves Chibon cd7658
Pierre-Yves Chibon cd7658
Pierre-Yves Chibon 9f54ca
def api_method(function):
Pierre-Yves Chibon 9c2953
    """ Runs an API endpoint and catch all the APIException thrown. """
Pierre-Yves Chibon 9f54ca
Pierre-Yves Chibon 9f54ca
    @functools.wraps(function)
Pierre-Yves Chibon 9f54ca
    def wrapper(*args, **kwargs):
Pierre-Yves Chibon 9c2953
        """ Actually does the job with the arguments provided. """
Pierre-Yves Chibon 9f54ca
        try:
Pierre-Yves Chibon 9f54ca
            result = function(*args, **kwargs)
Pierre-Yves Chibon 602511
        except APIError as err:
Pierre-Yves Chibon 602511
            if err.error_code in [APIERROR.EDBERROR]:
Pierre-Yves Chibon b130e5
                _log.exception(err)
Pierre-Yves Chibon 9f54ca
Pierre-Yves Chibon 602511
            if err.error_code in [APIERROR.ENOCODE]:
Pierre-Yves Chibon f7fcaa
                output = {
Pierre-Yves Chibon 9c2953
                    "error": err.error,
Pierre-Yves Chibon 9c2953
                    "error_code": err.error_code.name,
Pierre-Yves Chibon 9602c6
                }
Pierre-Yves Chibon 9f54ca
            else:
Pierre-Yves Chibon f7fcaa
                output = {
Pierre-Yves Chibon 9c2953
                    "error": err.error_code.value,
Pierre-Yves Chibon 9c2953
                    "error_code": err.error_code.name,
Pierre-Yves Chibon 9602c6
                }
Pierre-Yves Chibon f7fcaa
Pierre-Yves Chibon f7fcaa
            if err.errors:
Pierre-Yves Chibon 9c2953
                output["errors"] = err.errors
Pierre-Yves Chibon f7fcaa
            response = flask.jsonify(output)
Pierre-Yves Chibon 602511
            response.status_code = err.status_code
Pierre-Yves Chibon 9f54ca
        else:
Pierre-Yves Chibon 7f151a
            response = result
Pierre-Yves Chibon 9f54ca
Pierre-Yves Chibon 9f54ca
        return response
Pierre-Yves Chibon 9f54ca
Pierre-Yves Chibon 9f54ca
    return wrapper
Pierre-Yves Chibon 9f54ca
Pierre-Yves Chibon 9f54ca
Pierre-Yves Chibon 90cfb8
def get_page():
Pierre-Yves Chibon 90cfb8
    """ Returns the page value specified in the request.
Pierre-Yves Chibon 90cfb8
    Defaults to 1.
Pierre-Yves Chibon 90cfb8
    raises APIERROR.EINVALIDREQ if the page provided isn't an integer
Pierre-Yves Chibon 90cfb8
    raises APIERROR.EINVALIDREQ if the page provided is lower than 1
Pierre-Yves Chibon 90cfb8
    """
Pierre-Yves Chibon 90cfb8
Pierre-Yves Chibon 9c2953
    page = flask.request.values.get("page", None)
Pierre-Yves Chibon 90cfb8
    if not page:
Pierre-Yves Chibon 90cfb8
        page = 1
Pierre-Yves Chibon 90cfb8
    else:
Pierre-Yves Chibon 90cfb8
        try:
Pierre-Yves Chibon 90cfb8
            page = int(page)
Pierre-Yves Chibon 90cfb8
        except (TypeError, ValueError):
Pierre-Yves Chibon 90cfb8
            raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
                400, error_code=APIERROR.EINVALIDREQ
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 90cfb8
Pierre-Yves Chibon 90cfb8
        if page < 1:
Pierre-Yves Chibon 90cfb8
            raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
                400, error_code=APIERROR.EINVALIDREQ
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 90cfb8
Pierre-Yves Chibon 90cfb8
    return page
Pierre-Yves Chibon 90cfb8
Pierre-Yves Chibon 90cfb8
Pierre-Yves Chibon 90cfb8
def get_per_page():
Pierre-Yves Chibon 90cfb8
    """ Returns the per_page value specified in the request.
Pierre-Yves Chibon 90cfb8
    Defaults to 20.
Pierre-Yves Chibon 90cfb8
    raises APIERROR.EINVALIDREQ if the page provided isn't an integer
Pierre-Yves Chibon 90cfb8
    raises APIERROR.EINVALIDPERPAGEVALUE if the page provided is lower
Pierre-Yves Chibon 90cfb8
        than 1 or greater than 100
Pierre-Yves Chibon 90cfb8
    """
Pierre-Yves Chibon 9c2953
    per_page = flask.request.values.get("per_page", None) or 20
Pierre-Yves Chibon 90cfb8
    if per_page:
Pierre-Yves Chibon 90cfb8
        try:
Pierre-Yves Chibon 90cfb8
            per_page = int(per_page)
Pierre-Yves Chibon 90cfb8
        except (TypeError, ValueError):
Pierre-Yves Chibon 90cfb8
            raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
                400, error_code=APIERROR.EINVALIDREQ
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 90cfb8
Pierre-Yves Chibon 90cfb8
        if per_page < 1 or per_page > 100:
Pierre-Yves Chibon 90cfb8
            raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
                400, error_code=APIERROR.EINVALIDPERPAGEVALUE
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 90cfb8
Pierre-Yves Chibon 90cfb8
    return per_page
Pierre-Yves Chibon 90cfb8
Pierre-Yves Chibon 90cfb8
Pierre-Yves Chibon 9c2953
if pagure_config.get("ENABLE_TICKETS", True):
Pierre-Yves Chibon de6f12
    from pagure.api import issue  # noqa: E402
Pierre-Yves Chibon de6f12
from pagure.api import fork  # noqa: E402
Pierre-Yves Chibon de6f12
from pagure.api import project  # noqa: E402
Pierre-Yves Chibon de6f12
from pagure.api import user  # noqa: E402
Pierre-Yves Chibon de6f12
from pagure.api import group  # noqa: E402
Patrick Uiterwijk acf298
Pierre-Yves Chibon 9c2953
if pagure_config.get("PAGURE_CI_SERVICES", False):
Pierre-Yves Chibon de6f12
    from pagure.api.ci import jenkins  # noqa: E402
Pierre-Yves Chibon e3718c
Pierre-Yves Chibon e8915e
Pierre-Yves Chibon 9c2953
@API.route("/version/")
Pierre-Yves Chibon 9c2953
@API.route("/version")
Pierre-Yves Chibon 9c2953
@API.route("/-/version")
Pierre-Yves Chibon 0537b7
def api_version():
Pierre-Yves Chibon 9c2953
    """
Pierre-Yves Chibon 0537b7
    API Version
Pierre-Yves Chibon 0537b7
    -----------
Lei Yang 566c51
    Get the current API version.
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 0537b7
    ::
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 0b9b6b
        GET /api/0/-/version
Pierre-Yves Chibon 0537b7
Lei Yang 566c51
    Sample response
Lei Yang 566c51
    ^^^^^^^^^^^^^^^
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 0537b7
    ::
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 0537b7
        {
Pierre-Yves Chibon 0537b7
          "version": "1"
Pierre-Yves Chibon 0537b7
        }
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 9c2953
    """
Pierre-Yves Chibon 9c2953
    return flask.jsonify({"version": pagure.__api_version__})
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 9c2953
@API.route("/users/")
Pierre-Yves Chibon 9c2953
@API.route("/users")
Pierre-Yves Chibon 0537b7
def api_users():
Pierre-Yves Chibon 9c2953
    """
Pierre-Yves Chibon 0537b7
    List users
Pierre-Yves Chibon 0537b7
    -----------
LubomĂ­r SedlĂ¡Å™ f02111
    Retrieve users that have logged into the Pagure instance.
Lei Yang 39bfe2
    This can then be used as input for autocompletion in some forms/fields.
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 0537b7
    ::
Pierre-Yves Chibon 0537b7
Lei Yang 566c51
        GET /api/0/users
Lei Yang 566c51
Lei Yang 566c51
    Parameters
Lei Yang 566c51
    ^^^^^^^^^^
Pierre-Yves Chibon 0537b7
Lei Yang d559d1
    +---------------+----------+---------------+------------------------------+
Lei Yang d559d1
    | Key           | Type     | Optionality   | Description                  |
Lei Yang d559d1
    +===============+==========+===============+==============================+
Lei Yang d559d1
    | ``pattern``   | string   | Optional      | | Filters the starting       |
Lei Yang d559d1
    |               |          |               |   letters of the usernames   |
Lei Yang d559d1
    +---------------+----------+---------------+------------------------------+
Pierre-Yves Chibon 0537b7
Lei Yang 566c51
    Sample response
Lei Yang 566c51
    ^^^^^^^^^^^^^^^
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 0537b7
    ::
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 0537b7
        {
Pierre-Yves Chibon 7a734f
          "total_users": 2,
Pierre-Yves Chibon 0537b7
          "users": ["user1", "user2"]
Pierre-Yves Chibon 0537b7
        }
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 9c2953
    """
Pierre-Yves Chibon 9c2953
    pattern = flask.request.args.get("pattern", None)
Pierre-Yves Chibon 9c2953
    if pattern is not None and not pattern.endswith("*"):
Pierre-Yves Chibon 9c2953
        pattern += "*"
Pierre-Yves Chibon 0537b7
Pierre-Yves Chibon 930073
    users = pagure.lib.query.search_user(flask.g.session, pattern=pattern)
Pierre-Yves Chibon 7a734f
Pierre-Yves Chibon 0537b7
    return flask.jsonify(
Pierre-Yves Chibon 0537b7
        {
Pierre-Yves Chibon 9c2953
            "total_users": len(users),
Pierre-Yves Chibon 9c2953
            "users": [usr.username for usr in users],
Pierre-Yves Chibon 9c2953
            "mention": [
Pierre-Yves Chibon 9c2953
                {
Pierre-Yves Chibon 9c2953
                    "username": usr.username,
Pierre-Yves Chibon 9c2953
                    "name": usr.fullname,
Pierre-Yves Chibon 930073
                    "image": pagure.lib.query.avatar_url_from_email(
Pierre-Yves Chibon 9c2953
                        usr.default_email, size=16
Pierre-Yves Chibon 9c2953
                    ),
Pierre-Yves Chibon 9c2953
                }
Pierre-Yves Chibon 9c2953
                for usr in users
Pierre-Yves Chibon 9c2953
            ],
Pierre-Yves Chibon 0537b7
        }
Pierre-Yves Chibon 0537b7
    )
Pierre-Yves Chibon 89a23a
Pierre-Yves Chibon 89a23a
Pierre-Yves Chibon 9c2953
@API.route("/-/whoami", methods=["POST"])
Pierre-Yves Chibon 48ad71
@api_login_optional()
Pierre-Yves Chibon 48ad71
def api_whoami():
Pierre-Yves Chibon 9c2953
    """
Pierre-Yves Chibon 48ad71
    Who am I?
Pierre-Yves Chibon 48ad71
    ---------
Pierre-Yves Chibon 48ad71
    This API endpoint will return the username associated with the provided
Pierre-Yves Chibon 48ad71
    API token.
Pierre-Yves Chibon 48ad71
Pierre-Yves Chibon 48ad71
    ::
Pierre-Yves Chibon 48ad71
Pierre-Yves Chibon 48ad71
        POST /api/0/-/whoami
Pierre-Yves Chibon 48ad71
Pierre-Yves Chibon 48ad71
Pierre-Yves Chibon 48ad71
    Sample response
Pierre-Yves Chibon 48ad71
    ^^^^^^^^^^^^^^^
Pierre-Yves Chibon 48ad71
Pierre-Yves Chibon 48ad71
    ::
Pierre-Yves Chibon 48ad71
Pierre-Yves Chibon 48ad71
        {
Pierre-Yves Chibon 48ad71
          "username": "user1"
Pierre-Yves Chibon 48ad71
        }
Pierre-Yves Chibon 48ad71
Pierre-Yves Chibon 9c2953
    """
Pierre-Yves Chibon 48ad71
Pierre-Yves Chibon 48ad71
    if authenticated():
Pierre-Yves Chibon 9c2953
        return flask.jsonify({"username": flask.g.fas_user.username})
Pierre-Yves Chibon 48ad71
    else:
Pierre-Yves Chibon 48ad71
        output = {
Pierre-Yves Chibon 9c2953
            "error_code": APIERROR.EINVALIDTOK.name,
Pierre-Yves Chibon 9c2953
            "error": APIERROR.EINVALIDTOK.value,
Pierre-Yves Chibon 48ad71
        }
Pierre-Yves Chibon 48ad71
        jsonout = flask.jsonify(output)
Pierre-Yves Chibon 48ad71
        jsonout.status_code = 401
Pierre-Yves Chibon 48ad71
        return jsonout
Pierre-Yves Chibon 48ad71
Pierre-Yves Chibon 48ad71
Pierre-Yves Chibon 9c2953
@API.route("/task/<taskid>/status")</taskid>
Pierre-Yves Chibon 9c2953
@API.route("/task/<taskid>/status/")</taskid>
Patrick Uiterwijk 61fdf2
def api_task_status(taskid):
Pierre-Yves Chibon 9c2953
    """
Patrick Uiterwijk 61fdf2
    Return the status of a async task
Pierre-Yves Chibon 9c2953
    """
Patrick Uiterwijk 61fdf2
    result = pagure.lib.tasks.get_result(taskid)
Slavek Kabrda 92297a
    if not result.ready():
Pierre-Yves Chibon 9c2953
        output = {"ready": False, "status": result.status}
Patrick Uiterwijk 61fdf2
    else:
Pierre-Yves Chibon 9c2953
        output = {
Pierre-Yves Chibon 9c2953
            "ready": True,
Slavek Kabrda 92297a
            "successful": result.successful(),
Pierre-Yves Chibon 9c2953
            "status": result.status,
Pierre-Yves Chibon 9c2953
        }
Patrick Uiterwijk 61fdf2
Patrick Uiterwijk 61fdf2
    return flask.jsonify(output)
Patrick Uiterwijk 61fdf2
Patrick Uiterwijk 61fdf2
Pierre-Yves Chibon 9c2953
@API.route("/<repo>/tags")</repo>
Pierre-Yves Chibon 9c2953
@API.route("/<repo>/tags/")</repo>
Pierre-Yves Chibon 9c2953
@API.route("/fork/<username>/<repo>/tags")</repo></username>
Pierre-Yves Chibon 9c2953
@API.route("/fork/<username>/<repo>/tags/")</repo></username>
Pierre-Yves Chibon 89a23a
def api_project_tags(repo, username=None):
Pierre-Yves Chibon 9c2953
    """
Pierre-Yves Chibon 89a23a
    List all the tags of a project
Pierre-Yves Chibon 89a23a
    ------------------------------
Lei Yang 566c51
    List the tags made on the project's issues.
Pierre-Yves Chibon 89a23a
Pierre-Yves Chibon 89a23a
    ::
Pierre-Yves Chibon 89a23a
Lei Yang 566c51
        GET /api/0/<repo>/tags</repo>
Lei Yang 566c51
Lei Yang 566c51
    ::
Pierre-Yves Chibon 89a23a
Lei Yang 566c51
        GET /api/0/fork/<username>/<repo>/tags</repo></username>
Pierre-Yves Chibon 89a23a
Lei Yang 566c51
    Parameters
Lei Yang 566c51
    ^^^^^^^^^^
Pierre-Yves Chibon 89a23a
Lei Yang d559d1
    +---------------+----------+---------------+--------------------------+
Lei Yang d559d1
    | Key           | Type     | Optionality   | Description              |
Lei Yang d559d1
    +===============+==========+===============+==========================+
Lei Yang d559d1
    | ``pattern``   | string   | Optional      | | Filters the starting   |
Lei Yang d559d1
    |               |          |               |   letters of the tags    |
Lei Yang d559d1
    +---------------+----------+---------------+--------------------------+
Lei Yang 566c51
Lei Yang 566c51
    Sample response
Lei Yang 566c51
    ^^^^^^^^^^^^^^^
Pierre-Yves Chibon 89a23a
Pierre-Yves Chibon 89a23a
    ::
Pierre-Yves Chibon 89a23a
Pierre-Yves Chibon 89a23a
        {
Pierre-Yves Chibon 7a734f
          "total_tags": 2,
Pierre-Yves Chibon 89a23a
          "tags": ["tag1", "tag2"]
Pierre-Yves Chibon 89a23a
        }
Pierre-Yves Chibon 89a23a
Pierre-Yves Chibon 9c2953
    """
Pierre-Yves Chibon b130e5
Pierre-Yves Chibon 9c2953
    pattern = flask.request.args.get("pattern", None)
Pierre-Yves Chibon 9c2953
    if pattern is not None and not pattern.endswith("*"):
Pierre-Yves Chibon 9c2953
        pattern += "*"
Pierre-Yves Chibon 89a23a
Pierre-Yves Chibon b130e5
    project_obj = get_authorized_api_project(flask.g.session, repo, username)
Pierre-Yves Chibon b1fc61
    if not project_obj:
Pierre-Yves Chibon 9c2953
        output = {"output": "notok", "error": "Project not found"}
Pierre-Yves Chibon 89a23a
        jsonout = flask.jsonify(output)
Pierre-Yves Chibon 89a23a
        jsonout.status_code = 404
Pierre-Yves Chibon 89a23a
        return jsonout
Pierre-Yves Chibon 89a23a
Pierre-Yves Chibon 930073
    tags = pagure.lib.query.get_tags_of_project(
Pierre-Yves Chibon 9c2953
        flask.g.session, project_obj, pattern=pattern
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 7a734f
Pierre-Yves Chibon 89a23a
    return flask.jsonify(
Pierre-Yves Chibon 9c2953
        {"total_tags": len(tags), "tags": [tag.tag for tag in tags]}
Pierre-Yves Chibon 89a23a
    )
Pierre-Yves Chibon aa4d23
Pierre-Yves Chibon aa4d23
Pierre-Yves Chibon 9c2953
@API.route("/error_codes/")
Pierre-Yves Chibon 9c2953
@API.route("/error_codes")
Pierre-Yves Chibon 9c2953
@API.route("/-/error_codes")
Pierre-Yves Chibon 88273d
def api_error_codes():
Pierre-Yves Chibon 9c2953
    """
Pierre-Yves Chibon 88273d
    Error codes
Pierre-Yves Chibon 88273d
    ------------
Lei Yang 566c51
    Get a dictionary (hash) of all error codes.
Pierre-Yves Chibon 88273d
Pierre-Yves Chibon 88273d
    ::
Pierre-Yves Chibon 88273d
Pierre-Yves Chibon 0b9b6b
        GET /api/0/-/error_codes
Pierre-Yves Chibon 88273d
Lei Yang 566c51
    Sample response
Lei Yang 566c51
    ^^^^^^^^^^^^^^^
Pierre-Yves Chibon 88273d
Pierre-Yves Chibon 88273d
    ::
Pierre-Yves Chibon 88273d
Pierre-Yves Chibon 88273d
        {
Pierre-Yves Chibon 88273d
          ENOCODE: 'Variable message describing the issue',
Pierre-Yves Chibon 88273d
          ENOPROJECT: 'Project not found',
Pierre-Yves Chibon 88273d
        }
Pierre-Yves Chibon 88273d
Pierre-Yves Chibon 9c2953
    """
Pierre-Yves Chibon 4768f2
    errors = {
Pierre-Yves Chibon 9c2953
        val.name: val.value for val in APIERROR.__members__.values()
Pierre-Yves Chibon 4768f2
    }  # pylint: disable=no-member
Pierre-Yves Chibon 88273d
Pierre-Yves Chibon 88273d
    return flask.jsonify(errors)
Pierre-Yves Chibon aa08df
Pierre-Yves Chibon aa08df
Pierre-Yves Chibon 9c2953
@API.route("/")
Pierre-Yves Chibon aa08df
def api():
Pierre-Yves Chibon 9c2953
    """ Display the api information page. """
Pierre-Yves Chibon b42ba1
    api_project_doc = load_doc(project.api_project)
Pierre-Yves Chibon 16f973
    api_projects_doc = load_doc(project.api_projects)
Matt Prahl 398dcf
    api_project_watchers_doc = load_doc(project.api_project_watchers)
Pierre-Yves Chibon b42ba1
    api_git_tags_doc = load_doc(project.api_git_tags)
Matt Prahl ad5147
    api_project_git_urls_doc = load_doc(project.api_project_git_urls)
Matt Prahl 398dcf
    api_git_branches_doc = load_doc(project.api_git_branches)
Matt Prahl 398dcf
    api_new_project_doc = load_doc(project.api_new_project)
Matt Prahl 398dcf
    api_modify_project_doc = load_doc(project.api_modify_project)
Matt Prahl 398dcf
    api_fork_project_doc = load_doc(project.api_fork_project)
Karsten Hopp be01e8
    api_modify_acls_doc = load_doc(project.api_modify_acls)
Matt Prahl 489ad1
    api_generate_acls_doc = load_doc(project.api_generate_acls)
mprahl 7d811e
    api_new_branch_doc = load_doc(project.api_new_branch)
Slavek Kabrda 3e4583
    api_commit_flags_doc = load_doc(project.api_commit_flags)
Pierre-Yves Chibon 8715b5
    api_commit_add_flag_doc = load_doc(project.api_commit_add_flag)
Pierre-Yves Chibon f778bd
    api_update_project_watchers_doc = load_doc(
Pierre-Yves Chibon 9c2953
        project.api_update_project_watchers
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 0ede45
    api_get_project_options_doc = load_doc(project.api_get_project_options)
Pierre-Yves Chibon 473ccb
    api_modify_project_options_doc = load_doc(
Pierre-Yves Chibon 473ccb
        project.api_modify_project_options
Pierre-Yves Chibon 473ccb
    )
Pierre-Yves Chibon 1e355f
Pierre-Yves Chibon 559b89
    issues = []
Pierre-Yves Chibon 9c2953
    if pagure_config.get("ENABLE_TICKETS", True):
Pierre-Yves Chibon 559b89
        issues.append(load_doc(issue.api_new_issue))
Pierre-Yves Chibon 559b89
        issues.append(load_doc(issue.api_view_issues))
Pierre-Yves Chibon 559b89
        issues.append(load_doc(issue.api_view_issue))
Pierre-Yves Chibon 559b89
        issues.append(load_doc(issue.api_view_issue_comment))
Pierre-Yves Chibon 559b89
        issues.append(load_doc(issue.api_comment_issue))
Pierre-Yves Chibon eec033
        issues.append(load_doc(issue.api_update_custom_field))
Clement Verna 19890f
        issues.append(load_doc(issue.api_update_custom_fields))
Pierre-Yves Chibon eec033
        issues.append(load_doc(issue.api_change_status_issue))
Pierre-Yves Chibon ca9e52
        issues.append(load_doc(issue.api_change_milestone_issue))
Pierre-Yves Chibon eec033
        issues.append(load_doc(issue.api_assign_issue))
Pierre-Yves Chibon eec033
        issues.append(load_doc(issue.api_subscribe_issue))
Pierre-Yves Chibon 36669f
        issues.append(load_doc(user.api_view_user_issues))
Pierre-Yves Chibon a514ae
Pierre-Yves Chibon 602511
    ci_doc = []
Patrick Uiterwijk 3f97f6
    if pagure_config.get("PAGURE_CI_SERVICES", False):
Pierre-Yves Chibon 9c2953
        if "jenkins" in pagure_config["PAGURE_CI_SERVICES"]:
Pierre-Yves Chibon 602511
            ci_doc.append(load_doc(jenkins.jenkins_ci_notification))
Pierre-Yves Chibon 3b79ad
Pierre-Yves Chibon 7575b4
    api_pull_request_create_doc = load_doc(fork.api_pull_request_create)
Pierre-Yves Chibon a514ae
    api_pull_request_views_doc = load_doc(fork.api_pull_request_views)
Pierre-Yves Chibon a514ae
    api_pull_request_view_doc = load_doc(fork.api_pull_request_view)
Pierre-Yves Chibon 8e493d
    api_pull_request_diffstats_doc = load_doc(fork.api_pull_request_diffstats)
Slavek Kabrda 1a6e21
    api_pull_request_by_uid_view_doc = load_doc(
Slavek Kabrda 1a6e21
        fork.api_pull_request_by_uid_view
Slavek Kabrda 1a6e21
    )
Pierre-Yves Chibon a514ae
    api_pull_request_merge_doc = load_doc(fork.api_pull_request_merge)
Pierre-Yves Chibon 5798ff
    api_pull_request_rebase_doc = load_doc(fork.api_pull_request_rebase)
Pierre-Yves Chibon a514ae
    api_pull_request_close_doc = load_doc(fork.api_pull_request_close)
Pierre-Yves Chibon d5d683
    api_pull_request_add_comment_doc = load_doc(
Pierre-Yves Chibon 9c2953
        fork.api_pull_request_add_comment
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon d5d683
    api_pull_request_add_flag_doc = load_doc(fork.api_pull_request_add_flag)
Pierre-Yves Chibon a514ae
Pierre-Yves Chibon aa08df
    api_version_doc = load_doc(api_version)
Pierre-Yves Chibon 48ad71
    api_whoami_doc = load_doc(api_whoami)
Pierre-Yves Chibon aa08df
    api_users_doc = load_doc(api_users)
Lei Yang 07ea6c
    api_view_user_doc = load_doc(user.api_view_user)
Pierre-Yves Chibon c051a9
    api_view_user_activity_stats_doc = load_doc(
Pierre-Yves Chibon 9c2953
        user.api_view_user_activity_stats
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon f21cb0
    api_view_user_activity_date_doc = load_doc(
Pierre-Yves Chibon 9c2953
        user.api_view_user_activity_date
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 36669f
    api_view_user_requests_filed_doc = load_doc(
Pierre-Yves Chibon 9c2953
        user.api_view_user_requests_filed
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 36669f
    api_view_user_requests_actionable_doc = load_doc(
Pierre-Yves Chibon 9c2953
        user.api_view_user_requests_actionable
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon c051a9
Matt Prahl 1a51d9
    api_view_group_doc = load_doc(group.api_view_group)
Matt Prahl 802ab8
    api_groups_doc = load_doc(group.api_groups)
Matt Prahl 1a51d9
Pierre-Yves Chibon 9c2953
    if pagure_config.get("ENABLE_TICKETS", True):
Pierre-Yves Chibon 1de9c5
        api_project_tags_doc = load_doc(api_project_tags)
Pierre-Yves Chibon aa08df
    api_error_codes_doc = load_doc(api_error_codes)
Pierre-Yves Chibon aa08df
Pierre-Yves Chibon 9c2953
    extras = [api_whoami_doc, api_version_doc, api_error_codes_doc]
Pierre-Yves Chibon 1de9c5
Pierre-Yves Chibon 9c2953
    if pagure_config.get("ENABLE_TICKETS", True):
Pierre-Yves Chibon 1de9c5
        extras.append(api_project_tags_doc)
Pierre-Yves Chibon 1de9c5
Pierre-Yves Chibon aa08df
    return flask.render_template(
Pierre-Yves Chibon 9c2953
        "api.html",
Pierre-Yves Chibon b130e5
        version=pagure.__api_version__,
Pierre-Yves Chibon ea3e81
        api_doc=APIDOC,
Pierre-Yves Chibon a514ae
        projects=[
Pierre-Yves Chibon 78b253
            api_new_project_doc,
Matt Prahl 30f8b1
            api_modify_project_doc,
Pierre-Yves Chibon b42ba1
            api_project_doc,
Pierre-Yves Chibon 16f973
            api_projects_doc,
Pierre-Yves Chibon b42ba1
            api_git_tags_doc,
Matt Prahl 398dcf
            api_project_git_urls_doc,
Matt Prahl 398dcf
            api_project_watchers_doc,
Matt Prahl 398dcf
            api_git_branches_doc,
Matt Prahl 489ad1
            api_fork_project_doc,
Karsten Hopp be01e8
            api_modify_acls_doc,
mprahl 7d811e
            api_generate_acls_doc,
Pierre-Yves Chibon 8715b5
            api_new_branch_doc,
Slavek Kabrda 3e4583
            api_commit_flags_doc,
Pierre-Yves Chibon 8715b5
            api_commit_add_flag_doc,
Pierre-Yves Chibon f778bd
            api_update_project_watchers_doc,
Pierre-Yves Chibon 0ede45
            api_get_project_options_doc,
Pierre-Yves Chibon 473ccb
            api_modify_project_options_doc,
Pierre-Yves Chibon 07a970
        ],
Pierre-Yves Chibon 559b89
        issues=issues,
Pierre-Yves Chibon 07a970
        requests=[
Pierre-Yves Chibon 7575b4
            api_pull_request_create_doc,
Pierre-Yves Chibon a514ae
            api_pull_request_views_doc,
Pierre-Yves Chibon a514ae
            api_pull_request_view_doc,
Pierre-Yves Chibon f80f17
            api_pull_request_diffstats_doc,
Slavek Kabrda 1a6e21
            api_pull_request_by_uid_view_doc,
Pierre-Yves Chibon a514ae
            api_pull_request_merge_doc,
Pierre-Yves Chibon 5798ff
            api_pull_request_rebase_doc,
Pierre-Yves Chibon a514ae
            api_pull_request_close_doc,
Pierre-Yves Chibon a514ae
            api_pull_request_add_comment_doc,
Pierre-Yves Chibon d5d683
            api_pull_request_add_flag_doc,
Pierre-Yves Chibon a514ae
        ],
Pierre-Yves Chibon a514ae
        users=[
Pierre-Yves Chibon a514ae
            api_users_doc,
Lei Yang 07ea6c
            api_view_user_doc,
Pierre-Yves Chibon c051a9
            api_view_user_activity_stats_doc,
Pierre-Yves Chibon f21cb0
            api_view_user_activity_date_doc,
Pierre-Yves Chibon 36669f
            api_view_user_requests_filed_doc,
Pierre-Yves Chibon 36669f
            api_view_user_requests_actionable_doc,
Pierre-Yves Chibon a514ae
        ],
Pierre-Yves Chibon 9c2953
        groups=[api_groups_doc, api_view_group_doc],
Pierre-Yves Chibon 602511
        ci=ci_doc,
Pierre-Yves Chibon 1de9c5
        extras=extras,
Pierre-Yves Chibon aa08df
    )