Browse Source

Handler for counting notifications statuses added

For calculation of notifications statuses we made requests in the UI
and fetch all notifications data and process them on the UI side.
We want to replace a polling of the whole notification collection by
a polling of unread notifications number. This dramatically decrease
Fuel UI load in case of a big amount of notifications.

Change-Id: I8f83d4e2d7f58beaf06c489b2264ccb69f9927ce
Partial-Bug: #1657348
Alexander Kislitsky 2 years ago
parent
commit
d4bf85957e

+ 30
- 0
nailgun/nailgun/api/v1/handlers/notifications.py View File

@@ -59,3 +59,33 @@ class NotificationCollectionHandler(CollectionHandler):
59 59
             self.collection.single.update(notif, nd)
60 60
             notifications_updated.append(notif)
61 61
         return self.collection.to_list(notifications_updated)
62
+
63
+
64
+class NotificationCollectionStatsHandler(CollectionHandler):
65
+
66
+    collection = objects.NotificationCollection
67
+    validator = NotificationValidator
68
+
69
+    @handle_errors
70
+    @validate
71
+    @serialize
72
+    def GET(self):
73
+        """Calculates notifications statuses
74
+
75
+        Counts all presented notifications in the DB and returns dict
76
+        with structure {'total': count, 'unread': count, ...}
77
+
78
+        :returns: dict with notifications statuses count
79
+
80
+        :http: * 200 (OK)
81
+        """
82
+        return self.collection.single.get_statuses_with_count()
83
+
84
+    @handle_errors
85
+    @validate
86
+    def POST(self):
87
+        """Update notification statuses is not allowed
88
+
89
+        :http: * 405 (Method not allowed)
90
+        """
91
+        raise self.http(405)

+ 4
- 0
nailgun/nailgun/api/v1/urls.py View File

@@ -86,6 +86,8 @@ from nailgun.api.v1.handlers.plugin_link import PluginLinkCollectionHandler
86 86
 from nailgun.api.v1.handlers.plugin_link import PluginLinkHandler
87 87
 
88 88
 from nailgun.api.v1.handlers.notifications import NotificationCollectionHandler
89
+from nailgun.api.v1.handlers.notifications import \
90
+    NotificationCollectionStatsHandler
89 91
 from nailgun.api.v1.handlers.notifications import NotificationHandler
90 92
 
91 93
 from nailgun.api.v1.handlers.orchestrator import DefaultDeploymentInfo
@@ -336,6 +338,8 @@ urls = (
336 338
     NotificationCollectionHandler,
337 339
     r'/notifications/(?P<obj_id>\d+)/?$',
338 340
     NotificationHandler,
341
+    r'/notifications/stats/?$',
342
+    NotificationCollectionStatsHandler,
339 343
 
340 344
     r'/dump/(?P<snapshot_name>[A-Za-z0-9-_.]+)$',
341 345
     SnapshotDownloadHandler,

+ 23
- 5
nailgun/nailgun/objects/notification.py View File

@@ -16,17 +16,17 @@
16 16
 
17 17
 from datetime import datetime
18 18
 
19
-from nailgun.db.sqlalchemy import models
19
+from sqlalchemy import func
20 20
 
21
+from nailgun import consts
22
+from nailgun.db import db
23
+from nailgun.db.sqlalchemy import models
21 24
 from nailgun import errors
22 25
 from nailgun.logger import logger
23
-
24 26
 from nailgun.objects import NailgunCollection
25 27
 from nailgun.objects import NailgunObject
26
-
27
-from nailgun.objects import Task
28
-
29 28
 from nailgun.objects.serializers.notification import NotificationSerializer
29
+from nailgun.objects import Task
30 30
 
31 31
 
32 32
 class Notification(NailgunObject):
@@ -87,6 +87,24 @@ class Notification(NailgunObject):
87 87
         notif_dict['date'] = instance.datetime.strftime('%d-%m-%Y')
88 88
         return notif_dict
89 89
 
90
+    @classmethod
91
+    def get_statuses_with_count(cls):
92
+        """Counts notifications statuses in DB
93
+
94
+        Calculates number of notifications and adds total count to the
95
+        result. All notifications statuses described in the
96
+        consts.NOTIFICATION_STATUSES will be present in the result.
97
+
98
+        :return: dict with structure {'total': count, 'unread': count, ...}
99
+        """
100
+        result = dict.fromkeys(consts.NOTIFICATION_STATUSES, 0)
101
+        query = db().query(cls.model.status, func.count(cls.model.status)).\
102
+            group_by(cls.model.status)
103
+        for status, num in query.all():
104
+            result[status] = num
105
+        result['total'] = sum(result.values())
106
+        return result
107
+
90 108
 
91 109
 class NotificationCollection(NailgunCollection):
92 110
 

+ 39
- 0
nailgun/nailgun/test/unit/test_notification_handler.py View File

@@ -101,3 +101,42 @@ class TestHandlers(BaseIntegrationTest):
101 101
             expect_errors=True
102 102
         )
103 103
         self.assertEqual(404, resp.status_code)
104
+
105
+    def test_get_notification_status(self):
106
+        resp = self.app.get(
107
+            reverse(
108
+                'NotificationCollectionStatsHandler',
109
+            ),
110
+            headers=self.default_headers
111
+        )
112
+        self.assertEqual({'total': 0, 'read': 0, 'unread': 0}, resp.json_body)
113
+        self.assertEqual(200, resp.status_code)
114
+
115
+        self.env.create_notification()
116
+        resp = self.app.get(
117
+            reverse(
118
+                'NotificationCollectionStatsHandler',
119
+            ),
120
+            headers=self.default_headers
121
+        )
122
+        self.assertEqual({'total': 1, 'read': 0, 'unread': 1}, resp.json_body)
123
+
124
+        self.env.create_notification(status='read')
125
+        self.env.create_notification(status='read')
126
+        resp = self.app.get(
127
+            reverse(
128
+                'NotificationCollectionStatsHandler',
129
+            ),
130
+            headers=self.default_headers
131
+        )
132
+        self.assertEqual({'total': 3, 'read': 2, 'unread': 1}, resp.json_body)
133
+
134
+    def test_notification_statuses_post_not_allowed(self):
135
+        resp = self.app.post(
136
+            reverse(
137
+                'NotificationCollectionStatsHandler',
138
+            ),
139
+            headers=self.default_headers,
140
+            expect_errors=True
141
+        )
142
+        self.assertEqual(405, resp.status_code)

Loading…
Cancel
Save