コード例 #1
0
ファイル: app.py プロジェクト: pypingou/pagure_mirror
def search():
    """ Search this pagure instance for projects or users.
    """
    stype = flask.request.args.get("type", "projects")
    term = flask.request.args.get("term")
    page = flask.request.args.get("page", 1)
    direct = is_true(flask.request.values.get("direct", False))

    try:
        page = int(page)
        if page < 1:
            page = 1
    except ValueError:
        page = 1

    if direct:
        return flask.redirect(flask.url_for("ui_ns.view_repo", repo="") + term)

    if stype == "projects":
        return flask.redirect(
            flask.url_for("ui_ns.view_projects", pattern=term)
        )
    elif stype == "projects_forks":
        return flask.redirect(
            flask.url_for("view_projects", pattern=term, forks=True)
        )
    elif stype == "groups":
        return flask.redirect(flask.url_for("ui_ns.view_group", group=term))
    else:
        return flask.redirect(flask.url_for("ui_ns.view_users", username=term))
コード例 #2
0
ファイル: app.py プロジェクト: pypingou/pagure
def wait_task(taskid):
    """ Shows a wait page until the task finishes. """
    task = pagure.lib.tasks.get_result(taskid)

    is_js = is_true(flask.request.args.get("js"))

    prev = flask.request.args.get("prev")
    if not is_safe_url(prev):
        prev = flask.url_for("index")

    count = flask.request.args.get("count", 0)
    try:
        count = int(count)
        if count < 1:
            count = 0
    except ValueError:
        count = 0

    if task.ready():
        if is_js:
            flask.abort(417)
        return flask.redirect(get_task_redirect_url(task, prev))
    else:
        if is_js:
            return flask.jsonify({"count": count + 1, "status": task.status})

        return flask.render_template(
            "waiting.html", task=task, count=count, prev=prev
        )
コード例 #3
0
ファイル: app.py プロジェクト: pypingou/pagure_mirror
def wait_task(taskid):
    """ Shows a wait page until the task finishes. """
    task = pagure.lib.tasks.get_result(taskid)

    is_js = is_true(flask.request.args.get("js"))

    prev = flask.request.args.get("prev")
    if not is_safe_url(prev):
        prev = flask.url_for("index")

    count = flask.request.args.get("count", 0)
    try:
        count = int(count)
        if count < 1:
            count = 0
    except ValueError:
        count = 0

    if task.ready():
        if is_js:
            flask.abort(417)
        return flask.redirect(get_task_redirect_url(task, prev))
    else:
        if is_js:
            return flask.jsonify({"count": count + 1, "status": task.status})

        return flask.render_template(
            "waiting.html", task=task, count=count, prev=prev
        )
コード例 #4
0
ファイル: app.py プロジェクト: pypingou/pagure
def search():
    """ Search this pagure instance for projects or users.
    """
    stype = flask.request.args.get("type", "projects")
    term = flask.request.args.get("term")
    page = flask.request.args.get("page", 1)
    direct = is_true(flask.request.values.get("direct", False))

    try:
        page = int(page)
        if page < 1:
            page = 1
    except ValueError:
        page = 1

    if direct:
        return flask.redirect(flask.url_for("ui_ns.view_repo", repo="") + term)

    if stype == "projects":
        return flask.redirect(
            flask.url_for("ui_ns.view_projects", pattern=term)
        )
    elif stype == "projects_forks":
        return flask.redirect(
            flask.url_for("view_projects", pattern=term, forks=True)
        )
    elif stype == "groups":
        return flask.redirect(flask.url_for("ui_ns.view_group", group=term))
    else:
        return flask.redirect(flask.url_for("ui_ns.view_users", username=term))
コード例 #5
0
ファイル: issue.py プロジェクト: pypingou/pagure
def api_new_issue(repo, username=None, namespace=None):
    """
    Create a new issue
    ------------------
    Open a new issue on a project.

    ::

        POST /api/0/<repo>/new_issue
        POST /api/0/<namespace>/<repo>/new_issue

    ::

        POST /api/0/fork/<username>/<repo>/new_issue
        POST /api/0/fork/<username>/<namespace>/<repo>/new_issue

    Input
    ^^^^^

    +-------------------+--------+-------------+---------------------------+
    | Key               | Type   | Optionality | Description               |
    +===================+========+=============+===========================+
    | ``title``         | string | Mandatory   | The title of the issue    |
    +-------------------+--------+-------------+---------------------------+
    | ``issue_content`` | string | Mandatory   | | The description of the  |
    |                   |        |             |   issue                   |
    +-------------------+--------+-------------+---------------------------+
    | ``private``       | boolean| Optional    | | Include this key if     |
    |                   |        |             |   you want a private issue|
    |                   |        |             |   to be created           |
    +-------------------+--------+-------------+---------------------------+
    | ``priority``      | string | Optional    | | The priority to set to  |
    |                   |        |             |   this ticket from the    |
    |                   |        |             |   list of priorities set  |
    |                   |        |             |   in the project          |
    +-------------------+--------+-------------+---------------------------+
    | ``milestone``     | string | Optional    | | The milestone to assign |
    |                   |        |             |   to this ticket from the |
    |                   |        |             |   list of milestones set  |
    |                   |        |             |   in the project          |
    +-------------------+--------+-------------+---------------------------+
    | ``tag``           | string | Optional    | | Comma separated list of |
    |                   |        |             |   tags to link to this    |
    |                   |        |             |   ticket from the list of |
    |                   |        |             |   tags in the project     |
    +-------------------+--------+-------------+---------------------------+
    | ``assignee``      | string | Optional    | | The username of the user|
    |                   |        |             |   to assign this ticket to|
    +-------------------+--------+-------------+---------------------------+

    Sample response
    ^^^^^^^^^^^^^^^

    ::

        {
          "issue": {
            "assignee": null,
            "blocks": [],
            "close_status": null,
            "closed_at": null,
            "closed_by": null,
            "comments": [],
            "content": "This issue needs attention",
            "custom_fields": [],
            "date_created": "1479458613",
            "depends": [],
            "id": 1,
            "milestone": null,
            "priority": null,
            "private": false,
            "status": "Open",
            "tags": [],
            "title": "test issue",
            "user": {
              "fullname": "PY C",
              "name": "pingou"
            }
          },
          "message": "Issue created"
        }

    """
    output = {}
    repo = _get_repo(repo, username, namespace)
    _check_issue_tracker(repo)
    _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)

    form = pagure.forms.IssueFormSimplied(
        priorities=repo.priorities,
        milestones=repo.milestones,
        csrf_enabled=False,
    )
    if form.validate_on_submit():
        title = form.title.data
        content = form.issue_content.data
        milestone = form.milestone.data or None
        private = is_true(form.private.data)
        priority = form.priority.data or None
        assignee = get_request_data().get("assignee", "").strip() or None
        tags = [
            tag.strip()
            for tag in get_request_data().get("tag", "").split(",")
            if tag.strip()
        ]

        try:
            issue = pagure.lib.query.new_issue(
                flask.g.session,
                repo=repo,
                title=title,
                content=content,
                private=private,
                assignee=assignee,
                milestone=milestone,
                priority=priority,
                tags=tags,
                user=flask.g.fas_user.username,
            )
            flask.g.session.flush()
            # If there is a file attached, attach it.
            filestream = flask.request.files.get("filestream")
            if filestream and "<!!image>" in issue.content:
                new_filename = pagure.lib.query.add_attachment(
                    repo=repo,
                    issue=issue,
                    attachmentfolder=pagure_config["ATTACHMENTS_FOLDER"],
                    user=user_obj,
                    filename=filestream.filename,
                    filestream=filestream.stream,
                )
                # Replace the <!!image> tag in the comment with the link
                # to the actual image
                filelocation = flask.url_for(
                    "ui_ns.view_issue_raw_file",
                    repo=repo.name,
                    username=username,
                    filename="files/%s" % new_filename,
                )
                new_filename = new_filename.split("-", 1)[1]
                url = "[![%s](%s)](%s)" % (
                    new_filename,
                    filelocation,
                    filelocation,
                )
                issue.content = issue.content.replace("<!!image>", url)
                flask.g.session.add(issue)
                flask.g.session.flush()

            flask.g.session.commit()
            output["message"] = "Issue created"
            output["issue"] = issue.to_json(public=True)
        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
        )

    jsonout = flask.jsonify(output)
    return jsonout
コード例 #6
0
ファイル: issue.py プロジェクト: pypingou/pagure
def api_view_issue(repo, issueid, username=None, namespace=None):
    """
    Issue information
    -----------------
    Retrieve information of a specific issue.

    ::

        GET /api/0/<repo>/issue/<issue id>
        GET /api/0/<namespace>/<repo>/issue/<issue id>

    ::

        GET /api/0/fork/<username>/<repo>/issue/<issue id>
        GET /api/0/fork/<username>/<namespace>/<repo>/issue/<issue id>

    The identifier provided can be either the unique identifier or the
    regular identifier used in the UI (for example ``24`` in
    ``/forks/user/test/issue/24``)

    Sample response
    ^^^^^^^^^^^^^^^

    ::

        {
          "assignee": null,
          "blocks": [],
          "comments": [],
          "content": "This issue needs attention",
          "date_created": "1431414800",
          "depends": ["4"],
          "id": 1,
          "private": false,
          "status": "Open",
          "tags": [],
          "title": "test issue",
          "user": {
            "fullname": "PY C",
            "name": "pingou"
          }
        }

    """
    comments = is_true(flask.request.args.get("comments", True))

    repo = _get_repo(repo, username, namespace)
    _check_issue_tracker(repo)
    _check_token(repo)

    issue_id = issue_uid = None
    try:
        issue_id = int(issueid)
    except (ValueError, TypeError):
        issue_uid = issueid

    issue = _get_issue(repo, issue_id, issueuid=issue_uid)
    _check_private_issue_access(issue)

    jsonout = flask.jsonify(issue.to_json(public=True, with_comments=comments))
    return jsonout
コード例 #7
0
ファイル: issue.py プロジェクト: pypingou/pagure
def api_view_issues(repo, username=None, namespace=None):
    """
    List project's issues
    ---------------------
    List issues of a project.

    ::

        GET /api/0/<repo>/issues
        GET /api/0/<namespace>/<repo>/issues

    ::

        GET /api/0/fork/<username>/<repo>/issues
        GET /api/0/fork/<username>/<namespace>/<repo>/issues

    Parameters
    ^^^^^^^^^^

    +---------------+---------+--------------+---------------------------+
    | Key           | Type    | Optionality  | Description               |
    +===============+=========+==============+===========================+
    | ``status``    | string  | Optional     | | Filters the status of   |
    |               |         |              |   issues. Fetches all the |
    |               |         |              |   issues if status is     |
    |               |         |              |   ``all``. Default:       |
    |               |         |              |   ``Open``                |
    +---------------+---------+--------------+---------------------------+
    | ``tags``      | string  | Optional     | | A list of tags you      |
    |               |         |              |   wish to filter. If      |
    |               |         |              |   you want to filter      |
    |               |         |              |   for issues not having   |
    |               |         |              |   a tag, add an           |
    |               |         |              |   exclamation mark in     |
    |               |         |              |   front of it             |
    +---------------+---------+--------------+---------------------------+
    | ``assignee``  | string  | Optional     | | Filter the issues       |
    |               |         |              |   by assignee             |
    +---------------+---------+--------------+---------------------------+
    | ``author``    | string  | Optional     | | Filter the issues       |
    |               |         |              |   by creator              |
    +---------------+---------+--------------+---------------------------+
    | ``milestones``| list of | Optional     | | Filter the issues       |
    |               | strings |              |   by milestone            |
    +---------------+---------+--------------+---------------------------+
    | ``priority``  | string  | Optional     | | Filter the issues       |
    |               |         |              |   by priority             |
    +---------------+---------+--------------+---------------------------+
    | ``no_stones`` | boolean | Optional     | | If true returns only the|
    |               |         |              |   issues having no        |
    |               |         |              |   milestone, if false     |
    |               |         |              |   returns only the issues |
    |               |         |              |   having a milestone      |
    +---------------+---------+--------------+---------------------------+
    | ``since``     | string  | Optional     | | Filter the issues       |
    |               |         |              |   updated after this date.|
    |               |         |              |   The date can either be  |
    |               |         |              |   provided as an unix date|
    |               |         |              |   or in the format Y-M-D  |
    +---------------+---------+--------------+---------------------------+
    | ``order``     | string  | Optional     | | Set the ordering of the |
    |               |         |              |   issues. This can be     |
    |               |         |              |   ``asc`` or ``desc``.    |
    |               |         |              |   Default: ``desc``       |
    +---------------+---------+--------------+---------------------------+
    | ``page``      | int      | Optional    | | Specifies which         |
    |               |          |             |   page to return          |
    |               |          |             |   (defaults to: 1)        |
    +---------------+----------+-------------+---------------------------+
    | ``per_page``  | int      | Optional    | | The number of projects  |
    |               |          |             |   to return per page.     |
    |               |          |             |   The maximum is 100.     |
    +---------------+----------+-------------+---------------------------+

    Sample response
    ^^^^^^^^^^^^^^^

    ::

        {
          "args": {
            "assignee": null,
            "author": null,
            'milestones': [],
            'no_stones': null,
            'order': null,
            'priority': null,
            "since": null,
            "status": "Closed",
            "tags": [
              "0.1"
            ]
          },
          "total_issues": 1,
          "issues": [
            {
              "assignee": null,
              "blocks": ["1"],
              "close_status": null,
              "closed_at": null,
              "closed_by": null,
              "comments": [],
              "content": "asd",
              "custom_fields": [],
              "date_created": "1427442217",
              "depends": [],
              "id": 4,
              "last_updated": "1533815358",
              "milestone": null,
              "priority": null,
              "private": false,
              "status": "Fixed",
              "tags": [
                "0.1"
              ],
              "title": "bug",
              "user": {
                "fullname": "PY.C",
                "name": "pingou"
              }
            }
          ],
          'pagination': {
            'first': 'http://localhost/api/0/test/issues?per_page=20&page=1',
            'last': 'http://localhost/api/0/test/issues?per_page=20&page=1',
            'next': null,
            'page': 1,
            'pages': 1,
            'per_page': 20,
            'prev': null
          },
        }

    """
    repo = _get_repo(repo, username, namespace)
    _check_issue_tracker(repo)
    _check_token(repo)

    assignee = flask.request.args.get("assignee", None)
    author = flask.request.args.get("author", None)
    milestone = flask.request.args.getlist("milestones", None)
    no_stones = flask.request.args.get("no_stones", None)
    if no_stones is not None:
        no_stones = is_true(no_stones)
    priority = flask.request.args.get("priority", None)
    since = flask.request.args.get("since", None)
    order = flask.request.args.get("order", None)
    status = flask.request.args.get("status", None)
    tags = flask.request.args.getlist("tags")
    tags = [tag.strip() for tag in tags if tag.strip()]
    search_id = flask.request.args.get("query_id", None)

    priority_key = None
    if priority:
        found = False
        if priority in repo.priorities:
            found = True
            priority_key = int(priority)
        else:
            for key, val in repo.priorities.items():
                if val.lower() == priority.lower():
                    priority_key = key
                    found = True
                    break

        if not found:
            raise pagure.exceptions.APIError(
                400, error_code=APIERROR.EINVALIDPRIORITY
            )

    # Hide private tickets
    private = False
    # If user is authenticated, show him/her his/her private tickets
    if api_authenticated():
        private = flask.g.fas_user.username
    # If user is repo committer, show all tickets included the private ones
    if is_repo_committer(repo):
        private = None

    params = {
        "session": flask.g.session,
        "repo": repo,
        "tags": tags,
        "assignee": assignee,
        "author": author,
        "private": private,
        "milestones": milestone,
        "priority": priority_key,
        "order": order,
        "no_milestones": no_stones,
        "search_id": search_id,
    }

    if status is not None:
        if status.lower() == "all":
            params.update({"status": None})
        elif status.lower() == "closed":
            params.update({"closed": True})
        else:
            params.update({"status": status})
    else:
        params.update({"status": "Open"})

    updated_after = None
    if since:
        # Validate and convert the time
        if since.isdigit():
            # We assume its a timestamp, so convert it to datetime
            try:
                updated_after = arrow.get(int(since)).datetime
            except ValueError:
                raise pagure.exceptions.APIError(
                    400, error_code=APIERROR.ETIMESTAMP
                )
        else:
            # We assume datetime format, so validate it
            try:
                updated_after = datetime.datetime.strptime(since, "%Y-%m-%d")
            except ValueError:
                raise pagure.exceptions.APIError(
                    400, error_code=APIERROR.EDATETIME
                )

    params.update({"updated_after": updated_after})

    page = get_page()
    per_page = get_per_page()
    params["count"] = True
    issue_cnt = pagure.lib.query.search_issues(**params)
    pagination_metadata = pagure.lib.query.get_pagination_metadata(
        flask.request, page, per_page, issue_cnt
    )
    query_start = (page - 1) * per_page
    query_limit = per_page

    params["count"] = False
    params["limit"] = query_limit
    params["offset"] = query_start
    issues = pagure.lib.query.search_issues(**params)

    jsonout = flask.jsonify(
        {
            "total_issues": len(issues),
            "issues": [issue.to_json(public=True) for issue in issues],
            "args": {
                "assignee": assignee,
                "author": author,
                "milestones": milestone,
                "no_stones": no_stones,
                "order": order,
                "priority": priority,
                "since": since,
                "status": status,
                "tags": tags,
            },
            "pagination": pagination_metadata,
        }
    )
    return jsonout
コード例 #8
0
ファイル: issue.py プロジェクト: pypingou/pagure
def api_subscribe_issue(repo, issueid, username=None, namespace=None):
    """
    Subscribe to an issue
    ---------------------
    Allows someone to subscribe to or unsubscribe from the notifications
    related to an issue.

    ::

        POST /api/0/<repo>/issue/<issue id>/subscribe
        POST /api/0/<namespace>/<repo>/issue/<issue id>/subscribe

    ::

        POST /api/0/fork/<username>/<repo>/issue/<issue id>/subscribe
        POST /api/0/fork/<username>/<namespace>/<repo>/issue/<issue id>/subscribe

    Input
    ^^^^^

    +--------------+----------+---------------+---------------------------+
    | Key          | Type     | Optionality   | Description               |
    +==============+==========+===============+===========================+
    | ``status``   | boolean  | Mandatory     | The intended subscription |
    |              |          |               | status. ``true`` for      |
    |              |          |               | subscribing, ``false``    |
    |              |          |               | for unsubscribing.        |
    +--------------+----------+---------------+---------------------------+

    Sample response
    ^^^^^^^^^^^^^^^

    ::

        {
          "message": "User subscribed",
          "avatar_url": "https://image.png",
          "user": "******"
        }

    """  # noqa
    output = {}
    repo = _get_repo(repo, username, namespace)
    _check_issue_tracker(repo)
    _check_token(repo)

    issue = _get_issue(repo, issueid)
    _check_private_issue_access(issue)

    form = pagure.forms.SubscribtionForm(csrf_enabled=False)
    if form.validate_on_submit():
        status = is_true(form.status.data)
        try:
            # Toggle subscribtion
            message = pagure.lib.query.set_watch_obj(
                flask.g.session,
                user=flask.g.fas_user.username,
                obj=issue,
                watch_status=status,
            )
            flask.g.session.commit()
            output["message"] = message
            user_obj = pagure.lib.query.get_user(
                flask.g.session, flask.g.fas_user.username
            )
            output["avatar_url"] = pagure.lib.query.avatar_url_from_email(
                user_obj.default_email, size=30
            )
            output["user"] = flask.g.fas_user.username
        except SQLAlchemyError as err:  # pragma: no cover
            flask.g.session.rollback()
            _log.exception(err)
            raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR)

    jsonout = flask.jsonify(output)
    return jsonout
コード例 #9
0
def api_view_user_activity_date(username, date):
    """
    User activity on a specific date
    --------------------------------
    Use this endpoint to retrieve activity information about a specific user
    on the specified date.

    ::

        GET /api/0/user/<username>/activity/<date>

    ::

        GET /api/0/user/ralph/activity/2016-01-02

        GET /api/0/user/ralph/activity/2016-01-02?grouped=true


    Parameters
    ^^^^^^^^^^

    +---------------+----------+--------------+----------------------------+
    | Key           | Type     | Optionality  | Description                |
    +===============+==========+==============+============================+
    | ``username``  | string   | Mandatory    | | The username of the user |
    |               |          |              |   whose activity you are   |
    |               |          |              |   interested in.           |
    +---------------+----------+--------------+----------------------------+
    | ``date``      | string   | Mandatory    | | The date of interest,    |
    |               |          |              |   best provided in ISO     |
    |               |          |              |   format: YYYY-MM-DD       |
    +---------------+----------+--------------+----------------------------+
    | ``grouped``   | boolean  | Optional     | | Whether or not to group  |
    |               |          |              |   the commits              |
    +---------------+----------+--------------+----------------------------+


    Sample response
    ^^^^^^^^^^^^^^^

    ::

        {
          "activities": [
            {
              "date": "2016-02-24",
              "date_created": "1456305852",
              "description": "pingou created PR test#44",
              "description_mk": "<p>pingou created PR <a href=\"/test/pull-request/44\" title=\"Update test_foo\">test#44</a></p>",
              "id": 4067,
              "user": {
                "fullname": "Pierre-YvesC",
                "name": "pingou"
              }
            },
            {
              "date": "2016-02-24",
              "date_created": "1456305887",
              "description": "pingou commented on PR test#44",
              "description_mk": "<p>pingou commented on PR <a href=\"/test/pull-request/44\" title=\"Update test_foo\">test#44</a></p>",
              "id": 4112,
              "user": {
                "fullname": "Pierre-YvesC",
                "name": "pingou"
              }
            }
          ]
        }

    """  # noqa
    grouped = is_true(flask.request.args.get("grouped"))
    tz = flask.request.args.get("tz", "UTC")

    try:
        date = arrow.get(date)
        date = date.strftime("%Y-%m-%d")
    except arrow.parser.ParserError as err:
        raise pagure.exceptions.APIError(400,
                                         error_code=APIERROR.ENOCODE,
                                         error=str(err))

    user = _get_user(username=username)

    activities = pagure.lib.query.get_user_activity_day(flask.g.session,
                                                        user,
                                                        date,
                                                        tz=tz)
    js_act = []
    if grouped:
        commits = collections.defaultdict(list)
        acts = []
        for activity in activities:
            if activity.log_type == "committed":
                commits[activity.project.fullname].append(activity)
            else:
                acts.append(activity)
        for project in commits:
            if len(commits[project]) == 1:
                tmp = dict(description_mk=pagure.lib.query.text2markdown(
                    six.text_type(commits[project][0])))
            else:
                tmp = dict(description_mk=pagure.lib.query.text2markdown(
                    "@%s pushed %s commits to %s" %
                    (username, len(commits[project]), project)))
            js_act.append(tmp)
        activities = acts

    for act in activities:
        activity = act.to_json(public=True)
        activity["description_mk"] = pagure.lib.query.text2markdown(
            six.text_type(act))
        js_act.append(activity)

    jsonout = flask.jsonify(dict(activities=js_act, date=date))
    return jsonout
コード例 #10
0
def api_view_user_issues(username):
    """
    List user's issues
    ---------------------
    List issues opened by or assigned to a specific user across all projects.

    ::

        GET /api/0/user/<username>/issues

    Parameters
    ^^^^^^^^^^

    +---------------+---------+--------------+---------------------------+
    | Key           | Type    | Optionality  | Description               |
    +===============+=========+==============+===========================+
    | ``page``      | integer | Mandatory    | | The page requested.     |
    |               |         |              |   Defaults to 1.          |
    +---------------+---------+--------------+---------------------------+
    | ``per_page``  | int     | Optional     | | The number of items     |
    |               |         |              |   to return per page.     |
    |               |         |              |   The maximum is 100.     |
    +---------------+---------+--------------+---------------------------+
    | ``status``    | string  | Optional     | | Filters the status of   |
    |               |         |              |   issues. Fetches all the |
    |               |         |              |   issues if status is     |
    |               |         |              |   ``all``. Default:       |
    |               |         |              |   ``Open``                |
    +---------------+---------+--------------+---------------------------+
    | ``tags``      | string  | Optional     | | A list of tags you      |
    |               |         |              |   wish to filter. If      |
    |               |         |              |   you want to filter      |
    |               |         |              |   for issues not having   |
    |               |         |              |   a tag, add an           |
    |               |         |              |   exclamation mark in     |
    |               |         |              |   front of it             |
    +---------------+---------+--------------+---------------------------+
    | ``milestones``| list of | Optional     | | Filter the issues       |
    |               | strings |              |   by milestone            |
    +---------------+---------+--------------+---------------------------+
    | ``no_stones`` | boolean | Optional     | | If true returns only the|
    |               |         |              |   issues having no        |
    |               |         |              |   milestone, if false     |
    |               |         |              |   returns only the issues |
    |               |         |              |   having a milestone      |
    +---------------+---------+--------------+---------------------------+
    | ``since``     | string  | Optional     | | Filter the issues       |
    |               |         |              |   updated after this date.|
    |               |         |              |   The date can either be  |
    |               |         |              |   provided as an unix date|
    |               |         |              |   or in the format Y-M-D  |
    +---------------+---------+--------------+---------------------------+
    | ``order``     | string  | Optional     | | Set the ordering of the |
    |               |         |              |   issues. This can be     |
    |               |         |              |   ``asc`` or ``desc``.    |
    |               |         |              |   Default: ``desc``       |
    +---------------+---------+--------------+---------------------------+
    | ``order_key`` | string  | Optional     | | Set the ordering key.   |
    |               |         |              |   This can be ``assignee``|
    |               |         |              |   , ``last_updated`` or   |
    |               |         |              |   name of other column.   |
    |               |         |              |   Default:                |
    |               |         |              |          ``date_created`` |
    +---------------+---------+--------------+---------------------------+
    | ``assignee``  | boolean | Optional     | | A boolean of whether to |
    |               |         |              |   return the issues       |
    |               |         |              |   assigned to this user   |
    |               |         |              |   or not. Defaults to True|
    +---------------+---------+--------------+---------------------------+
    | ``author``    | boolean | Optional     | | A boolean of whether to |
    |               |         |              |   return the issues       |
    |               |         |              |   created by this user or |
    |               |         |              |   not. Defaults to True   |
    +---------------+---------+--------------+---------------------------+

    Sample response
    ^^^^^^^^^^^^^^^

    ::

        {
          "args": {
            "assignee": true,
            "author": true,
            "milestones": [],
            "no_stones": null,
            "order": null,
            "order_key": null,
            "page": 1,
            "since": null,
            "status": null,
            "tags": []
          },
          "issues_assigned": [
            {
              "assignee": {
                "fullname": "Anar Adilova",
                "name": "anar"
              },
              "blocks": [],
              "close_status": null,
              "closed_at": null,
              "comments": [],
              "content": "Test Issue",
              "custom_fields": [],
              "date_created": "1510124763",
              "depends": [],
              "id": 2,
              "last_updated": "1510124763",
              "milestone": null,
              "priority": null,
              "private": false,
              "status": "Open",
              "tags": [],
              "title": "issue4",
              "user": {
                "fullname": "Anar Adilova",
                "name": "anar"
              }
            }
          ],
          "issues_created": [
            {
              "assignee": {
                "fullname": "Anar Adilova",
                "name": "anar"
              },
              "blocks": [],
              "close_status": null,
              "closed_at": null,
              "comments": [],
              "content": "Test Issue",
              "custom_fields": [],
              "date_created": "1510124763",
              "depends": [],
              "id": 2,
              "last_updated": "1510124763",
              "milestone": null,
              "priority": null,
              "private": false,
              "status": "Open",
              "tags": [],
              "title": "issue4",
              "user": {
                "fullname": "Anar Adilova",
                "name": "anar"
              }
            }
          ],
          "pagination_issues_assigned": {
            "first": "http://localhost:5000/api/0/user/anar/issues?per_page=1&page=1",
            "last": "http://localhost:5000/api/0/user/anar/issues?per_page=1&page=0",
            "next": null,
            "page": 1,
            "pages": 0,
            "per_page": 1,
            "prev": null
          },
          "pagination_issues_created": {
            "first": "http://localhost:5000/api/0/user/anar/issues?per_page=1&page=1",
            "last": "http://localhost:5000/api/0/user/anar/issues?per_page=1&page=200",
            "next": "http://localhost:5000/api/0/user/anar/issues?per_page=1&page=2",
            "page": 1,
            "pages": 200,
            "per_page": 1,
            "prev": null
          },
          "total_issues_assigned": 1,
          "total_issues_created": 1
        }


    """  # noqa
    milestone = flask.request.args.getlist("milestones", None)
    no_stones = flask.request.args.get("no_stones", None)
    if no_stones is not None:
        no_stones = is_true(no_stones)
    since = flask.request.args.get("since", None)
    order = flask.request.args.get("order", None)
    order_key = flask.request.args.get("order_key", None)
    status = flask.request.args.get("status", None)
    tags = flask.request.args.getlist("tags")
    tags = [tag.strip() for tag in tags if tag.strip()]

    page = get_page()
    per_page = get_per_page()

    assignee = flask.request.args.get("assignee", "").lower() not in [
        "false",
        "0",
        "f",
    ]
    author = flask.request.args.get("author", "").lower() not in [
        "false",
        "0",
        "f",
    ]

    offset = (page - 1) * per_page
    limit = per_page

    params = {
        "session": flask.g.session,
        "tags": tags,
        "milestones": milestone,
        "order": order,
        "order_key": order_key,
        "no_milestones": no_stones,
        "offset": offset,
        "limit": limit,
    }

    if status is not None:
        if status.lower() == "all":
            params.update({"status": None})
        elif status.lower() == "closed":
            params.update({"closed": True})
        else:
            params.update({"status": status})
    else:
        params.update({"status": "Open"})

    updated_after = None
    if since:
        # Validate and convert the time
        if since.isdigit():
            # We assume its a timestamp, so convert it to datetime
            try:
                updated_after = datetime.datetime.fromtimestamp(int(since))
            except ValueError:
                raise pagure.exceptions.APIError(
                    400, error_code=APIERROR.ETIMESTAMP)
        else:
            # We assume datetime format, so validate it
            try:
                updated_after = datetime.datetime.strptime(since, "%Y-%m-%d")
            except ValueError:
                raise pagure.exceptions.APIError(400,
                                                 error_code=APIERROR.EDATETIME)

    params.update({"updated_after": updated_after})

    issues_created = []
    issues_created_pages = 1
    issues_created_cnt = 0
    pagination_issues_created = None
    if author:
        # Issues authored by this user
        params_created = params.copy()
        params_created.update({"author": username})
        issues_created = pagure.lib.query.search_issues(**params_created)
        params_created.update({"offset": None, "limit": None, "count": True})
        issues_created_cnt = pagure.lib.query.search_issues(**params_created)
        pagination_issues_created = pagure.lib.query.get_pagination_metadata(
            flask.request, page, per_page, issues_created_cnt)

    issues_assigned = []
    issues_assigned_pages = 1
    issues_assigned_cnt = 0
    pagination_issues_assigned = None
    if assignee:
        # Issues assigned to this user
        params_assigned = params.copy()
        params_assigned.update({"assignee": username})
        issues_assigned = pagure.lib.query.search_issues(**params_assigned)
        params_assigned.update({"offset": None, "limit": None, "count": True})
        issues_assigned_cnt = pagure.lib.query.search_issues(**params_assigned)
        pagination_issues_assigned = pagure.lib.query.get_pagination_metadata(
            flask.request, page, per_page, issues_assigned_cnt)

    jsonout = flask.jsonify({
        "pagination_issues_created":
        pagination_issues_created,
        "pagination_issues_assigned":
        pagination_issues_assigned,
        "total_issues_created_pages":
        issues_created_pages,
        "total_issues_assigned_pages":
        issues_assigned_pages,
        "total_issues_created":
        issues_created_cnt,
        "total_issues_assigned":
        issues_assigned_cnt,
        "issues_created": [
            issue.to_json(public=True, with_project=True)
            for issue in issues_created
        ],
        "issues_assigned": [
            issue.to_json(public=True, with_project=True)
            for issue in issues_assigned
        ],
        "args": {
            "milestones": milestone,
            "no_stones": no_stones,
            "order": order,
            "order_key": order_key,
            "since": since,
            "status": status,
            "tags": tags,
            "page": page,
            "assignee": assignee,
            "author": author,
        },
    })
    return jsonout
コード例 #11
0
ファイル: filters.py プロジェクト: pypingou/pagure
def format_loc(
    loc,
    commit=None,
    filename=None,
    tree_id=None,
    prequest=None,
    index=None,
    isprdiff=False,
):
    """ Template filter putting the provided lines of code into a table
    """
    if loc is None:
        return

    output = ['<div class="highlight">', '<table class="code_table">']

    commit_hash = commit
    if hasattr(commit_hash, "hex"):
        commit_hash = commit_hash.hex

    comments = {}
    if prequest and not isinstance(prequest, flask.wrappers.Request):
        for com in prequest.comments:
            if (
                commit
                and com.commit_id == commit_hash
                and com.filename == filename
            ):
                if com.line in comments:
                    comments[com.line].append(com)
                else:
                    comments[com.line] = [com]
    for key in comments:
        comments[key] = sorted(comments[key], key=lambda obj: obj.date_created)

    if not index:
        index = ""

    cnt = 1
    for line in loc.split("\n"):
        if filename and commit:
            if isinstance(filename, str) and six.PY2:
                filename = filename.decode("UTF-8")

            if isprdiff and (
                line.startswith("@@")
                or line.startswith("+")
                or line.startswith("-")
            ):
                if line.startswith("@@"):
                    output.append(
                        '<tr class="stretch-table-column bg-light"\
                    id="c-%(commit)s-%(cnt_lbl)s">'
                        % ({"cnt_lbl": cnt, "commit": commit})
                    )
                elif line.startswith("+"):
                    output.append(
                        '<tr class="stretch-table-column alert-success" \
                    id="c-%(commit)s-%(cnt_lbl)s">'
                        % ({"cnt_lbl": cnt, "commit": commit})
                    )
                elif line.startswith("-"):
                    output.append(
                        '<tr class="stretch-table-column alert-danger" \
                    id="c-%(commit)s-%(cnt_lbl)s">'
                        % ({"cnt_lbl": cnt, "commit": commit})
                    )
            else:
                output.append(
                    '<tr id="c-%(commit)s-%(cnt_lbl)s">'
                    % ({"cnt_lbl": cnt, "commit": commit})
                )

            output.append(
                '<td class="cell1">'
                '<a id="%(cnt)s" href="#%(cnt)s" data-line-number='
                '"%(cnt_lbl)s" data-file-number='
                '"%(line)s"></a></td>'
                '<td class="prc border-right" data-row="%(cnt_lbl)s"'
                ' data-filename="%(filename)s" data-commit="%(commit)s"'
                ' data-tree="%(tree_id)s">'
                "<p>"
                '<span class="fa fa-comment prc_img" style="display: none;"'
                'alt="Add comment" title="Add comment"></span>'
                "</p>"
                "</td>"
                % (
                    {
                        "cnt": "_%s__%s" % (index, cnt),
                        "cnt_lbl": cnt,
                        "line": index,
                        "filename": filename,
                        "commit": commit,
                        "tree_id": tree_id,
                    }
                )
            )
        else:
            output.append(
                '<tr><td class="cell1">'
                '<a id="%(cnt)s" href="#%(cnt)s" data-line-number='
                '"%(cnt_lbl)s"></a></td>'
                % ({"cnt": "%s_%s" % (index, cnt), "cnt_lbl": cnt})
            )

        cnt += 1
        if not line:
            output.append(line)
            continue
        if line.startswith("@@"):
            if prequest and prequest.project_from:
                rangeline = (
                    line.partition("@@ ")[2]
                    if line.partition("@@ ")[1] == "@@ "
                    else None
                )
                if rangeline:
                    rangeline = rangeline.split(" @@")[0]
                    linenumber = rangeline.split("+")[1].split(",")[0]
                    line = line + '&nbsp;<a href="%s#_%s" target="_blank" ' % (
                        flask.url_for(
                            "ui_ns.view_file",
                            repo=prequest.project_from.name,
                            username=prequest.project_from.user.username
                            if prequest.project_from.is_fork
                            else None,
                            namespace=prequest.project_from.namespace,
                            identifier=prequest.branch_from,
                            filename=filename,
                        ),
                        linenumber,
                    )
                    line = (
                        line
                        + 'class="open_changed_file_icon_wrap">'
                        + '<span class="fa fa-file-code-o fa-fw" '
                        + 'alt="Open changed file" '
                        + 'title="Open changed file"></span></a>'
                    )

        if isprdiff and (
            line.startswith("@@")
            or line.startswith("+")
            or line.startswith("-")
        ):
            if line.startswith("@@"):
                output.append(
                    '<td class="cell2 stretch-table-column">\
                    <pre class="text-muted"><code>%s</code></pre></td>'
                    % line
                )
            elif line.startswith("+"):
                output.append(
                    '<td class="cell2 stretch-table-column">\
                    <pre class="alert-success"><code>%s</code></pre></td>'
                    % escape(line)
                )
            elif line.startswith("-"):
                output.append(
                    '<td class="cell2 stretch-table-column">\
                    <pre class="alert-danger"><code>%s</code></pre></td>'
                    % escape(line)
                )
        else:
            output.append(
                '<td class="cell2"><pre><code>%s</code></pre></td>'
                % (escape(line))
            )

        output.append("</tr>")

        tpl_edit = (
            '<a href="%(edit_url)s" '
            'class="btn btn-outline-primary border-0" '
            'data-comment="%(commentid)s" '
            'data-objid="%(requestid)s">'
            '<i class="fa fa-pencil"></i>'
            "</a>"
        )
        tpl_edited = (
            '<small class="text-muted" title="%(edit_date)s"> '
            "Edited %(human_edit_date)s by %(user)s </small>"
        )

        tpl_delete = (
            '<button class="btn btn-outline-primary border-0" '
            'title="Remove comment" '
            'name="drop_comment" value="%(commentid)s" type="submit" '
            "onclick=\"return confirm('Do you really want to remove this"
            ' comment?\');" ><i class="fa fa-trash"></i>'
            "</button>"
        )

        if cnt - 1 in comments:
            for comment in comments[cnt - 1]:

                templ_delete = ""
                templ_edit = ""
                templ_edited = ""
                if authenticated() and (
                    (
                        is_true(comment.parent.status, ["true", "open"])
                        and comment.user.user == flask.g.fas_user.username
                    )
                    or is_repo_committer(comment.parent.project)
                ):
                    templ_delete = tpl_delete % ({"commentid": comment.id})
                    templ_edit = tpl_edit % (
                        {
                            "edit_url": flask.url_for(
                                "ui_ns.pull_request_edit_comment",
                                repo=comment.parent.project.name,
                                namespace=comment.parent.project.namespace,
                                requestid=comment.parent.id,
                                commentid=comment.id,
                                username=comment.parent.user.user
                                if comment.parent.project.is_fork
                                else None,
                            ),
                            "requestid": comment.parent.id,
                            "commentid": comment.id,
                        }
                    )

                if comment.edited_on:
                    templ_edited = tpl_edited % (
                        {
                            "edit_date": format_ts(comment.edited_on),
                            "human_edit_date": humanize_date(
                                comment.edited_on
                            ),
                            "user": comment.editor.user,
                        }
                    )

                output.append(
                    '<tr class="inline-pr-comment">'
                    '<td colspan="3" class="p-3 border">'
                    '<div class="card clearfix">'
                    '<div class="card-header bg-light d-flex '
                    'align-items-center px-3 py-2">'
                    "<div>"
                    '<div id="comment-%(commentid)s">'
                    '<img class="avatar circle" src="%(avatar_url)s"/>'
                    '<a href="%(url)s" title="%(user_html)s">'
                    "%(user)s</a> commented "
                    '<a class="headerlink" title="Permalink '
                    'to this headline" href="#comment-%(commentid)s">'
                    '<span title="%(date)s">%(human_date)s</span>'
                    "</a></div>"
                    "</div>"
                    '<div class="mr-auto">'
                    "%(templ_edit)s"
                    "%(templ_delete)s"
                    "</div>"
                    "</div>"
                    '<div class="card-block">'
                    "<small></small>"
                    '<section class="issue_comment">'
                    '<div class="comment_body">'
                    "%(comment)s"
                    "</div>"
                    "</section>"
                    "</div></div>"
                    "</td></tr>"
                    % (
                        {
                            "url": flask.url_for(
                                "ui_ns.view_user", username=comment.user.user
                            ),
                            "templ_delete": templ_delete,
                            "templ_edit": templ_edit,
                            "templ_edited": templ_edited,
                            "user": comment.user.user,
                            "user_html": comment.user.html_title,
                            "avatar_url": avatar_url(
                                comment.user.default_email, 16
                            ),
                            "date": format_ts(comment.date_created),
                            "human_date": humanize_date(comment.date_created),
                            "comment": markdown_filter(comment.comment),
                            "commentid": comment.id,
                        }
                    )
                )

    output.append("</table></div>")

    return "\n".join(output)
コード例 #12
0
ファイル: app.py プロジェクト: pypingou/pagure_mirror
def view_projects(pattern=None, namespace=None):
    """ Present the list of projects.
    """
    forks = flask.request.args.get("forks")
    page = flask.request.args.get("page", 1)

    try:
        page = int(page)
        if page < 1:
            page = 1
    except ValueError:
        page = 1

    select = "projects"
    # If forks is specified, we want both forks and projects
    if is_true(forks):
        forks = None
        select = "projects_forks"
    else:
        forks = False
    private = False

    if authenticated():
        private = flask.g.fas_user.username

    limit = pagure_config["ITEM_PER_PAGE"]
    start = limit * (page - 1)

    projects = pagure.lib.query.search_projects(
        flask.g.session,
        pattern=pattern,
        namespace=namespace,
        fork=forks,
        start=start,
        limit=limit,
        private=private,
    )

    if len(projects) == 1:
        flask.flash("Only one result found, redirecting you to it")
        return flask.redirect(
            flask.url_for(
                "ui_ns.view_repo",
                repo=projects[0].name,
                namespace=projects[0].namespace,
                username=projects[0].user.username
                if projects[0].is_fork
                else None,
            )
        )

    projects_length = pagure.lib.query.search_projects(
        flask.g.session,
        pattern=pattern,
        namespace=namespace,
        fork=forks,
        count=True,
        private=private,
    )

    total_page = int(ceil(projects_length / float(limit)))

    if namespace in pagure_config["ALLOWED_PREFIX"]:
        namespace = None

    return flask.render_template(
        "index.html",
        namespace=namespace,
        repos=projects,
        repos_length=projects_length,
        total_page=total_page,
        page=page,
        select=select,
    )
コード例 #13
0
ファイル: filters.py プロジェクト: sandhyablue/pagure
def format_loc(
    loc,
    commit=None,
    filename=None,
    tree_id=None,
    prequest=None,
    index=None,
    isprdiff=False,
):
    """ Template filter putting the provided lines of code into a table
    """
    if loc is None:
        return

    output = ['<div class="highlight">', '<table class="code_table">']

    commit_hash = commit
    if hasattr(commit_hash, "hex"):
        commit_hash = commit_hash.hex

    comments = {}
    if prequest and not isinstance(prequest, flask.wrappers.Request):
        for com in prequest.comments:
            if (commit and com.commit_id == commit_hash
                    and com.filename == filename):
                if com.line in comments:
                    comments[com.line].append(com)
                else:
                    comments[com.line] = [com]
    for key in comments:
        comments[key] = sorted(comments[key], key=lambda obj: obj.date_created)

    if not index:
        index = ""

    cnt = 1
    for line in loc.split("\n"):
        if filename and commit:
            if isinstance(filename, str) and six.PY2:
                filename = filename.decode("UTF-8")

            if isprdiff and (line.startswith("@@") or line.startswith("+")
                             or line.startswith("-")):
                if line.startswith("@@"):
                    output.append('<tr class="stretch-table-column bg-light"\
                    id="c-%(commit)s-%(cnt_lbl)s">' % ({
                        "cnt_lbl": cnt,
                        "commit": commit
                    }))
                elif line.startswith("+"):
                    output.append(
                        '<tr class="stretch-table-column alert-success" \
                    id="c-%(commit)s-%(cnt_lbl)s">' % ({
                            "cnt_lbl": cnt,
                            "commit": commit
                        }))
                elif line.startswith("-"):
                    output.append(
                        '<tr class="stretch-table-column alert-danger" \
                    id="c-%(commit)s-%(cnt_lbl)s">' % ({
                            "cnt_lbl": cnt,
                            "commit": commit
                        }))
            else:
                output.append('<tr id="c-%(commit)s-%(cnt_lbl)s">' %
                              ({
                                  "cnt_lbl": cnt,
                                  "commit": commit
                              }))

            output.append(
                '<td class="cell1">'
                '<a id="%(cnt)s" href="#%(cnt)s" data-line-number='
                '"%(cnt_lbl)s" data-file-number='
                '"%(line)s"></a></td>'
                '<td class="prc border-right" data-row="%(cnt_lbl)s"'
                ' data-filename="%(filename)s" data-commit="%(commit)s"'
                ' data-tree="%(tree_id)s">'
                "<p>"
                '<span class="fa fa-comment prc_img" style="display: none;"'
                'alt="Add comment" title="Add comment"></span>'
                "</p>"
                "</td>" % ({
                    "cnt": "_%s__%s" % (index, cnt),
                    "cnt_lbl": cnt,
                    "line": index,
                    "filename": filename,
                    "commit": commit,
                    "tree_id": tree_id,
                }))
        else:
            output.append('<tr><td class="cell1">'
                          '<a id="%(cnt)s" href="#%(cnt)s" data-line-number='
                          '"%(cnt_lbl)s"></a></td>' %
                          ({
                              "cnt": "%s_%s" % (index, cnt),
                              "cnt_lbl": cnt
                          }))

        cnt += 1
        if not line:
            output.append(line)
            continue
        if line.startswith("@@"):
            if prequest and prequest.project_from:
                rangeline = (line.partition("@@ ")[2]
                             if line.partition("@@ ")[1] == "@@ " else None)
                if rangeline:
                    rangeline = rangeline.split(" @@")[0]
                    linenumber = rangeline.split("+")[1].split(",")[0]
                    line = line + '&nbsp;<a href="%s#_%s" target="_blank" ' % (
                        flask.url_for(
                            "ui_ns.view_file",
                            repo=prequest.project_from.name,
                            username=prequest.project_from.user.username
                            if prequest.project_from.is_fork else None,
                            namespace=prequest.project_from.namespace,
                            identifier=prequest.branch_from,
                            filename=filename,
                        ),
                        linenumber,
                    )
                    line = (line + 'class="open_changed_file_icon_wrap">' +
                            '<span class="fa fa-file-code-o fa-fw" ' +
                            'alt="Open changed file" ' +
                            'title="Open changed file"></span></a>')

        if isprdiff and (line.startswith("@@") or line.startswith("+")
                         or line.startswith("-")):
            if line.startswith("@@"):
                output.append('<td class="cell2 stretch-table-column">\
                    <pre class="text-muted"><code>%s</code></pre></td>' % line)
            elif line.startswith("+"):
                output.append('<td class="cell2 stretch-table-column">\
                    <pre class="alert-success"><code>%s</code></pre></td>' %
                              escape(line))
            elif line.startswith("-"):
                output.append('<td class="cell2 stretch-table-column">\
                    <pre class="alert-danger"><code>%s</code></pre></td>' %
                              escape(line))
        else:
            output.append('<td class="cell2"><pre><code>%s</code></pre></td>' %
                          (escape(line)))

        output.append("</tr>")

        tpl_edit = ('<a href="%(edit_url)s" '
                    'class="btn btn-outline-primary border-0" '
                    'data-comment="%(commentid)s" '
                    'data-objid="%(requestid)s">'
                    '<i class="fa fa-pencil"></i>'
                    "</a>")
        tpl_edited = ('<small class="text-muted" title="%(edit_date)s"> '
                      "Edited %(human_edit_date)s by %(user)s </small>")

        tpl_delete = (
            '<button class="btn btn-outline-primary border-0" '
            'title="Remove comment" '
            'name="drop_comment" value="%(commentid)s" type="submit" '
            "onclick=\"return confirm('Do you really want to remove this"
            ' comment?\');" ><i class="fa fa-trash"></i>'
            "</button>")

        if cnt - 1 in comments:
            for comment in comments[cnt - 1]:

                templ_delete = ""
                templ_edit = ""
                templ_edited = ""
                if authenticated() and (
                    (is_true(comment.parent.status, ["true", "open"])
                     and comment.user.user == flask.g.fas_user.username)
                        or is_repo_committer(comment.parent.project)):
                    templ_delete = tpl_delete % ({"commentid": comment.id})
                    templ_edit = tpl_edit % ({
                        "edit_url":
                        flask.url_for(
                            "ui_ns.pull_request_edit_comment",
                            repo=comment.parent.project.name,
                            requestid=comment.parent.id,
                            commentid=comment.id,
                            username=comment.parent.user.user
                            if comment.parent.project.is_fork else None,
                        ),
                        "requestid":
                        comment.parent.id,
                        "commentid":
                        comment.id,
                    })

                if comment.edited_on:
                    templ_edited = tpl_edited % (
                        {
                            "edit_date": format_ts(comment.edited_on),
                            "human_edit_date": humanize_date(
                                comment.edited_on),
                            "user": comment.editor.user,
                        })

                output.append(
                    '<tr class="inline-pr-comment">'
                    '<td colspan="3" class="p-3 border">'
                    '<div class="card clearfix">'
                    '<div class="card-header bg-light d-flex '
                    'align-items-center px-3 py-2">'
                    "<div>"
                    '<div id="comment-%(commentid)s">'
                    '<img class="avatar circle" src="%(avatar_url)s"/>'
                    '<a href="%(url)s" title="%(user_html)s">'
                    "%(user)s</a> commented "
                    '<a class="headerlink" title="Permalink '
                    'to this headline" href="#comment-%(commentid)s">'
                    '<span title="%(date)s">%(human_date)s</span>'
                    "</a></div>"
                    "</div>"
                    '<div class="mr-auto">'
                    "%(templ_edit)s"
                    "%(templ_delete)s"
                    "</div>"
                    "</div>"
                    '<div class="card-block">'
                    "<small></small>"
                    '<section class="issue_comment">'
                    '<div class="comment_body">'
                    "%(comment)s"
                    "</div>"
                    "</section>"
                    "</div></div>"
                    "</td></tr>" % ({
                        "url":
                        flask.url_for("ui_ns.view_user",
                                      username=comment.user.user),
                        "templ_delete":
                        templ_delete,
                        "templ_edit":
                        templ_edit,
                        "templ_edited":
                        templ_edited,
                        "user":
                        comment.user.user,
                        "user_html":
                        comment.user.html_title,
                        "avatar_url":
                        avatar_url(comment.user.default_email, 16),
                        "date":
                        format_ts(comment.date_created),
                        "human_date":
                        humanize_date(comment.date_created),
                        "comment":
                        markdown_filter(comment.comment),
                        "commentid":
                        comment.id,
                    }))

    output.append("</table></div>")

    return "\n".join(output)
コード例 #14
0
ファイル: issue.py プロジェクト: bscc/pagure
def api_new_issue(repo, username=None, namespace=None):
    """
    Create a new issue
    ------------------
    Open a new issue on a project.

    ::

        POST /api/0/<repo>/new_issue
        POST /api/0/<namespace>/<repo>/new_issue

    ::

        POST /api/0/fork/<username>/<repo>/new_issue
        POST /api/0/fork/<username>/<namespace>/<repo>/new_issue

    Input
    ^^^^^

    +-------------------+--------+-------------+---------------------------+
    | Key               | Type   | Optionality | Description               |
    +===================+========+=============+===========================+
    | ``title``         | string | Mandatory   | The title of the issue    |
    +-------------------+--------+-------------+---------------------------+
    | ``issue_content`` | string | Mandatory   | | The description of the  |
    |                   |        |             |   issue                   |
    +-------------------+--------+-------------+---------------------------+
    | ``private``       | boolean| Optional    | | Include this key if     |
    |                   |        |             |   you want a private issue|
    |                   |        |             |   to be created           |
    +-------------------+--------+-------------+---------------------------+
    | ``priority``      | string | Optional    | | The priority to set to  |
    |                   |        |             |   this ticket from the    |
    |                   |        |             |   list of priorities set  |
    |                   |        |             |   in the project          |
    +-------------------+--------+-------------+---------------------------+
    | ``milestone``     | string | Optional    | | The milestone to assign |
    |                   |        |             |   to this ticket from the |
    |                   |        |             |   list of milestones set  |
    |                   |        |             |   in the project          |
    +-------------------+--------+-------------+---------------------------+
    | ``tag``           | string | Optional    | | Comma separated list of |
    |                   |        |             |   tags to link to this    |
    |                   |        |             |   ticket from the list of |
    |                   |        |             |   tags in the project     |
    +-------------------+--------+-------------+---------------------------+
    | ``assignee``      | string | Optional    | | The username of the user|
    |                   |        |             |   to assign this ticket to|
    +-------------------+--------+-------------+---------------------------+

    Sample response
    ^^^^^^^^^^^^^^^

    ::

        {
          "issue": {
            "assignee": null,
            "blocks": [],
            "close_status": null,
            "closed_at": null,
            "closed_by": null,
            "comments": [],
            "content": "This issue needs attention",
            "custom_fields": [],
            "date_created": "1479458613",
            "depends": [],
            "id": 1,
            "milestone": null,
            "priority": null,
            "private": false,
            "status": "Open",
            "tags": [],
            "title": "test issue",
            "user": {
              "fullname": "PY C",
              "name": "pingou"
            }
          },
          "message": "Issue created"
        }

    """
    output = {}
    repo = _get_repo(repo, username, namespace)
    _check_issue_tracker(repo)
    _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)

    form = pagure.forms.IssueFormSimplied(
        priorities=repo.priorities,
        milestones=repo.milestones,
        csrf_enabled=False,
    )
    if form.validate_on_submit():
        title = form.title.data
        content = form.issue_content.data
        milestone = form.milestone.data or None
        private = is_true(form.private.data)
        priority = form.priority.data or None
        assignee = get_request_data().get("assignee", "").strip() or None
        tags = [
            tag.strip() for tag in get_request_data().get("tag", "").split(",")
            if tag.strip()
        ]

        try:
            issue = pagure.lib.query.new_issue(
                flask.g.session,
                repo=repo,
                title=title,
                content=content,
                private=private,
                assignee=assignee,
                milestone=milestone,
                priority=priority,
                tags=tags,
                user=flask.g.fas_user.username,
            )
            flask.g.session.flush()
            # If there is a file attached, attach it.
            filestream = flask.request.files.get("filestream")
            if filestream and "<!!image>" in issue.content:
                new_filename = pagure.lib.query.add_attachment(
                    repo=repo,
                    issue=issue,
                    attachmentfolder=pagure_config["ATTACHMENTS_FOLDER"],
                    user=user_obj,
                    filename=filestream.filename,
                    filestream=filestream.stream,
                )
                # Replace the <!!image> tag in the comment with the link
                # to the actual image
                filelocation = flask.url_for(
                    "ui_ns.view_issue_raw_file",
                    repo=repo.name,
                    username=username,
                    filename="files/%s" % new_filename,
                )
                new_filename = new_filename.split("-", 1)[1]
                url = "[![%s](%s)](%s)" % (
                    new_filename,
                    filelocation,
                    filelocation,
                )
                issue.content = issue.content.replace("<!!image>", url)
                flask.g.session.add(issue)
                flask.g.session.flush()

            flask.g.session.commit()
            output["message"] = "Issue created"
            output["issue"] = issue.to_json(public=True)
        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)

    jsonout = flask.jsonify(output)
    return jsonout
コード例 #15
0
ファイル: issue.py プロジェクト: bscc/pagure
def api_view_issue(repo, issueid, username=None, namespace=None):
    """
    Issue information
    -----------------
    Retrieve information of a specific issue.

    ::

        GET /api/0/<repo>/issue/<issue id>
        GET /api/0/<namespace>/<repo>/issue/<issue id>

    ::

        GET /api/0/fork/<username>/<repo>/issue/<issue id>
        GET /api/0/fork/<username>/<namespace>/<repo>/issue/<issue id>

    The identifier provided can be either the unique identifier or the
    regular identifier used in the UI (for example ``24`` in
    ``/forks/user/test/issue/24``)

    Sample response
    ^^^^^^^^^^^^^^^

    ::

        {
          "assignee": null,
          "blocks": [],
          "comments": [],
          "content": "This issue needs attention",
          "date_created": "1431414800",
          "depends": ["4"],
          "id": 1,
          "private": false,
          "status": "Open",
          "tags": [],
          "title": "test issue",
          "user": {
            "fullname": "PY C",
            "name": "pingou"
          }
        }

    """
    comments = is_true(flask.request.args.get("comments", True))

    repo = _get_repo(repo, username, namespace)
    _check_issue_tracker(repo)
    _check_token(repo)

    issue_id = issue_uid = None
    try:
        issue_id = int(issueid)
    except (ValueError, TypeError):
        issue_uid = issueid

    issue = _get_issue(repo, issue_id, issueuid=issue_uid)
    _check_private_issue_access(issue)

    jsonout = flask.jsonify(issue.to_json(public=True, with_comments=comments))
    return jsonout
コード例 #16
0
ファイル: issue.py プロジェクト: bscc/pagure
def api_view_issues(repo, username=None, namespace=None):
    """
    List project's issues
    ---------------------
    List issues of a project.

    ::

        GET /api/0/<repo>/issues
        GET /api/0/<namespace>/<repo>/issues

    ::

        GET /api/0/fork/<username>/<repo>/issues
        GET /api/0/fork/<username>/<namespace>/<repo>/issues

    Parameters
    ^^^^^^^^^^

    +---------------+---------+--------------+---------------------------+
    | Key           | Type    | Optionality  | Description               |
    +===============+=========+==============+===========================+
    | ``status``    | string  | Optional     | | Filters the status of   |
    |               |         |              |   issues. Fetches all the |
    |               |         |              |   issues if status is     |
    |               |         |              |   ``all``. Default:       |
    |               |         |              |   ``Open``                |
    +---------------+---------+--------------+---------------------------+
    | ``tags``      | string  | Optional     | | A list of tags you      |
    |               |         |              |   wish to filter. If      |
    |               |         |              |   you want to filter      |
    |               |         |              |   for issues not having   |
    |               |         |              |   a tag, add an           |
    |               |         |              |   exclamation mark in     |
    |               |         |              |   front of it             |
    +---------------+---------+--------------+---------------------------+
    | ``assignee``  | string  | Optional     | | Filter the issues       |
    |               |         |              |   by assignee             |
    +---------------+---------+--------------+---------------------------+
    | ``author``    | string  | Optional     | | Filter the issues       |
    |               |         |              |   by creator              |
    +---------------+---------+--------------+---------------------------+
    | ``milestones``| list of | Optional     | | Filter the issues       |
    |               | strings |              |   by milestone            |
    +---------------+---------+--------------+---------------------------+
    | ``priority``  | string  | Optional     | | Filter the issues       |
    |               |         |              |   by priority             |
    +---------------+---------+--------------+---------------------------+
    | ``no_stones`` | boolean | Optional     | | If true returns only the|
    |               |         |              |   issues having no        |
    |               |         |              |   milestone, if false     |
    |               |         |              |   returns only the issues |
    |               |         |              |   having a milestone      |
    +---------------+---------+--------------+---------------------------+
    | ``since``     | string  | Optional     | | Filter the issues       |
    |               |         |              |   updated after this date.|
    |               |         |              |   The date can either be  |
    |               |         |              |   provided as an unix date|
    |               |         |              |   or in the format Y-M-D  |
    +---------------+---------+--------------+---------------------------+
    | ``order``     | string  | Optional     | | Set the ordering of the |
    |               |         |              |   issues. This can be     |
    |               |         |              |   ``asc`` or ``desc``.    |
    |               |         |              |   Default: ``desc``       |
    +---------------+---------+--------------+---------------------------+
    | ``page``      | int      | Optional    | | Specifies which         |
    |               |          |             |   page to return          |
    |               |          |             |   (defaults to: 1)        |
    +---------------+----------+-------------+---------------------------+
    | ``per_page``  | int      | Optional    | | The number of projects  |
    |               |          |             |   to return per page.     |
    |               |          |             |   The maximum is 100.     |
    +---------------+----------+-------------+---------------------------+

    Sample response
    ^^^^^^^^^^^^^^^

    ::

        {
          "args": {
            "assignee": null,
            "author": null,
            'milestones': [],
            'no_stones': null,
            'order': null,
            'priority': null,
            "since": null,
            "status": "Closed",
            "tags": [
              "0.1"
            ]
          },
          "total_issues": 1,
          "issues": [
            {
              "assignee": null,
              "blocks": ["1"],
              "close_status": null,
              "closed_at": null,
              "closed_by": null,
              "comments": [],
              "content": "asd",
              "custom_fields": [],
              "date_created": "1427442217",
              "depends": [],
              "id": 4,
              "last_updated": "1533815358",
              "milestone": null,
              "priority": null,
              "private": false,
              "status": "Fixed",
              "tags": [
                "0.1"
              ],
              "title": "bug",
              "user": {
                "fullname": "PY.C",
                "name": "pingou"
              }
            }
          ],
          'pagination': {
            'first': 'http://localhost/api/0/test/issues?per_page=20&page=1',
            'last': 'http://localhost/api/0/test/issues?per_page=20&page=1',
            'next': null,
            'page': 1,
            'pages': 1,
            'per_page': 20,
            'prev': null
          },
        }

    """
    repo = _get_repo(repo, username, namespace)
    _check_issue_tracker(repo)
    _check_token(repo, project_token=False)

    assignee = flask.request.args.get("assignee", None)
    author = flask.request.args.get("author", None)
    milestone = flask.request.args.getlist("milestones", None)
    no_stones = flask.request.args.get("no_stones", None)
    if no_stones is not None:
        no_stones = is_true(no_stones)
    priority = flask.request.args.get("priority", None)
    since = flask.request.args.get("since", None)
    order = flask.request.args.get("order", None)
    status = flask.request.args.get("status", None)
    tags = flask.request.args.getlist("tags")
    tags = [tag.strip() for tag in tags if tag.strip()]
    search_id = flask.request.args.get("query_id", None)

    priority_key = None
    if priority:
        found = False
        if priority in repo.priorities:
            found = True
            priority_key = int(priority)
        else:
            for key, val in repo.priorities.items():
                if val.lower() == priority.lower():
                    priority_key = key
                    found = True
                    break

        if not found:
            raise pagure.exceptions.APIError(
                400, error_code=APIERROR.EINVALIDPRIORITY)

    # Hide private tickets
    private = False
    # If user is authenticated, show him/her his/her private tickets
    if api_authenticated():
        private = flask.g.fas_user.username
    # If user is repo committer, show all tickets included the private ones
    if is_repo_committer(repo):
        private = None

    params = {
        "session": flask.g.session,
        "repo": repo,
        "tags": tags,
        "assignee": assignee,
        "author": author,
        "private": private,
        "milestones": milestone,
        "priority": priority_key,
        "order": order,
        "no_milestones": no_stones,
        "search_id": search_id,
    }

    if status is not None:
        if status.lower() == "all":
            params.update({"status": None})
        elif status.lower() == "closed":
            params.update({"closed": True})
        else:
            params.update({"status": status})
    else:
        params.update({"status": "Open"})

    updated_after = None
    if since:
        # Validate and convert the time
        if since.isdigit():
            # We assume its a timestamp, so convert it to datetime
            try:
                updated_after = arrow.get(int(since)).datetime
            except ValueError:
                raise pagure.exceptions.APIError(
                    400, error_code=APIERROR.ETIMESTAMP)
        else:
            # We assume datetime format, so validate it
            try:
                updated_after = datetime.datetime.strptime(since, "%Y-%m-%d")
            except ValueError:
                raise pagure.exceptions.APIError(400,
                                                 error_code=APIERROR.EDATETIME)

    params.update({"updated_after": updated_after})

    page = get_page()
    per_page = get_per_page()
    params["count"] = True
    issue_cnt = pagure.lib.query.search_issues(**params)
    pagination_metadata = pagure.lib.query.get_pagination_metadata(
        flask.request, page, per_page, issue_cnt)
    query_start = (page - 1) * per_page
    query_limit = per_page

    params["count"] = False
    params["limit"] = query_limit
    params["offset"] = query_start
    issues = pagure.lib.query.search_issues(**params)

    jsonout = flask.jsonify({
        "total_issues":
        len(issues),
        "issues": [issue.to_json(public=True) for issue in issues],
        "args": {
            "assignee": assignee,
            "author": author,
            "milestones": milestone,
            "no_stones": no_stones,
            "order": order,
            "priority": priority,
            "since": since,
            "status": status,
            "tags": tags,
        },
        "pagination":
        pagination_metadata,
    })
    return jsonout
コード例 #17
0
ファイル: issue.py プロジェクト: bscc/pagure
def api_subscribe_issue(repo, issueid, username=None, namespace=None):
    """
    Subscribe to an issue
    ---------------------
    Allows someone to subscribe to or unsubscribe from the notifications
    related to an issue.

    ::

        POST /api/0/<repo>/issue/<issue id>/subscribe
        POST /api/0/<namespace>/<repo>/issue/<issue id>/subscribe

    ::

        POST /api/0/fork/<username>/<repo>/issue/<issue id>/subscribe
        POST /api/0/fork/<username>/<namespace>/<repo>/issue/<issue id>/subscribe

    Input
    ^^^^^

    +--------------+----------+---------------+---------------------------+
    | Key          | Type     | Optionality   | Description               |
    +==============+==========+===============+===========================+
    | ``status``   | boolean  | Mandatory     | The intended subscription |
    |              |          |               | status. ``true`` for      |
    |              |          |               | subscribing, ``false``    |
    |              |          |               | for unsubscribing.        |
    +--------------+----------+---------------+---------------------------+

    Sample response
    ^^^^^^^^^^^^^^^

    ::

        {
          "message": "User subscribed",
          "avatar_url": "https://image.png",
          "user": "******"
        }

    """  # noqa
    output = {}
    repo = _get_repo(repo, username, namespace)
    _check_issue_tracker(repo)
    _check_token(repo)

    issue = _get_issue(repo, issueid)
    _check_private_issue_access(issue)

    form = pagure.forms.SubscribtionForm(csrf_enabled=False)
    if form.validate_on_submit():
        status = is_true(form.status.data)
        try:
            # Toggle subscribtion
            message = pagure.lib.query.set_watch_obj(
                flask.g.session,
                user=flask.g.fas_user.username,
                obj=issue,
                watch_status=status,
            )
            flask.g.session.commit()
            output["message"] = message
            user_obj = pagure.lib.query.get_user(flask.g.session,
                                                 flask.g.fas_user.username)
            output["avatar_url"] = pagure.lib.query.avatar_url_from_email(
                user_obj.default_email, size=30)
            output["user"] = flask.g.fas_user.username
        except SQLAlchemyError as err:  # pragma: no cover
            flask.g.session.rollback()
            _log.exception(err)
            raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR)

    jsonout = flask.jsonify(output)
    return jsonout
コード例 #18
0
ファイル: group.py プロジェクト: pypingou/pagure
def api_groups():
    """
    List groups
    -----------
    Retrieve groups on this Pagure instance.
    This can then be used as input for autocompletion in some forms/fields.

    ::

        GET /api/0/groups

    Parameters
    ^^^^^^^^^^

    +---------------+----------+---------------+--------------------------+
    | Key           | Type     | Optionality   | Description              |
    +===============+==========+===============+==========================+
    | ``pattern``   | string   | Optional      | | Filters the starting   |
    |               |          |               |   letters of the group   |
    |               |          |               |   names                  |
    +---------------+----------+---------------+--------------------------+
    | ``page``      | int      | Optional      | | Specifies which        |
    |               |          |               |   page to return         |
    |               |          |               |   (defaults to: 1)       |
    +---------------+----------+---------------+--------------------------+
    | ``per_page``  | int      | Optional      | | The number of projects |
    |               |          |               |   to return per page.    |
    |               |          |               |   The maximum is 100.    |
    +---------------+----------+---------------+--------------------------+

    Sample response
    ^^^^^^^^^^^^^^^

    ::

        {
          "total_groups": 2,
          u'pagination': {
            'first': 'http://localhost/api/0/groups?per_page=20&extended=1&page=1',
            'last': 'http://localhost/api/0/groups?per_page=20&extended=1&page=1',
            'next': null,
            'page': 1,
            'pages': 1,
            'per_page': 20,
            'prev': None
          },
          "groups": ["group1", "group2"]
        }

    """  # noqa
    pattern = flask.request.args.get("pattern", None)
    extended = is_true(flask.request.args.get("extended", False))

    if pattern is not None and not pattern.endswith("*"):
        pattern += "*"

    page = get_page()
    per_page = get_per_page()
    group_cnt = pagure.lib.query.search_groups(
        flask.g.session, pattern=pattern, count=True
    )
    pagination_metadata = pagure.lib.query.get_pagination_metadata(
        flask.request, page, per_page, group_cnt
    )
    query_start = (page - 1) * per_page
    query_limit = per_page

    groups = pagure.lib.query.search_groups(
        flask.g.session, pattern=pattern, limit=query_limit, offset=query_start
    )

    if extended:
        groups = [
            {"name": grp.group_name, "description": grp.description}
            for grp in groups
        ]
    else:
        groups = [group.group_name for group in groups]

    return flask.jsonify(
        {
            "total_groups": group_cnt,
            "groups": groups,
            "pagination": pagination_metadata,
        }
    )
コード例 #19
0
ファイル: app.py プロジェクト: pypingou/pagure
def view_projects(pattern=None, namespace=None):
    """ Present the list of projects.
    """
    forks = flask.request.args.get("forks")
    page = flask.request.args.get("page", 1)

    try:
        page = int(page)
        if page < 1:
            page = 1
    except ValueError:
        page = 1

    select = "projects"
    # If forks is specified, we want both forks and projects
    if is_true(forks):
        forks = None
        select = "projects_forks"
    else:
        forks = False
    private = False

    if authenticated():
        private = flask.g.fas_user.username

    limit = pagure_config["ITEM_PER_PAGE"]
    start = limit * (page - 1)

    projects = pagure.lib.query.search_projects(
        flask.g.session,
        pattern=pattern,
        namespace=namespace,
        fork=forks,
        start=start,
        limit=limit,
        private=private,
    )

    if len(projects) == 1:
        flask.flash("Only one result found, redirecting you to it")
        return flask.redirect(
            flask.url_for(
                "ui_ns.view_repo",
                repo=projects[0].name,
                namespace=projects[0].namespace,
                username=projects[0].user.username
                if projects[0].is_fork
                else None,
            )
        )

    projects_length = pagure.lib.query.search_projects(
        flask.g.session,
        pattern=pattern,
        namespace=namespace,
        fork=forks,
        count=True,
        private=private,
    )

    total_page = int(ceil(projects_length / float(limit)))

    if namespace in pagure_config["ALLOWED_PREFIX"]:
        namespace = None

    return flask.render_template(
        "index.html",
        namespace=namespace,
        repos=projects,
        repos_length=projects_length,
        total_page=total_page,
        page=page,
        select=select,
    )
コード例 #20
0
ファイル: fork.py プロジェクト: akanksham3/pagure
def api_subscribe_pull_request(repo, requestid, username=None, namespace=None):
    """
    Subscribe to an pull-request
    ----------------------------
    Allows someone to subscribe to or unsubscribe from the notifications
    related to a pull-request.

    ::

        POST /api/0/<repo>/pull-request/<request id>/subscribe
        POST /api/0/<namespace>/<repo>/pull-request/<request id>/subscribe

    ::

        POST /api/0/fork/<username>/<repo>/pull-request/<request id>/subscribe
        POST /api/0/fork/<username>/<namespace>/<repo>/pull-request/<request id>/subscribe

    Input
    ^^^^^

    +--------------+----------+---------------+---------------------------+
    | Key          | Type     | Optionality   | Description               |
    +==============+==========+===============+===========================+
    | ``status``   | boolean  | Mandatory     | The intended subscription |
    |              |          |               | status. ``true`` for      |
    |              |          |               | subscribing, ``false``    |
    |              |          |               | for unsubscribing.        |
    +--------------+----------+---------------+---------------------------+

    Sample response
    ^^^^^^^^^^^^^^^

    ::

        {
          "message": "User subscribed",
          "avatar_url": "https://image.png",
          "user": "******"
        }

    """  # noqa

    repo = get_authorized_api_project(
        flask.g.session, repo, user=username, namespace=namespace
    )

    output = {}

    if repo is None:
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT)

    if not repo.settings.get("pull_requests", True):
        raise pagure.exceptions.APIError(
            404, error_code=APIERROR.EPULLREQUESTSDISABLED
        )

    if (
        api_authenticated()
        and flask.g.token
        and flask.g.token.project
        and repo != flask.g.token.project
    ) or not authenticated():
        raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK)

    request = pagure.lib.query.search_pull_requests(
        flask.g.session, project_id=repo.id, requestid=requestid
    )

    if not request:
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ)

    form = pagure.forms.SubscribtionForm(csrf_enabled=False)
    if form.validate_on_submit():
        status = is_true(form.status.data)
        try:
            # Toggle subscribtion
            message = pagure.lib.query.set_watch_obj(
                flask.g.session,
                user=flask.g.fas_user.username,
                obj=request,
                watch_status=status,
            )
            flask.g.session.commit()
            output["message"] = message
            user_obj = pagure.lib.query.get_user(
                flask.g.session, flask.g.fas_user.username
            )
            output["avatar_url"] = pagure.lib.query.avatar_url_from_email(
                user_obj.default_email, size=30
            )
            output["user"] = flask.g.fas_user.username
        except SQLAlchemyError as err:  # pragma: no cover
            flask.g.session.rollback()
            _log.logger.exception(err)
            raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR)

    jsonout = flask.jsonify(output)
    return jsonout
コード例 #21
0
def api_groups():
    """
    List groups
    -----------
    Retrieve groups on this Pagure instance.
    This can then be used as input for autocompletion in some forms/fields.

    ::

        GET /api/0/groups

    Parameters
    ^^^^^^^^^^

    +---------------+----------+---------------+--------------------------+
    | Key           | Type     | Optionality   | Description              |
    +===============+==========+===============+==========================+
    | ``pattern``   | string   | Optional      | | Filters the starting   |
    |               |          |               |   letters of the group   |
    |               |          |               |   names                  |
    +---------------+----------+---------------+--------------------------+
    | ``page``      | int      | Optional      | | Specifies which        |
    |               |          |               |   page to return         |
    |               |          |               |   (defaults to: 1)       |
    +---------------+----------+---------------+--------------------------+
    | ``per_page``  | int      | Optional      | | The number of projects |
    |               |          |               |   to return per page.    |
    |               |          |               |   The maximum is 100.    |
    +---------------+----------+---------------+--------------------------+

    Sample response
    ^^^^^^^^^^^^^^^

    ::

        {
          "total_groups": 2,
          u'pagination': {
            'first': 'http://localhost/api/0/groups?per_page=20&extended=1&page=1',
            'last': 'http://localhost/api/0/groups?per_page=20&extended=1&page=1',
            'next': null,
            'page': 1,
            'pages': 1,
            'per_page': 20,
            'prev': None
          },
          "groups": ["group1", "group2"]
        }

    """  # noqa
    pattern = flask.request.args.get("pattern", None)
    extended = is_true(flask.request.args.get("extended", False))

    if pattern is not None and not pattern.endswith("*"):
        pattern += "*"

    page = get_page()
    per_page = get_per_page()
    group_cnt = pagure.lib.query.search_groups(flask.g.session,
                                               pattern=pattern,
                                               count=True)
    pagination_metadata = pagure.lib.query.get_pagination_metadata(
        flask.request, page, per_page, group_cnt)
    query_start = (page - 1) * per_page
    query_limit = per_page

    groups = pagure.lib.query.search_groups(flask.g.session,
                                            pattern=pattern,
                                            limit=query_limit,
                                            offset=query_start)

    if extended:
        groups = [{
            "name": grp.group_name,
            "description": grp.description
        } for grp in groups]
    else:
        groups = [group.group_name for group in groups]

    return flask.jsonify({
        "total_groups": group_cnt,
        "groups": groups,
        "pagination": pagination_metadata,
    })