notification: send a notification to several users (#60643)

This commit is contained in:
Nicolas Roche 2022-01-18 12:12:19 +01:00 committed by Frédéric Péters
parent 93d54bf08f
commit 0be1356882
2 changed files with 125 additions and 14 deletions

View File

@ -14,11 +14,15 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.contrib.auth.models import User
from django.db import transaction
from django.utils.encoding import force_text
from rest_framework import authentication, permissions, serializers, status
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from combo.profile.utils import get_user_from_name_id
from .models import Notification
@ -31,6 +35,27 @@ class NotificationSerializer(serializers.Serializer):
start_timestamp = serializers.DateTimeField(required=False, allow_null=True)
end_timestamp = serializers.DateTimeField(required=False, allow_null=True)
duration = serializers.IntegerField(required=False, allow_null=True, min_value=0)
name_ids = serializers.ListField(
required=False, child=serializers.CharField(required=True, max_length=150)
)
def validate(self, attrs):
super().validate(attrs)
users = []
founded = []
missing = []
for uuid in attrs.get('name_ids') or []:
try:
user = get_user_from_name_id(uuid, raise_on_missing=True)
except User.DoesNotExist:
missing.append(uuid)
else:
users.append(user)
founded.append(uuid)
attrs['users'] = users
attrs['founded_uuids'] = founded
attrs['missing_uuids'] = missing
return attrs
class Add(GenericAPIView):
@ -42,25 +67,41 @@ class Add(GenericAPIView):
if not serializer.is_valid():
response = {'err': 1, 'err_desc': serializer.errors}
return Response(response, status.HTTP_400_BAD_REQUEST)
data = serializer.validated_data
payload = serializer.validated_data
notification_ids = []
try:
notification = Notification.notify(
user=request.user,
summary=data['summary'],
id=data.get('id'),
body=data.get('body'),
url=data.get('url'),
origin=data.get('origin'),
start_timestamp=data.get('start_timestamp'),
end_timestamp=data.get('end_timestamp'),
duration=data.get('duration'),
)
with transaction.atomic():
for user in payload.get('users') or [request.user]:
notification = Notification.notify(
user=user,
summary=payload['summary'],
id=payload.get('id'),
body=payload.get('body'),
url=payload.get('url'),
origin=payload.get('origin'),
start_timestamp=payload.get('start_timestamp'),
end_timestamp=payload.get('end_timestamp'),
duration=payload.get('duration'),
)
notification_ids.append(notification.public_id)
except ValueError as e:
response = {'err': 1, 'err_desc': {'id': [force_text(e)]}}
return Response(response, status.HTTP_400_BAD_REQUEST)
data = {}
if not payload.get('name_ids'):
data = {'id': notification_ids.pop()}
else:
response = {'err': 0, 'data': {'id': notification.public_id}}
return Response(response)
data = {
'nb_notify': len(notification_ids),
'notified': payload.get('founded_uuids'),
'unnotified': payload.get('missing_uuids'),
}
if payload.get('id'):
data['id'] = payload.get('id')
else:
data['ids'] = notification_ids
return Response({'err': 0, 'data': data})
add = Add.as_view()

View File

@ -10,6 +10,7 @@ from django.test.client import RequestFactory
from django.urls import reverse
from django.utils.encoding import force_text
from django.utils.timezone import now
from mellon.models import UserSAMLIdentifier
from combo.apps.lingo.models import ActiveItems, PaymentBackend, Regie
from combo.apps.notifications.models import Notification, NotificationsCell
@ -518,3 +519,72 @@ def test_notification_never_expire(app, freezer, rf, john_doe):
assert Notification.objects.visible(john_doe).count() == 1
assert 'notibar' in content
assert 'notifoo' not in content
def test_notification_ws_create_many(john_doe, jane_doe):
UserSAMLIdentifier.objects.create(user=john_doe, name_id='00a')
UserSAMLIdentifier.objects.create(user=jane_doe, name_id='00b')
login(john_doe)
data = {'summary': 'foo', 'name_ids': ['00a', '00b']}
resp = client.post(reverse('api-notification-add'), json.dumps(data), content_type='application/json')
assert resp.status_code == 200
assert len(resp.json()['data']['ids']) == 2
assert Notification.objects.count() == 2
assert Notification.objects.get(user=john_doe, id=resp.json()['data']['ids'][0]).summary == 'foo'
assert Notification.objects.get(user=jane_doe, id=resp.json()['data']['ids'][1]).summary == 'foo'
resp.json()['data']['ids'] = ['xx', 'yy']
assert resp.json() == {
'err': 0,
'data': {'nb_notify': 2, 'notified': ['00a', '00b'], 'unnotified': [], 'ids': ['xx', 'yy']},
}
# wrong username
data = {'summary': 'bar', 'name_ids': ['00a', 'unknown']}
resp = client.post(reverse('api-notification-add'), json.dumps(data), content_type='application/json')
assert resp.status_code == 200
assert len(resp.json()['data']['ids']) == 1
assert Notification.objects.count() == 3
assert Notification.objects.get(user=john_doe, id=resp.json()['data']['ids'][0]).summary == 'bar'
resp.json()['data']['ids'] = ['xx']
assert resp.json() == {
'err': 0,
'data': {'nb_notify': 1, 'notified': ['00a'], 'unnotified': ['unknown'], 'ids': ['xx']},
}
def test_notification_ws_update_many(john_doe, jane_doe):
UserSAMLIdentifier.objects.create(user=john_doe, name_id='00a')
UserSAMLIdentifier.objects.create(user=jane_doe, name_id='00b')
login(john_doe)
data = {
'summary': 'foo',
'name_ids': ['00a', '00b'],
'id': 'test:42',
}
resp = client.post(reverse('api-notification-add'), json.dumps(data), content_type='application/json')
assert resp.status_code == 200
result = resp.json()
assert resp.json() == {
'err': 0,
'data': {'nb_notify': 2, 'notified': ['00a', '00b'], 'unnotified': [], 'id': 'test:42'},
}
assert Notification.objects.count() == 2
assert Notification.objects.get(user=john_doe, external_id='test:42').summary == 'foo'
assert Notification.objects.get(user=jane_doe, external_id='test:42').summary == 'foo'
data['summary'] = 'bar'
resp = client.post(reverse('api-notification-add'), json.dumps(data), content_type='application/json')
assert resp.status_code == 200
assert resp.json() == {
'err': 0,
'data': {'nb_notify': 2, 'notified': ['00a', '00b'], 'unnotified': [], 'id': 'test:42'},
}
result = resp.json()
assert result['err'] == 0
assert result['data']['nb_notify'] == 2
assert result['data']['id'] == 'test:42'
assert Notification.objects.count() == 2
assert Notification.objects.get(user=john_doe, external_id='test:42').summary == 'bar'
assert Notification.objects.get(user=jane_doe, external_id='test:42').summary == 'bar'