summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Kislitsky <akislitsky@mirantis.com>2017-01-26 17:25:33 +0300
committerAlexander Kislitsky <akislitsky@mirantis.com>2017-01-30 18:03:15 +0300
commitd4bf85957e13abecc519c84f43122e55df510eec (patch)
tree38ca0083737b1c26f8d9bb8efa342723b716b69b
parent0cabf795b5c241e1b529e15fed328a30d2e61dbf (diff)
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
Notes
Notes (review): Code-Review+2: Aleksey Kasatkin <akasatkin@mirantis.com> Verified+1: Fuel CI <fuel-ci-bot@mirantis.com> Code-Review+1: Julia Aranovich <jkirnosova@mirantis.com> Workflow+1: Ihor Kalnytskyi <ikalnitsky@mirantis.com> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Tue, 31 Jan 2017 11:36:38 +0000 Reviewed-on: https://review.openstack.org/425719 Project: openstack/fuel-web Branch: refs/heads/master
-rw-r--r--nailgun/nailgun/api/v1/handlers/notifications.py30
-rw-r--r--nailgun/nailgun/api/v1/urls.py4
-rw-r--r--nailgun/nailgun/objects/notification.py28
-rw-r--r--nailgun/nailgun/test/unit/test_notification_handler.py39
4 files changed, 96 insertions, 5 deletions
diff --git a/nailgun/nailgun/api/v1/handlers/notifications.py b/nailgun/nailgun/api/v1/handlers/notifications.py
index 6113c8f..c516b4e 100644
--- a/nailgun/nailgun/api/v1/handlers/notifications.py
+++ b/nailgun/nailgun/api/v1/handlers/notifications.py
@@ -59,3 +59,33 @@ class NotificationCollectionHandler(CollectionHandler):
59 self.collection.single.update(notif, nd) 59 self.collection.single.update(notif, nd)
60 notifications_updated.append(notif) 60 notifications_updated.append(notif)
61 return self.collection.to_list(notifications_updated) 61 return self.collection.to_list(notifications_updated)
62
63
64class 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)
diff --git a/nailgun/nailgun/api/v1/urls.py b/nailgun/nailgun/api/v1/urls.py
index d4249db..78dbeba 100644
--- a/nailgun/nailgun/api/v1/urls.py
+++ b/nailgun/nailgun/api/v1/urls.py
@@ -86,6 +86,8 @@ from nailgun.api.v1.handlers.plugin_link import PluginLinkCollectionHandler
86from nailgun.api.v1.handlers.plugin_link import PluginLinkHandler 86from nailgun.api.v1.handlers.plugin_link import PluginLinkHandler
87 87
88from nailgun.api.v1.handlers.notifications import NotificationCollectionHandler 88from nailgun.api.v1.handlers.notifications import NotificationCollectionHandler
89from nailgun.api.v1.handlers.notifications import \
90 NotificationCollectionStatsHandler
89from nailgun.api.v1.handlers.notifications import NotificationHandler 91from nailgun.api.v1.handlers.notifications import NotificationHandler
90 92
91from nailgun.api.v1.handlers.orchestrator import DefaultDeploymentInfo 93from nailgun.api.v1.handlers.orchestrator import DefaultDeploymentInfo
@@ -336,6 +338,8 @@ urls = (
336 NotificationCollectionHandler, 338 NotificationCollectionHandler,
337 r'/notifications/(?P<obj_id>\d+)/?$', 339 r'/notifications/(?P<obj_id>\d+)/?$',
338 NotificationHandler, 340 NotificationHandler,
341 r'/notifications/stats/?$',
342 NotificationCollectionStatsHandler,
339 343
340 r'/dump/(?P<snapshot_name>[A-Za-z0-9-_.]+)$', 344 r'/dump/(?P<snapshot_name>[A-Za-z0-9-_.]+)$',
341 SnapshotDownloadHandler, 345 SnapshotDownloadHandler,
diff --git a/nailgun/nailgun/objects/notification.py b/nailgun/nailgun/objects/notification.py
index 94d711f..e7d2bb8 100644
--- a/nailgun/nailgun/objects/notification.py
+++ b/nailgun/nailgun/objects/notification.py
@@ -16,17 +16,17 @@
16 16
17from datetime import datetime 17from datetime import datetime
18 18
19from nailgun.db.sqlalchemy import models 19from sqlalchemy import func
20 20
21from nailgun import consts
22from nailgun.db import db
23from nailgun.db.sqlalchemy import models
21from nailgun import errors 24from nailgun import errors
22from nailgun.logger import logger 25from nailgun.logger import logger
23
24from nailgun.objects import NailgunCollection 26from nailgun.objects import NailgunCollection
25from nailgun.objects import NailgunObject 27from nailgun.objects import NailgunObject
26
27from nailgun.objects import Task
28
29from nailgun.objects.serializers.notification import NotificationSerializer 28from nailgun.objects.serializers.notification import NotificationSerializer
29from nailgun.objects import Task
30 30
31 31
32class Notification(NailgunObject): 32class Notification(NailgunObject):
@@ -87,6 +87,24 @@ class Notification(NailgunObject):
87 notif_dict['date'] = instance.datetime.strftime('%d-%m-%Y') 87 notif_dict['date'] = instance.datetime.strftime('%d-%m-%Y')
88 return notif_dict 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
91class NotificationCollection(NailgunCollection): 109class NotificationCollection(NailgunCollection):
92 110
diff --git a/nailgun/nailgun/test/unit/test_notification_handler.py b/nailgun/nailgun/test/unit/test_notification_handler.py
index c82100d..69fd57e 100644
--- a/nailgun/nailgun/test/unit/test_notification_handler.py
+++ b/nailgun/nailgun/test/unit/test_notification_handler.py
@@ -101,3 +101,42 @@ class TestHandlers(BaseIntegrationTest):
101 expect_errors=True 101 expect_errors=True
102 ) 102 )
103 self.assertEqual(404, resp.status_code) 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)