|
@@ -132,6 +132,222 @@ def api_view_user(username):
|
|
|
return jsonout
|
|
|
|
|
|
|
|
|
+@API.route('/user/<username>/issues')
|
|
|
+@api_method
|
|
|
+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 |
|
|
|
+ +===============+=========+==============+===========================+
|
|
|
+ | ``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`` |
|
|
|
+ +---------------+---------+--------------+---------------------------+
|
|
|
+
|
|
|
+ Sample response
|
|
|
+ ^^^^^^^^^^^^^^^
|
|
|
+
|
|
|
+ ::
|
|
|
+
|
|
|
+ {
|
|
|
+ "args": {
|
|
|
+ "milestones": [],
|
|
|
+ "no_stones": null,
|
|
|
+ "order": null,
|
|
|
+ "order_key": null,
|
|
|
+ "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"
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "total_issues_assigned": 1,
|
|
|
+ "total_issues_created": 1
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ """
|
|
|
+ assignee = flask.request.args.get('assignee', None)
|
|
|
+ author = username
|
|
|
+ milestone = flask.request.args.getlist('milestones', None)
|
|
|
+ no_stones = flask.request.args.get('no_stones', None)
|
|
|
+ if no_stones is not None:
|
|
|
+ if str(no_stones).lower() in ['1', 'true', 't']:
|
|
|
+ no_stones = True
|
|
|
+ else:
|
|
|
+ no_stones = False
|
|
|
+ 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()]
|
|
|
+ params = {
|
|
|
+ 'session': SESSION,
|
|
|
+ 'tags': tags,
|
|
|
+ 'milestones': milestone,
|
|
|
+ 'order': order,
|
|
|
+ 'order_key': order_key,
|
|
|
+ 'no_milestones': no_stones,
|
|
|
+ }
|
|
|
+
|
|
|
+ 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})
|
|
|
+ params_created = params.copy()
|
|
|
+ params_assigned = params
|
|
|
+ params.update({"author": username})
|
|
|
+ issues_created = pagure.lib.search_issues(**params_created)
|
|
|
+ params_assigned.update({"assignee": username})
|
|
|
+ issues_assigned = pagure.lib.search_issues(**params_assigned)
|
|
|
+ jsonout = flask.jsonify({
|
|
|
+ 'total_issues_created': len(issues_created),
|
|
|
+ 'total_issues_assigned': len(issues_assigned),
|
|
|
+ 'issues_created': [issue.to_json(public=True)
|
|
|
+ for issue in issues_created],
|
|
|
+ 'issues_assigned': [issue.to_json(public=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,
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return jsonout
|
|
|
+
|
|
|
+
|
|
|
@API.route('/user/<username>/activity/stats')
|
|
|
@api_method
|
|
|
def api_view_user_activity_stats(username):
|