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
This commit is contained in:
Alexander Kislitsky 2017-01-26 17:25:33 +03:00
parent 0cabf795b5
commit d4bf85957e
4 changed files with 96 additions and 5 deletions

View File

@ -59,3 +59,33 @@ class NotificationCollectionHandler(CollectionHandler):
self.collection.single.update(notif, nd)
notifications_updated.append(notif)
return self.collection.to_list(notifications_updated)
class NotificationCollectionStatsHandler(CollectionHandler):
collection = objects.NotificationCollection
validator = NotificationValidator
@handle_errors
@validate
@serialize
def GET(self):
"""Calculates notifications statuses
Counts all presented notifications in the DB and returns dict
with structure {'total': count, 'unread': count, ...}
:returns: dict with notifications statuses count
:http: * 200 (OK)
"""
return self.collection.single.get_statuses_with_count()
@handle_errors
@validate
def POST(self):
"""Update notification statuses is not allowed
:http: * 405 (Method not allowed)
"""
raise self.http(405)

View File

@ -86,6 +86,8 @@ from nailgun.api.v1.handlers.plugin_link import PluginLinkCollectionHandler
from nailgun.api.v1.handlers.plugin_link import PluginLinkHandler
from nailgun.api.v1.handlers.notifications import NotificationCollectionHandler
from nailgun.api.v1.handlers.notifications import \
NotificationCollectionStatsHandler
from nailgun.api.v1.handlers.notifications import NotificationHandler
from nailgun.api.v1.handlers.orchestrator import DefaultDeploymentInfo
@ -336,6 +338,8 @@ urls = (
NotificationCollectionHandler,
r'/notifications/(?P<obj_id>\d+)/?$',
NotificationHandler,
r'/notifications/stats/?$',
NotificationCollectionStatsHandler,
r'/dump/(?P<snapshot_name>[A-Za-z0-9-_.]+)$',
SnapshotDownloadHandler,

View File

@ -16,17 +16,17 @@
from datetime import datetime
from nailgun.db.sqlalchemy import models
from sqlalchemy import func
from nailgun import consts
from nailgun.db import db
from nailgun.db.sqlalchemy import models
from nailgun import errors
from nailgun.logger import logger
from nailgun.objects import NailgunCollection
from nailgun.objects import NailgunObject
from nailgun.objects import Task
from nailgun.objects.serializers.notification import NotificationSerializer
from nailgun.objects import Task
class Notification(NailgunObject):
@ -87,6 +87,24 @@ class Notification(NailgunObject):
notif_dict['date'] = instance.datetime.strftime('%d-%m-%Y')
return notif_dict
@classmethod
def get_statuses_with_count(cls):
"""Counts notifications statuses in DB
Calculates number of notifications and adds total count to the
result. All notifications statuses described in the
consts.NOTIFICATION_STATUSES will be present in the result.
:return: dict with structure {'total': count, 'unread': count, ...}
"""
result = dict.fromkeys(consts.NOTIFICATION_STATUSES, 0)
query = db().query(cls.model.status, func.count(cls.model.status)).\
group_by(cls.model.status)
for status, num in query.all():
result[status] = num
result['total'] = sum(result.values())
return result
class NotificationCollection(NailgunCollection):

View File

@ -101,3 +101,42 @@ class TestHandlers(BaseIntegrationTest):
expect_errors=True
)
self.assertEqual(404, resp.status_code)
def test_get_notification_status(self):
resp = self.app.get(
reverse(
'NotificationCollectionStatsHandler',
),
headers=self.default_headers
)
self.assertEqual({'total': 0, 'read': 0, 'unread': 0}, resp.json_body)
self.assertEqual(200, resp.status_code)
self.env.create_notification()
resp = self.app.get(
reverse(
'NotificationCollectionStatsHandler',
),
headers=self.default_headers
)
self.assertEqual({'total': 1, 'read': 0, 'unread': 1}, resp.json_body)
self.env.create_notification(status='read')
self.env.create_notification(status='read')
resp = self.app.get(
reverse(
'NotificationCollectionStatsHandler',
),
headers=self.default_headers
)
self.assertEqual({'total': 3, 'read': 2, 'unread': 1}, resp.json_body)
def test_notification_statuses_post_not_allowed(self):
resp = self.app.post(
reverse(
'NotificationCollectionStatsHandler',
),
headers=self.default_headers,
expect_errors=True
)
self.assertEqual(405, resp.status_code)