notifications: allow notifications without an end_timestamp (#22732)

Those notifications will disappear only with an action of the user.
This commit is contained in:
Benjamin Dauvergne 2018-03-24 01:50:30 +01:00 committed by Frédéric Péters
parent a16ee38a99
commit dab07696ff
3 changed files with 100 additions and 6 deletions

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.11 on 2018-03-24 00:25
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('notifications', '0004_auto_20180316_1026'),
]
operations = [
migrations.AlterField(
model_name='notification',
name='end_timestamp',
field=models.DateTimeField(null=True, verbose_name='End date and time'),
),
]

View File

@ -42,14 +42,15 @@ class NotificationQuerySet(QuerySet):
return qs.filter(search_id)
def ack(self):
self.update(acked=True)
self.filter(end_timestamp__isnull=True).update(acked=True, end_timestamp=now() - timedelta(seconds=5))
self.filter(end_timestamp__isnull=False).update(acked=True)
def visible(self, user=None, n=None):
qs = self
if user:
qs = qs.filter(user=user)
n = n or now()
qs = qs.filter(start_timestamp__lte=n, end_timestamp__gt=n)
qs = qs.filter(Q(start_timestamp__lte=n) & (Q(end_timestamp__isnull=True) | Q(end_timestamp__gte=n)))
return qs.order_by('-start_timestamp')
def new(self):
@ -72,11 +73,10 @@ class Notification(models.Model):
url = models.URLField(_('URL'), default='', blank=True)
origin = models.CharField(_('Origin'), max_length=100, blank=True)
start_timestamp = models.DateTimeField(_('Start date and time'))
end_timestamp = models.DateTimeField(_('End date and time'))
end_timestamp = models.DateTimeField(_('End date and time'), null=True)
acked = models.BooleanField(_('Acked'), default=False)
external_id = models.SlugField(_('External identifier'), null=True)
class Meta:
verbose_name = _('Notification')
unique_together = (
@ -106,6 +106,8 @@ class Notification(models.Model):
if end_timestamp:
pass
elif duration == 0:
end_timestamp = None
elif duration:
if not isinstance(duration, timedelta):
duration = timedelta(seconds=duration)
@ -157,8 +159,13 @@ class Notification(models.Model):
self.save(update_fields=['end_timestamp', 'acked'])
def ack(self):
self.acked = True
self.save(update_fields=['acked'])
if self.end_timestamp:
self.acked = True
self.save(update_fields=['acked'])
else:
self.acked = True
self.end_timestamp = now() - timedelta(seconds=5)
self.save(update_fields=['acked', 'end_timestamp'])
@register_cell_class

View File

@ -3,6 +3,7 @@ import json
import mock
import pytest
from decimal import Decimal
from datetime import timedelta as timedelta
from django.contrib.auth.models import User
from django.test.client import RequestFactory
@ -343,6 +344,7 @@ def test_notify_remote_items(mock_get, app, john_doe, jane_doe, regie, monkeypat
from combo.apps.lingo import models
monkeypatch.setattr(models, 'UserSAMLIdentifier', None)
regie.notify_new_remote_invoices()
# make sure no other requests calls are made
assert mock_get.call_count == 1
@ -393,3 +395,68 @@ def test_notify_remote_items(mock_get, app, john_doe, jane_doe, regie, monkeypat
# be sure the are no more reminders created
regie.notify_new_remote_invoices()
assert Notification.objects.count() == 4
def test_notification_never_expire(app, freezer, rf, john_doe):
start = freezer()
app.authorization = ('Basic', (john_doe.username, john_doe.username))
app.post_json(reverse('api-notification-add'), params={
'summary': 'notibar',
'url': 'http://www.example.net',
'body': 'foobar',
'origin': 'blah',
'duration': 0,
})
app.post_json(reverse('api-notification-add'), params={
'summary': 'notifoo',
'url': 'http://www.example.net',
'body': 'foobar',
'origin': 'blah',
'duration': 86400 * 2, # 2 days
})
page = Page.objects.create(title='notif', slug='test_notification_cell', template_name='standard')
cell = NotificationsCell(page=page, placeholder='content', order=0)
request = rf.get('/')
request.user = john_doe
context = {'request': request}
freezer.move_to(start - timedelta(seconds=10))
assert Notification.objects.visible(john_doe).count() == 0
content = cell.render(context)
assert 'notibar' not in content
assert 'notifoo' not in content
freezer.move_to(start + timedelta(seconds=10))
assert Notification.objects.visible(john_doe).count() == 2
content = cell.render(context)
assert 'notibar' in content
assert 'notifoo' in content
freezer.move_to(start + timedelta(days=1))
content = cell.render(context)
assert Notification.objects.visible(john_doe).count() == 2
assert 'notibar' in content
assert 'notifoo' in content
freezer.move_to(start + timedelta(days=3))
content = cell.render(context)
assert Notification.objects.visible(john_doe).count() == 1
assert 'notibar' in content
assert 'notifoo' not in content
freezer.move_to(start + timedelta(days=365))
content = cell.render(context)
assert Notification.objects.visible(john_doe).count() == 1
assert 'notibar' in content
assert 'notifoo' not in content
Notification.objects.visible(john_doe).ack()
# acking a notification without and end_timestamp, forget it
freezer.move_to(start + timedelta(days=365, seconds=1))
content = cell.render(context)
assert Notification.objects.visible(john_doe).count() == 0
assert 'notibar' not in content
assert 'notifoo' not in content