Quellcode durchsuchen

Add a new API endpoint to retrieve details stats about the issues

This endpoint will return for the past year a moving 7 days overview
of the number of tickets opened, closed and the total number of
tickets at the beginning of this window.

Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>
Pierre-Yves Chibon vor 4 Jahren
Ursprung
Commit
4f0011e795
3 geänderte Dateien mit 107 neuen und 12 gelöschten Zeilen
  1. 63 1
      pagure/api/issue.py
  2. 22 10
      pagure/lib/query.py
  3. 22 1
      tests/test_pagure_flask_api_issue.py

+ 63 - 1
pagure/api/issue.py

@@ -1532,6 +1532,68 @@ def api_view_issues_history_stats(repo, username=None, namespace=None):
     repo = _get_repo(repo, username, namespace)
     _check_issue_tracker(repo)
 
-    stats = pagure.lib.query.issues_history_stats(flask.g.session, repo)
+    stats = pagure.lib.query.issues_history_stats(
+        flask.g.session, repo, detailed=False
+    )
+    jsonout = flask.jsonify({"stats": stats})
+    return jsonout
+
+
+@API.route("/<repo>/issues/history/detailed_stats")
+@API.route("/<namespace>/<repo>/issues/history/detailed_stats")
+@API.route("/fork/<username>/<repo>/issues/history/detailed_stats")
+@API.route("/fork/<username>/<namespace>/<repo>/issues/history/detailed_stats")
+@api_method
+def api_view_issues_history_detailed_stats(
+    repo, username=None, namespace=None
+):
+    """
+    List project's detailed statistical issues history.
+    ---------------------------------------------------
+    Provides the number of opened issues over the last year of the
+    project.
+
+    ::
+
+        GET /api/0/<repo>/issues/history/detailed_stats
+        GET /api/0/<namespace>/<repo>/issues/history/detailed_stats
+
+    ::
+
+        GET /api/0/fork/<username>/<repo>/issues/history/detailed_stats
+        GET /api/0/fork/<username>/<namespace>/<repo>/issues/history/detailed_stats
+
+
+    Sample response
+    ^^^^^^^^^^^^^^^
+
+    ::
+        {
+          "stats": {
+            "2020-03-26T19:21:51.348451": {
+              "closed_ticket": 0,
+              "count": 0,
+              "open_ticket": 0
+            },
+            "2020-04-02T19:21:51.348451": {
+              "closed_ticket": 0,
+              "count": 0,
+              "open_ticket": 0
+            },
+            "2020-04-09T19:21:51.348451": {
+              "closed_ticket": 1,
+              "count": 0,
+              "open_ticket": 2
+            }
+          }
+        }
+
+    """  # noqa
+    repo = _get_repo(repo, username, namespace)
+    _check_issue_tracker(repo)
+
+    stats = pagure.lib.query.issues_history_stats(
+        flask.g.session, repo, detailed=True
+    )
     jsonout = flask.jsonify({"stats": stats})
     return jsonout

+ 22 - 10
pagure/lib/query.py

@@ -5652,7 +5652,7 @@ def update_read_only_mode(session, repo, read_only=True):
         session.add(repo)
 
 
-def issues_history_stats(session, project):
+def issues_history_stats(session, project, detailed=False):
     """ Returns the number of opened issues on the specified project over
     the last 365 days
 
@@ -5675,23 +5675,35 @@ def issues_history_stats(session, project):
     tomorrow = datetime.datetime.utcnow() + datetime.timedelta(days=1)
     output = {}
     for week in range(53):
-        start = tomorrow - datetime.timedelta(days=(week * 7))
+        end = tomorrow - datetime.timedelta(days=(week * 7))
+        start = end - datetime.timedelta(days=7)
         closed_ticket = (
             session.query(model.Issue)
             .filter(model.Issue.project_id == project.id)
             .filter(model.Issue.closed_at >= start)
-            .filter(model.Issue.date_created <= start)
-        )
-        open_ticket = (
+            .filter(model.Issue.closed_at < end)
+        ).count()
+        query_open = (
             session.query(model.Issue)
             .filter(model.Issue.project_id == project.id)
-            .filter(model.Issue.status == "Open")
-            .filter(model.Issue.date_created <= start)
-        )
-        cnt = open_ticket.count() + closed_ticket.count() - to_ignore
+            .filter(model.Issue.date_created >= start)
+            .filter(model.Issue.date_created < end)
+        )
+        # For backward compatibility
+        if detailed is False:
+            query_open = query_open.filter(model.Issue.status == "Open")
+        open_ticket = query_open.count()
+        cnt = open_ticket + closed_ticket - to_ignore
         if cnt < 0:
             cnt = 0
-        output[start.isoformat()] = cnt
+        if detailed is False:
+            output[start.isoformat()] = cnt
+        else:
+            output[start.isoformat()] = {
+                "open_ticket": open_ticket,
+                "closed_ticket": closed_ticket,
+                "count": cnt,
+            }
 
     return output
 

+ 22 - 1
tests/test_pagure_flask_api_issue.py

@@ -4230,7 +4230,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         """ Test the api_view_issues_history_stats method of the flask api. """
         self.test_api_new_issue()
 
-        # Create private issue
+        # Create private issue, closed and without a closed_at date
         repo = pagure.lib.query.get_authorized_project(self.session, "test")
         msg = pagure.lib.query.new_issue(
             session=self.session,
@@ -4255,6 +4255,27 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         for k in sorted(data["stats"].keys())[:-1]:
             self.assertEqual(data["stats"][k], 0)
 
+    def test_api_view_issues_history_stats_detailed(self):
+        """ Test the api_view_issues_history_stats method of the flask api. """
+        self.test_api_new_issue()
+
+        output = self.app.get("/api/0/test/issues/history/detailed_stats")
+        self.assertEqual(output.status_code, 200)
+        data = json.loads(output.get_data(as_text=True))
+
+        self.assertEqual(list(data.keys()), ["stats"])
+        self.assertEqual(len(data["stats"]), 53)
+        last_key = sorted(data["stats"].keys())[-1]
+        self.assertEqual(
+            data["stats"][last_key],
+            {"closed_ticket": 0, "count": 0, "open_ticket": 1},
+        )
+        for k in sorted(data["stats"].keys())[:-1]:
+            self.assertEqual(
+                data["stats"][k],
+                {"closed_ticket": 0, "count": 0, "open_ticket": 0},
+            )
+
     def test_api_view_user_issues_pingou(self):
         """ Test the api_view_user_issues method of the flask api for pingou.
         """