0002-notification-send-notification-to-several-users-6064.patch
combo/apps/notifications/api_views.py | ||
---|---|---|
9 | 9 |
# This program is distributed in the hope that it will be useful, |
10 | 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | 12 |
# GNU Affero General Public License for more details. |
13 | 13 |
# |
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from django.contrib.auth.models import User |
|
18 |
from django.db import transaction |
|
17 | 19 |
from django.utils.encoding import force_text |
20 |
from django.utils.translation import ugettext_lazy as _ |
|
18 | 21 |
from rest_framework import authentication, permissions, serializers, status |
19 | 22 |
from rest_framework.generics import GenericAPIView |
20 | 23 |
from rest_framework.response import Response |
21 | 24 | |
22 | 25 |
from .models import Notification |
23 | 26 | |
24 | 27 | |
25 | 28 |
class NotificationSerializer(serializers.Serializer): |
26 | 29 |
summary = serializers.CharField(required=True, allow_blank=False, max_length=140) |
27 | 30 |
id = serializers.CharField(required=False, allow_null=True) |
28 | 31 |
body = serializers.CharField(allow_blank=False, default='') |
29 | 32 |
url = serializers.URLField(allow_blank=True, default='') |
30 | 33 |
origin = serializers.CharField(allow_blank=True, default='') |
31 | 34 |
start_timestamp = serializers.DateTimeField(required=False, allow_null=True) |
32 | 35 |
end_timestamp = serializers.DateTimeField(required=False, allow_null=True) |
33 | 36 |
duration = serializers.IntegerField(required=False, allow_null=True, min_value=0) |
37 |
usernames = serializers.ListField( |
|
38 |
required=False, child=serializers.CharField(required=True, max_length=150) |
|
39 |
) |
|
40 | ||
41 |
def validate(self, attrs): |
|
42 |
super().validate(attrs) |
|
43 |
users = [] |
|
44 |
for username in attrs.get('usernames') or []: |
|
45 |
try: |
|
46 |
users.append(User.objects.get(username=username)) |
|
47 |
except User.DoesNotExist: |
|
48 |
raise serializers.ValidationError({'users': _('"%s" user does not exist.') % username}) |
|
49 |
attrs['users'] = users |
|
50 |
return attrs |
|
34 | 51 | |
35 | 52 | |
36 | 53 |
class Add(GenericAPIView): |
37 | 54 |
permission_classes = (permissions.IsAuthenticated,) |
38 | 55 |
serializer_class = NotificationSerializer |
39 | 56 | |
40 | 57 |
def post(self, request, *args, **kwargs): |
41 | 58 |
serializer = self.get_serializer(data=request.data) |
42 | 59 |
if not serializer.is_valid(): |
43 | 60 |
response = {'err': 1, 'err_desc': serializer.errors} |
44 | 61 |
return Response(response, status.HTTP_400_BAD_REQUEST) |
45 | 62 |
data = serializer.validated_data |
63 |
notification_ids = [] |
|
46 | 64 |
try: |
47 |
notification = Notification.notify( |
|
48 |
user=request.user, |
|
49 |
summary=data['summary'], |
|
50 |
id=data.get('id'), |
|
51 |
body=data.get('body'), |
|
52 |
url=data.get('url'), |
|
53 |
origin=data.get('origin'), |
|
54 |
start_timestamp=data.get('start_timestamp'), |
|
55 |
end_timestamp=data.get('end_timestamp'), |
|
56 |
duration=data.get('duration'), |
|
57 |
) |
|
65 |
with transaction.atomic(): |
|
66 |
for user in data.get('users') or [request.user]: |
|
67 |
notification = Notification.notify( |
|
68 |
user=user, |
|
69 |
summary=data['summary'], |
|
70 |
id=data.get('id'), |
|
71 |
body=data.get('body'), |
|
72 |
url=data.get('url'), |
|
73 |
origin=data.get('origin'), |
|
74 |
start_timestamp=data.get('start_timestamp'), |
|
75 |
end_timestamp=data.get('end_timestamp'), |
|
76 |
duration=data.get('duration'), |
|
77 |
) |
|
78 |
notification_ids.append(notification.public_id) |
|
58 | 79 |
except ValueError as e: |
59 | 80 |
response = {'err': 1, 'err_desc': {'id': [force_text(e)]}} |
60 | 81 |
return Response(response, status.HTTP_400_BAD_REQUEST) |
82 |
uniq_ids = set(notification_ids) |
|
83 |
if len(uniq_ids) == 1: |
|
84 |
response = {'err': 0, 'data': {'nb_notify': len(notification_ids), 'id': uniq_ids.pop()}} |
|
61 | 85 |
else: |
62 |
response = {'err': 0, 'data': {'id': notification.public_id}}
|
|
63 |
return Response(response)
|
|
86 |
response = {'err': 0, 'data': {'nb_notify': len(notification_ids), 'ids': notification_ids}}
|
|
87 |
return Response(response) |
|
64 | 88 | |
65 | 89 | |
66 | 90 |
add = Add.as_view() |
67 | 91 | |
68 | 92 | |
69 | 93 |
class Ack(GenericAPIView): |
70 | 94 |
authentication_classes = (authentication.SessionAuthentication,) |
71 | 95 |
permission_classes = (permissions.IsAuthenticated,) |
tests/test_notification.py | ||
---|---|---|
147 | 147 | |
148 | 148 | |
149 | 149 |
def test_notification_ws(john_doe): |
150 | 150 |
def notify(data, count, check_id=None): |
151 | 151 |
resp = client.post(reverse('api-notification-add'), json.dumps(data), content_type='application/json') |
152 | 152 |
assert resp.status_code == 200 |
153 | 153 |
result = json.loads(force_text(resp.content)) |
154 | 154 |
assert result['err'] == 0 |
155 |
assert result['data']['nb_notify'] == 1 |
|
156 |
assert 'id' in result['data'] |
|
155 | 157 |
if 'id' in data: |
156 | 158 |
assert check_id is not None and result['data']['id'] == check_id |
157 | 159 |
assert Notification.objects.filter(user=john_doe).count() == count |
158 | 160 |
return Notification.objects.filter(user=john_doe).order_by('id').last() |
159 | 161 | |
160 | 162 |
login(john_doe) |
161 | 163 |
notify({'summary': 'foo'}, 1) |
162 | 164 |
notify({'summary': 'bar'}, 2) |
... | ... | |
513 | 515 |
Notification.objects.visible(john_doe).ack() |
514 | 516 | |
515 | 517 |
# acking a notification without and end_timestamp, still visible |
516 | 518 |
freezer.move_to(start + timedelta(days=365, seconds=1)) |
517 | 519 |
content = cell.render(context) |
518 | 520 |
assert Notification.objects.visible(john_doe).count() == 1 |
519 | 521 |
assert 'notibar' in content |
520 | 522 |
assert 'notifoo' not in content |
523 | ||
524 | ||
525 |
def test_notification_ws_create_many(john_doe, jane_doe): |
|
526 |
login(john_doe) |
|
527 | ||
528 |
data = {'summary': 'foo', 'usernames': [john_doe.username, jane_doe.username]} |
|
529 |
resp = client.post(reverse('api-notification-add'), json.dumps(data), content_type='application/json') |
|
530 |
assert resp.status_code == 200 |
|
531 |
result = resp.json() |
|
532 |
assert result['err'] == 0 |
|
533 |
assert result['data']['nb_notify'] == 2 |
|
534 |
assert len(result['data']['ids']) == 2 |
|
535 |
assert Notification.objects.count() == 2 |
|
536 |
notif = Notification.objects.filter(user=john_doe).last() |
|
537 |
assert notif.public_id == result['data']['ids'][0] |
|
538 |
assert notif.summary == 'foo' |
|
539 |
notif = Notification.objects.filter(user=jane_doe).last() |
|
540 |
assert notif.public_id == result['data']['ids'][1] |
|
541 |
assert notif.summary == 'foo' |
|
542 | ||
543 |
# wrong username |
|
544 |
data = {'summary': 'foo', 'usernames': [john_doe.username, 'unknown']} |
|
545 |
resp = client.post(reverse('api-notification-add'), json.dumps(data), content_type='application/json') |
|
546 |
assert resp.status_code == 400 |
|
547 |
result = resp.json() |
|
548 |
assert result['err_desc'] == {'users': ['"unknown" user does not exist.']} |
|
549 |
assert Notification.objects.count() == 2 |
|
550 | ||
551 | ||
552 |
def test_notification_ws_update_many(john_doe, jane_doe): |
|
553 |
login(john_doe) |
|
554 | ||
555 |
data = { |
|
556 |
'summary': 'foo', |
|
557 |
'usernames': [john_doe.username, jane_doe.username], |
|
558 |
'id': 'test:42', |
|
559 |
} |
|
560 |
resp = client.post(reverse('api-notification-add'), json.dumps(data), content_type='application/json') |
|
561 |
assert resp.status_code == 200 |
|
562 |
result = resp.json() |
|
563 |
assert result['err'] == 0 |
|
564 |
assert result['data']['nb_notify'] == 2 |
|
565 |
assert result['data']['id'] == 'test:42' |
|
566 |
assert Notification.objects.count() == 2 |
|
567 |
assert Notification.objects.get(user=john_doe, external_id='test:42').summary == 'foo' |
|
568 |
assert Notification.objects.get(user=jane_doe, external_id='test:42').summary == 'foo' |
|
569 | ||
570 |
data['summary'] = 'bar' |
|
571 |
resp = client.post(reverse('api-notification-add'), json.dumps(data), content_type='application/json') |
|
572 |
assert resp.status_code == 200 |
|
573 |
result = resp.json() |
|
574 |
assert result['err'] == 0 |
|
575 |
assert result['data']['nb_notify'] == 2 |
|
576 |
assert result['data']['id'] == 'test:42' |
|
577 |
assert Notification.objects.count() == 2 |
|
578 |
assert Notification.objects.get(user=john_doe, external_id='test:42').summary == 'bar' |
|
579 |
assert Notification.objects.get(user=jane_doe, external_id='test:42').summary == 'bar' |
|
521 |
- |