Exemple #1
0
def api_pull_request_views(repo, username=None, namespace=None):
    """
    List project's Pull-Requests
    ----------------------------
    Retrieve pull requests of a project.

    ::

        GET /api/0/<repo>/pull-requests
        GET /api/0/<namespace>/<repo>/pull-requests

    ::

        GET /api/0/fork/<username>/<repo>/pull-requests
        GET /api/0/fork/<username>/<namespace>/<repo>/pull-requests

    Parameters
    ^^^^^^^^^^

    +---------------+----------+--------------+----------------------------+
    | Key           | Type     | Optionality  | Description                |
    +===============+==========+==============+============================+
    | ``status``    | string   | Optional     | | Filter the status of     |
    |               |          |              |   pull requests. Default:  |
    |               |          |              |   ``True`` (opened pull    |
    |               |          |              |   requests), can be ``0``  |
    |               |          |              |   or ``closed`` for closed |
    |               |          |              |   requests or ``Merged``   |
    |               |          |              |   for merged requests.     |
    |               |          |              |   ``All`` returns closed,  |
    |               |          |              |   merged and open requests.|
    +---------------+----------+--------------+----------------------------+
    | ``assignee``  | string   | Optional     | | Filter the assignee of   |
    |               |          |              |   pull requests            |
    +---------------+----------+--------------+----------------------------+
    | ``author``    | string   | Optional     | | Filter the author of     |
    |               |          |              |   pull requests            |
    +---------------+----------+--------------+----------------------------+

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

    ::

        {
          "args": {
            "assignee": null,
            "author": null,
            "status": true
          },
          "total_requests": 1,
          "requests": [
            {
              "assignee": null,
              "branch": "master",
              "branch_from": "master",
              "closed_at": null,
              "closed_by": null,
              "comments": [],
              "commit_start": null,
              "commit_stop": null,
              "date_created": "1431414800",
              "id": 1,
              "project": {
                "date_created": "1431414800",
                "description": "test project #1",
                "id": 1,
                "name": "test",
                "parent": null,
                "user": {
                  "fullname": "PY C",
                  "name": "pingou"
                }
              },
              "repo_from": {
                "date_created": "1431414800",
                "description": "test project #1",
                "id": 1,
                "name": "test",
                "parent": null,
                "user": {
                  "fullname": "PY C",
                  "name": "pingou"
                }
              },
              "status": "Open",
              "title": "test pull-request",
              "uid": "1431414800",
              "updated_on": "1431414800",
              "user": {
                "fullname": "PY C",
                "name": "pingou"
              }
            }
          ]
        }

    """

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

    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
        )

    status = flask.request.args.get("status", True)
    assignee = flask.request.args.get("assignee", None)
    author = flask.request.args.get("author", None)

    status_text = ("%s" % status).lower()
    requests = []
    if status_text in ["0", "false", "closed"]:
        requests = pagure.lib.query.search_pull_requests(
            flask.g.session,
            project_id=repo.id,
            status=False,
            assignee=assignee,
            author=author,
        )

    elif status_text == "all":
        requests = pagure.lib.query.search_pull_requests(
            flask.g.session,
            project_id=repo.id,
            status=None,
            assignee=assignee,
            author=author,
        )

    else:
        requests = pagure.lib.query.search_pull_requests(
            flask.g.session,
            project_id=repo.id,
            assignee=assignee,
            author=author,
            status=status,
        )

    page = get_page()
    per_page = get_per_page()

    pagination_metadata = pagure.lib.query.get_pagination_metadata(
        flask.request, page, per_page, len(requests)
    )
    start = (page - 1) * per_page
    if start + per_page > len(requests):
        requests_page = requests[start:]
    else:
        requests_page = requests[start : (start + per_page)]

    jsonout = {
        "total_requests": len(requests),
        "requests": [
            request.to_json(public=True, api=True) for request in requests_page
        ],
        "args": {"status": status, "assignee": assignee, "author": author},
    }
    if pagination_metadata:
        jsonout["args"]["page"] = page
        jsonout["args"]["per_page"] = per_page
        jsonout["pagination"] = pagination_metadata
    return flask.jsonify(jsonout)
Exemple #2
0
def api_view_user_requests_actionable(username):
    """
    List PRs actionable by user
    ---------------------------

    Use this endpoint to retrieve a list of open pull requests a user is
    able to action (e.g. merge) over the entire pagure instance.

    ::

        GET /api/0/user/<username>/requests/actionable

    ::

        GET /api/0/user/dudemcpants/requests/actionable

    Parameters
    ^^^^^^^^^^

    +---------------+----------+--------------+----------------------------+
    | Key           | Type     | Optionality  | Description                |
    +===============+==========+==============+============================+
    | ``username``  | string   | Mandatory    | | The username of the user |
    |               |          |              |   whose activity you are   |
    |               |          |              |   interested in.           |
    +---------------+----------+--------------+----------------------------+
    | ``page``      | integer  | Mandatory    | | The page requested.      |
    |               |          |              |   Defaults to 1.           |
    +---------------+----------+--------------+----------------------------+
    | ``status``    | string   | Optional     | | Filter the status of     |
    |               |          |              |   pull requests. Default:  |
    |               |          |              |   ``Open`` (open pull      |
    |               |          |              |   requests), can be        |
    |               |          |              |   ``Closed`` for closed    |
    |               |          |              |   requests, ``Merged``     |
    |               |          |              |   for merged requests, or  |
    |               |          |              |   ``Open`` for open        |
    |               |          |              |   requests.                |
    |               |          |              |   ``All`` returns closed,  |
    |               |          |              |   merged and open requests.|
    +---------------+----------+--------------+----------------------------+

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

    ::

        {
          "args": {
            "status": "open",
            "username": "******",
            "page": 1,
          },
          "pagination": {
            "first": "http://localhost:5000/api/0/user/ryanlerch/requests/actionable?per_page=1&page=1",
            "last": "http://localhost:5000/api/0/user/ryanlerch/requests/actionable?per_page=1&page=61",
            "next": "http://localhost:5000/api/0/user/ryanlerch/requests/actionable?per_page=1&page=2",
            "page": 1,
            "pages": 61,
            "per_page": 1,
            "prev": null
          },
          "requests": [
            {
              "assignee": null,
              "branch": "master",
              "branch_from": "master",
              "closed_at": null,
              "closed_by": null,
              "comments": [],
              "commit_start": "3973fae98fc485783ca14f5c3612d85832185065",
              "commit_stop": "3973fae98fc485783ca14f5c3612d85832185065",
              "date_created": "1510227832",
              "id": 2,
              "initial_comment": null,
              "last_updated": "1510227833",
              "project": {
                  "access_groups": {
                    "admin": [],
                    "commit": [],
                    "ticket": []
                  },
                  "access_users": {
                    "admin": [],
                    "commit": [],
                    "owner": [
                        "ryanlerch"
                    ],
                    "ticket": []
                  },
                  "close_status": [],
                  "custom_keys": [],
                  "date_created": "1510227638",
                  "date_modified": "1510227638",
                  "description": "this is a quick project",
                  "fullname": "aquickproject",
                  "id": 1,
                  "milestones": {},
                  "name": "aquickproject",
                  "namespace": null,
                  "parent": null,
                  "priorities": {},
                  "tags": [],
                  "url_path": "aquickproject",
                  "user": {
                    "fullname": "ryanlerch",
                    "name": "ryanlerch"
                  }
              },
              "remote_git": null,
              "repo_from": {
                  "access_groups": {
                    "admin": [],
                    "commit": [],
                    "ticket": []
                  },
                  "access_users": {
                    "admin": [],
                    "commit": [],
                    "owner": [
                      "dudemcpants"
                    ],
                    "ticket": []
                  },
                  "close_status": [],
                  "custom_keys": [],
                  "date_created": "1510227729",
                  "date_modified": "1510227729",
                  "description": "this is a quick project",
                  "fullname": "forks/dudemcpants/aquickproject",
                  "id": 2,
                  "milestones": {},
                  "name": "aquickproject",
                  "namespace": null,
                  "parent": {
                    "access_groups": {
                      "admin": [],
                      "commit": [],
                      "ticket": []
                    },
                    "access_users": {
                      "admin": [],
                      "commit": [],
                      "owner": [
                        "ryanlerch"
                      ],
                      "ticket": []
                    },
                    "close_status": [],
                    "custom_keys": [],
                    "date_created": "1510227638",
                    "date_modified": "1510227638",
                    "description": "this is a quick project",
                    "fullname": "aquickproject",
                    "id": 1,
                    "milestones": {},
                    "name": "aquickproject",
                    "namespace": null,
                    "parent": null,
                    "priorities": {},
                    "tags": [],
                    "url_path": "aquickproject",
                    "user": {
                      "fullname": "ryanlerch",
                      "name": "ryanlerch"
                    }
                  },
                  "priorities": {},
                  "tags": [],
                  "url_path": "fork/dudemcpants/aquickproject",
                  "user": {
                    "fullname": "Dude McPants",
                    "name": "dudemcpants"
                  }
              },
              "status": "Open",
              "title": "Update README.md",
              "uid": "819e0b1c449e414fa291c914f28d73ec",
              "updated_on": "1510227832",
              "user": {
                "fullname": "Dude McPants",
                "name": "dudemcpants"
              }
            }
          ],
          "total_requests": 1
        }

    """  # noqa
    status = flask.request.args.get("status", "open")

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

    orig_status = status
    if status.lower() == "all":
        status = None
    else:
        status = status.capitalize()

    pullrequests_cnt = pagure.lib.query.get_pull_request_of_user(
        flask.g.session, username=username, status=status, count=True)
    pagination = pagure.lib.query.get_pagination_metadata(
        flask.request, page, per_page, pullrequests_cnt)

    pullrequests = pagure.lib.query.get_pull_request_of_user(
        flask.g.session,
        username=username,
        status=status,
        actionable=username,
        offset=offset,
        limit=limit,
    )

    pullrequestslist = [
        pr.to_json(public=True, api=True) for pr in pullrequests
    ]

    return flask.jsonify({
        "total_requests": len(pullrequestslist),
        "requests": pullrequestslist,
        "args": {
            "username": username,
            "status": orig_status,
            "page": page,
        },
        "pagination": pagination,
    })
Exemple #3
0
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
Exemple #4
0
def api_view_user(username):
    """
    User information
    ----------------
    Use this endpoint to retrieve information about a specific user.

    ::

        GET /api/0/user/<username>

    ::

        GET /api/0/user/ralph

    Parameters
    ^^^^^^^^^^

    +---------------+----------+---------------+--------------------------+
    | Key           | Type     | Optionality   | Description              |
    +===============+==========+===============+==========================+
    | ``repopage``  | int      | Optional      | | Specifies which        |
    |               |          |               |   page of the projects   |
    |               |          |               |   to return              |
    |               |          |               |   (defaults to: 1)       |
    +---------------+----------+---------------+--------------------------+
    | ``forkpage``  | int      | Optional      | | Specifies which        |
    |               |          |               |   page of the forks      |
    |               |          |               |   to return              |
    |               |          |               |   (defaults to: 1)       |
    +---------------+----------+---------------+--------------------------+
    | ``per_page``  | int      | Optional      | | The number of items    |
    |               |          |               |   to return per page.    |
    |               |          |               |   The maximum is 100.    |
    +---------------+----------+---------------+--------------------------+

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

    ::

        {
          "forks": [],
          "repos": [
            {
              "custom_keys": [],
              "description": "",
              "parent": null,
              "tags": [],
              "namespace": None,
              "priorities": {},
              "close_status": [
                "Invalid",
                "Insufficient data",
                "Fixed",
                "Duplicated"
              ],
              "milestones": {},
              "user": {
                "fullname": "ralph",
                "name": "ralph"
              },
              "date_created": "1426595173",
              "id": 5,
              "name": "pagure"
            }
          ],
          "repos_pagination": {
            "first": "http://localhost:5000/api/0/user/ralph?per_page=1&repopage=1",
            "last": "http://localhost:5000/api/0/user/ralph?per_page=1&repopage=123",
            "next": "http://localhost:5000/api/0/user/ralph?per_page=1&repopage=2",
            "pages": 123,
            "per_page": 1,
            "prev": null,
            "repopage": 1
          },
          "user": {
            "fullname": "ralph",
            "name": "ralph"
          }
        }

    """  # noqa
    httpcode = 200
    output = {}

    user = _get_user(username=username)

    per_page = get_per_page()
    repopage = flask.request.args.get("repopage", 1)
    try:
        repopage = int(repopage)
    except ValueError:
        repopage = 1

    forkpage = flask.request.args.get("forkpage", 1)
    try:
        forkpage = int(forkpage)
    except ValueError:
        forkpage = 1

    repos_cnt = pagure.lib.query.search_projects(flask.g.session,
                                                 username=username,
                                                 fork=False,
                                                 count=True)

    pagination_metadata_repo = pagure.lib.query.get_pagination_metadata(
        flask.request, repopage, per_page, repos_cnt, key_page="repopage")
    repopage_start = (repopage - 1) * per_page
    repopage_limit = per_page

    repos = pagure.lib.query.search_projects(
        flask.g.session,
        username=username,
        fork=False,
        start=repopage_start,
        limit=repopage_limit,
    )

    forks_cnt = pagure.lib.query.search_projects(flask.g.session,
                                                 username=username,
                                                 fork=True,
                                                 count=True)

    pagination_metadata_fork = pagure.lib.query.get_pagination_metadata(
        flask.request, forkpage, per_page, forks_cnt, key_page="forkpage")
    forkpage_start = (forkpage - 1) * per_page
    forkpage_limit = per_page

    forks = pagure.lib.query.search_projects(
        flask.g.session,
        username=username,
        fork=True,
        start=forkpage_start,
        limit=forkpage_limit,
    )

    output["user"] = user.to_json(public=True)
    output["repos"] = [repo.to_json(public=True) for repo in repos]
    output["forks"] = [repo.to_json(public=True) for repo in forks]
    output["repos_pagination"] = pagination_metadata_repo
    output["forks_pagination"] = pagination_metadata_fork

    jsonout = flask.jsonify(output)
    jsonout.status_code = httpcode
    return jsonout
Exemple #5
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
Exemple #6
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,
    })
Exemple #7
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,
        }
    )
Exemple #8
0
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