api: filter by subscriptions in multiple agendas datetimes (#58446)
This commit is contained in:
parent
0e4689a139
commit
97b0b899af
|
@ -33,7 +33,7 @@ from django.contrib.postgres.fields import ArrayField, JSONField
|
||||||
from django.core.exceptions import FieldDoesNotExist, ValidationError
|
from django.core.exceptions import FieldDoesNotExist, ValidationError
|
||||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||||
from django.db import IntegrityError, connection, models, transaction
|
from django.db import IntegrityError, connection, models, transaction
|
||||||
from django.db.models import Count, Max, Prefetch, Q
|
from django.db.models import Count, F, Max, Prefetch, Q
|
||||||
from django.template import Context, Template, TemplateSyntaxError, VariableDoesNotExist, engines
|
from django.template import Context, Template, TemplateSyntaxError, VariableDoesNotExist, engines
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import functional
|
from django.utils import functional
|
||||||
|
@ -901,7 +901,12 @@ class Agenda(models.Model):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def prefetch_events_and_exceptions(
|
def prefetch_events_and_exceptions(
|
||||||
qs, user_external_id=None, show_past_events=False, min_start=None, max_start=None
|
qs,
|
||||||
|
user_external_id=None,
|
||||||
|
show_past_events=False,
|
||||||
|
show_only_subscribed=False,
|
||||||
|
min_start=None,
|
||||||
|
max_start=None,
|
||||||
):
|
):
|
||||||
event_queryset = Event.objects.filter(
|
event_queryset = Event.objects.filter(
|
||||||
Q(publication_datetime__isnull=True) | Q(publication_datetime__lte=now()),
|
Q(publication_datetime__isnull=True) | Q(publication_datetime__lte=now()),
|
||||||
|
@ -917,6 +922,12 @@ class Agenda(models.Model):
|
||||||
event_queryset = event_queryset.filter(start_datetime__gte=min_start)
|
event_queryset = event_queryset.filter(start_datetime__gte=min_start)
|
||||||
if max_start:
|
if max_start:
|
||||||
event_queryset = event_queryset.filter(start_datetime__lt=max_start)
|
event_queryset = event_queryset.filter(start_datetime__lt=max_start)
|
||||||
|
if show_only_subscribed:
|
||||||
|
event_queryset = event_queryset.filter(
|
||||||
|
agenda__subscriptions__user_external_id=user_external_id,
|
||||||
|
agenda__subscriptions__date_start__lt=F('start_datetime'),
|
||||||
|
agenda__subscriptions__date_end__gt=F('start_datetime'),
|
||||||
|
)
|
||||||
|
|
||||||
exceptions_desk = Desk.objects.filter(slug='_exceptions_holder').prefetch_related(
|
exceptions_desk = Desk.objects.filter(slug='_exceptions_holder').prefetch_related(
|
||||||
'unavailability_calendars'
|
'unavailability_calendars'
|
||||||
|
@ -934,6 +945,7 @@ class Agenda(models.Model):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
qs = Agenda.prefetch_recurring_events(qs)
|
qs = Agenda.prefetch_recurring_events(qs)
|
||||||
|
qs = qs.select_related('category')
|
||||||
agendas_exceptions = TimePeriodException.objects.filter(
|
agendas_exceptions = TimePeriodException.objects.filter(
|
||||||
Q(desk__slug='_exceptions_holder', desk__agenda__in=qs)
|
Q(desk__slug='_exceptions_holder', desk__agenda__in=qs)
|
||||||
| Q(
|
| Q(
|
||||||
|
|
|
@ -8,6 +8,16 @@ from rest_framework.exceptions import ValidationError
|
||||||
from chrono.agendas.models import AbsenceReason, Agenda, Booking, Category, Event, Subscription
|
from chrono.agendas.models import AbsenceReason, Agenda, Booking, Category, Event, Subscription
|
||||||
|
|
||||||
|
|
||||||
|
def get_objects_from_slugs(slugs, qs):
|
||||||
|
slugs = set(slugs)
|
||||||
|
objects = qs.filter(slug__in=slugs)
|
||||||
|
if len(objects) != len(slugs):
|
||||||
|
unknown_slugs = sorted(slugs - {obj.slug for obj in objects})
|
||||||
|
unknown_slugs = ', '.join(unknown_slugs)
|
||||||
|
raise ValidationError(('invalid slugs: %s') % unknown_slugs)
|
||||||
|
return objects
|
||||||
|
|
||||||
|
|
||||||
class StringOrListField(serializers.ListField):
|
class StringOrListField(serializers.ListField):
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
if isinstance(data, str):
|
if isinstance(data, str):
|
||||||
|
@ -190,10 +200,41 @@ class DatetimesSerializer(DateRangeSerializer):
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
class MultipleAgendasDatetimesSerializer(DatetimesSerializer):
|
class AgendaOrSubscribedSlugsMixin(metaclass=serializers.SerializerMetaclass):
|
||||||
agendas = CommaSeparatedStringField(
|
agendas = CommaSeparatedStringField(
|
||||||
required=True, child=serializers.SlugField(max_length=160, allow_blank=False)
|
required=False, child=serializers.SlugField(max_length=160, allow_blank=False)
|
||||||
)
|
)
|
||||||
|
subscribed = CommaSeparatedStringField(
|
||||||
|
required=False, child=serializers.SlugField(max_length=160, allow_blank=False)
|
||||||
|
)
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
super().validate(attrs)
|
||||||
|
if 'agendas' not in attrs and 'subscribed' not in attrs:
|
||||||
|
raise ValidationError(_('Either "agendas" or "subscribed" parameter is required.'))
|
||||||
|
if 'agendas' in attrs and 'subscribed' in attrs:
|
||||||
|
raise ValidationError(_('"agendas" and "subscribed" parameters are mutually exclusive.'))
|
||||||
|
user_external_id = attrs.get('user_external_id')
|
||||||
|
if 'subscribed' in attrs and not user_external_id:
|
||||||
|
raise ValidationError(
|
||||||
|
{'user_external_id': _('This field is required when using "subscribed" parameter.')}
|
||||||
|
)
|
||||||
|
|
||||||
|
if 'subscribed' in attrs:
|
||||||
|
agendas = Agenda.objects.filter(subscriptions__user_external_id=user_external_id).distinct()
|
||||||
|
if attrs['subscribed'] != ['all']:
|
||||||
|
agendas = agendas.filter(category__slug__in=attrs['subscribed'])
|
||||||
|
attrs['agendas'] = agendas
|
||||||
|
else:
|
||||||
|
attrs['agenda_slugs'] = self.agenda_slugs
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
def validate_agendas(self, value):
|
||||||
|
self.agenda_slugs = value
|
||||||
|
return get_objects_from_slugs(value, qs=Agenda.objects.filter(kind='events'))
|
||||||
|
|
||||||
|
|
||||||
|
class MultipleAgendasDatetimesSerializer(AgendaOrSubscribedSlugsMixin, DatetimesSerializer):
|
||||||
show_past_events = serializers.BooleanField(default=False)
|
show_past_events = serializers.BooleanField(default=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -875,9 +875,7 @@ class MultipleAgendasDatetimes(APIView):
|
||||||
raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors)
|
raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors)
|
||||||
payload = serializer.validated_data
|
payload = serializer.validated_data
|
||||||
|
|
||||||
agenda_slugs = payload['agendas']
|
agendas = payload['agendas']
|
||||||
agendas = get_objects_from_slugs(agenda_slugs, qs=Agenda.objects.filter(kind='events'))
|
|
||||||
|
|
||||||
user_external_id = payload.get('user_external_id') or payload.get('exclude_user_external_id')
|
user_external_id = payload.get('user_external_id') or payload.get('exclude_user_external_id')
|
||||||
disable_booked = bool(payload.get('exclude_user_external_id'))
|
disable_booked = bool(payload.get('exclude_user_external_id'))
|
||||||
show_past_events = bool(payload.get('show_past_events'))
|
show_past_events = bool(payload.get('show_past_events'))
|
||||||
|
@ -885,6 +883,7 @@ class MultipleAgendasDatetimes(APIView):
|
||||||
agendas,
|
agendas,
|
||||||
user_external_id=user_external_id,
|
user_external_id=user_external_id,
|
||||||
show_past_events=show_past_events,
|
show_past_events=show_past_events,
|
||||||
|
show_only_subscribed=bool('subscribed' in payload),
|
||||||
min_start=payload.get('date_start'),
|
min_start=payload.get('date_start'),
|
||||||
max_start=payload.get('date_end'),
|
max_start=payload.get('date_end'),
|
||||||
)
|
)
|
||||||
|
@ -909,8 +908,28 @@ class MultipleAgendasDatetimes(APIView):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
agenda_querystring_indexes = {agenda_slug: i for i, agenda_slug in enumerate(agenda_slugs)}
|
if 'agendas' in request.query_params:
|
||||||
entries.sort(key=lambda event: (event.start_datetime, agenda_querystring_indexes[event.agenda.slug]))
|
agenda_querystring_indexes = {
|
||||||
|
agenda_slug: i for i, agenda_slug in enumerate(payload['agenda_slugs'])
|
||||||
|
}
|
||||||
|
entries.sort(
|
||||||
|
key=lambda event: (
|
||||||
|
event.start_datetime,
|
||||||
|
agenda_querystring_indexes[event.agenda.slug],
|
||||||
|
event.slug,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif 'subscribed' in request.query_params:
|
||||||
|
category_querystring_indexes = {category: i for i, category in enumerate(payload['subscribed'])}
|
||||||
|
sort_by_category = bool(payload['subscribed'] != ['all'])
|
||||||
|
entries.sort(
|
||||||
|
key=lambda event: (
|
||||||
|
event.start_datetime,
|
||||||
|
category_querystring_indexes[event.agenda.category.slug] if sort_by_category else None,
|
||||||
|
event.agenda.slug,
|
||||||
|
event.slug,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
'data': [
|
'data': [
|
||||||
|
|
|
@ -7,7 +7,7 @@ from django.test import override_settings
|
||||||
from django.test.utils import CaptureQueriesContext
|
from django.test.utils import CaptureQueriesContext
|
||||||
from django.utils.timezone import localtime, make_aware, make_naive, now
|
from django.utils.timezone import localtime, make_aware, make_naive, now
|
||||||
|
|
||||||
from chrono.agendas.models import Agenda, Booking, Desk, Event, TimePeriodException
|
from chrono.agendas.models import Agenda, Booking, Category, Desk, Event, Subscription, TimePeriodException
|
||||||
|
|
||||||
pytestmark = pytest.mark.django_db
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
@ -1584,10 +1584,14 @@ def test_datetimes_multiple_agendas(app):
|
||||||
|
|
||||||
# invalid slugs
|
# invalid slugs
|
||||||
resp = app.get('/api/agendas/datetimes/', params={'agendas': 'xxx'}, status=400)
|
resp = app.get('/api/agendas/datetimes/', params={'agendas': 'xxx'}, status=400)
|
||||||
assert resp.json['err_desc'] == 'invalid slugs: xxx'
|
assert resp.json['errors']['agendas'][0] == 'invalid slugs: xxx'
|
||||||
|
|
||||||
resp = app.get('/api/agendas/datetimes/', params={'agendas': 'first-agenda,xxx,yyy'}, status=400)
|
resp = app.get('/api/agendas/datetimes/', params={'agendas': 'first-agenda,xxx,yyy'}, status=400)
|
||||||
assert resp.json['err_desc'] == 'invalid slugs: xxx, yyy'
|
assert resp.json['errors']['agendas'][0] == 'invalid slugs: xxx, yyy'
|
||||||
|
|
||||||
|
# missing agendas parameter
|
||||||
|
resp = app.get('/api/agendas/datetimes/', params={}, status=400)
|
||||||
|
assert resp.json['err_desc'] == 'invalid payload'
|
||||||
|
|
||||||
# it's possible to show past events
|
# it's possible to show past events
|
||||||
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'show_past_events': True})
|
resp = app.get('/api/agendas/datetimes/', params={'agendas': agenda_slugs, 'show_past_events': True})
|
||||||
|
@ -1720,17 +1724,26 @@ def test_datetimes_multiple_agendas(app):
|
||||||
|
|
||||||
@pytest.mark.freeze_time('2021-05-06 14:00')
|
@pytest.mark.freeze_time('2021-05-06 14:00')
|
||||||
def test_datetimes_multiple_agendas_sort(app):
|
def test_datetimes_multiple_agendas_sort(app):
|
||||||
first_agenda = Agenda.objects.create(label='First agenda', kind='events')
|
category = Category.objects.create(label='Category A')
|
||||||
|
first_agenda = Agenda.objects.create(label='First agenda', kind='events', category=category)
|
||||||
Desk.objects.create(agenda=first_agenda, slug='_exceptions_holder')
|
Desk.objects.create(agenda=first_agenda, slug='_exceptions_holder')
|
||||||
Event.objects.create(label='10-05', start_datetime=now().replace(day=10), places=5, agenda=first_agenda)
|
Event.objects.create(label='10-05', start_datetime=now().replace(day=10), places=5, agenda=first_agenda)
|
||||||
second_agenda = Agenda.objects.create(label='Second agenda', kind='events')
|
second_agenda = Agenda.objects.create(label='Second agenda', kind='events', category=category)
|
||||||
Desk.objects.create(agenda=second_agenda, slug='_exceptions_holder')
|
Desk.objects.create(agenda=second_agenda, slug='_exceptions_holder')
|
||||||
Event.objects.create(label='09-05', start_datetime=now().replace(day=9), places=5, agenda=second_agenda)
|
Event.objects.create(label='09-05', start_datetime=now().replace(day=9), places=5, agenda=second_agenda)
|
||||||
Event.objects.create(label='04-05', start_datetime=now().replace(day=4), places=5, agenda=second_agenda)
|
Event.objects.create(label='04-05', start_datetime=now().replace(day=4), places=5, agenda=second_agenda)
|
||||||
third_agenda = Agenda.objects.create(label='Third agenda', kind='events')
|
category = Category.objects.create(label='Category B')
|
||||||
|
third_agenda = Agenda.objects.create(label='Third agenda', kind='events', category=category)
|
||||||
Desk.objects.create(agenda=third_agenda, slug='_exceptions_holder')
|
Desk.objects.create(agenda=third_agenda, slug='_exceptions_holder')
|
||||||
Event.objects.create(label='09-05', start_datetime=now().replace(day=9), places=5, agenda=third_agenda)
|
Event.objects.create(label='09-05', start_datetime=now().replace(day=9), places=5, agenda=third_agenda)
|
||||||
Event.objects.create(label='04-05', start_datetime=now().replace(day=4), places=5, agenda=third_agenda)
|
Event.objects.create(label='04-05', start_datetime=now().replace(day=4), places=5, agenda=third_agenda)
|
||||||
|
for agenda in Agenda.objects.all():
|
||||||
|
Subscription.objects.create(
|
||||||
|
agenda=agenda,
|
||||||
|
user_external_id='xxx',
|
||||||
|
date_start=now(),
|
||||||
|
date_end=now() + datetime.timedelta(days=30),
|
||||||
|
)
|
||||||
|
|
||||||
# check events are ordered by start_datetime and then by agenda order in querystring
|
# check events are ordered by start_datetime and then by agenda order in querystring
|
||||||
agenda_slugs = ','.join((first_agenda.slug, third_agenda.slug, second_agenda.slug))
|
agenda_slugs = ','.join((first_agenda.slug, third_agenda.slug, second_agenda.slug))
|
||||||
|
@ -1748,11 +1761,45 @@ def test_datetimes_multiple_agendas_sort(app):
|
||||||
assert resp.json['data'][3]['id'] == 'second-agenda@09-05'
|
assert resp.json['data'][3]['id'] == 'second-agenda@09-05'
|
||||||
assert resp.json['data'][4]['id'] == 'first-agenda@10-05'
|
assert resp.json['data'][4]['id'] == 'first-agenda@10-05'
|
||||||
|
|
||||||
|
# check subscribed events are ordered by start_datetime
|
||||||
|
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
|
||||||
|
assert len(resp.json['data']) == 3
|
||||||
|
assert resp.json['data'][0]['id'] == 'second-agenda@09-05'
|
||||||
|
assert resp.json['data'][1]['id'] == 'third-agenda@09-05'
|
||||||
|
assert resp.json['data'][2]['id'] == 'first-agenda@10-05'
|
||||||
|
|
||||||
|
# and by category slug if specified in querystring
|
||||||
|
resp = app.get(
|
||||||
|
'/api/agendas/datetimes/', params={'subscribed': 'category-b,category-a', 'user_external_id': 'xxx'}
|
||||||
|
)
|
||||||
|
assert len(resp.json['data']) == 3
|
||||||
|
assert resp.json['data'][0]['id'] == 'third-agenda@09-05'
|
||||||
|
assert resp.json['data'][1]['id'] == 'second-agenda@09-05'
|
||||||
|
assert resp.json['data'][2]['id'] == 'first-agenda@10-05'
|
||||||
|
|
||||||
|
# order is stable if same date events are in the same category
|
||||||
|
Event.objects.create(label='09-05', start_datetime=now().replace(day=9), places=5, agenda=first_agenda)
|
||||||
|
resp = app.get(
|
||||||
|
'/api/agendas/datetimes/', params={'subscribed': 'category-b,category-a', 'user_external_id': 'xxx'}
|
||||||
|
)
|
||||||
|
assert len(resp.json['data']) == 4
|
||||||
|
assert resp.json['data'][0]['id'] == 'third-agenda@09-05'
|
||||||
|
assert resp.json['data'][1]['id'] == 'first-agenda@09-05'
|
||||||
|
assert resp.json['data'][2]['id'] == 'second-agenda@09-05'
|
||||||
|
assert resp.json['data'][3]['id'] == 'first-agenda@10-05'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.freeze_time('2021-05-06 14:00')
|
@pytest.mark.freeze_time('2021-05-06 14:00')
|
||||||
def test_datetimes_multiple_agendas_queries(app):
|
def test_datetimes_multiple_agendas_queries(app):
|
||||||
|
category = Category.objects.create(label='Category A')
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
agenda = Agenda.objects.create(label=str(i), kind='events')
|
agenda = Agenda.objects.create(label=str(i), kind='events', category=category)
|
||||||
|
Subscription.objects.create(
|
||||||
|
agenda=agenda,
|
||||||
|
user_external_id='xxx',
|
||||||
|
date_start=now() - datetime.timedelta(days=10),
|
||||||
|
date_end=now() + datetime.timedelta(days=10),
|
||||||
|
)
|
||||||
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
||||||
Event.objects.create(start_datetime=now() - datetime.timedelta(days=5), places=5, agenda=agenda)
|
Event.objects.create(start_datetime=now() - datetime.timedelta(days=5), places=5, agenda=agenda)
|
||||||
Event.objects.create(start_datetime=now() + datetime.timedelta(days=5), places=5, agenda=agenda)
|
Event.objects.create(start_datetime=now() + datetime.timedelta(days=5), places=5, agenda=agenda)
|
||||||
|
@ -1765,3 +1812,133 @@ def test_datetimes_multiple_agendas_queries(app):
|
||||||
)
|
)
|
||||||
assert len(resp.json['data']) == 30
|
assert len(resp.json['data']) == 30
|
||||||
assert len(ctx.captured_queries) == 7
|
assert len(ctx.captured_queries) == 7
|
||||||
|
|
||||||
|
with CaptureQueriesContext(connection) as ctx:
|
||||||
|
resp = app.get(
|
||||||
|
'/api/agendas/datetimes/',
|
||||||
|
params={'subscribed': 'all', 'user_external_id': 'xxx', 'show_past_events': True},
|
||||||
|
)
|
||||||
|
assert len(resp.json['data']) == 30
|
||||||
|
assert len(ctx.captured_queries) == 7
|
||||||
|
|
||||||
|
with CaptureQueriesContext(connection) as ctx:
|
||||||
|
resp = app.get(
|
||||||
|
'/api/agendas/datetimes/',
|
||||||
|
params={'subscribed': 'category-a', 'user_external_id': 'xxx', 'show_past_events': True},
|
||||||
|
)
|
||||||
|
assert len(resp.json['data']) == 30
|
||||||
|
assert len(ctx.captured_queries) == 7
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.freeze_time('2021-05-06 14:00')
|
||||||
|
def test_datetimes_multiple_agendas_subscribed(app):
|
||||||
|
first_agenda = Agenda.objects.create(label='First agenda', kind='events')
|
||||||
|
Desk.objects.create(agenda=first_agenda, slug='_exceptions_holder')
|
||||||
|
Event.objects.create(
|
||||||
|
slug='event',
|
||||||
|
start_datetime=now() + datetime.timedelta(days=5),
|
||||||
|
places=5,
|
||||||
|
agenda=first_agenda,
|
||||||
|
)
|
||||||
|
Event.objects.create(
|
||||||
|
slug='event-2',
|
||||||
|
start_datetime=now() + datetime.timedelta(days=20),
|
||||||
|
places=5,
|
||||||
|
agenda=first_agenda,
|
||||||
|
)
|
||||||
|
category = Category.objects.create(label='Category A')
|
||||||
|
second_agenda = Agenda.objects.create(
|
||||||
|
label='Second agenda', kind='events', category=category, maximal_booking_delay=400
|
||||||
|
)
|
||||||
|
Desk.objects.create(agenda=second_agenda, slug='_exceptions_holder')
|
||||||
|
Event.objects.create(
|
||||||
|
slug='event',
|
||||||
|
start_datetime=now() + datetime.timedelta(days=20),
|
||||||
|
places=5,
|
||||||
|
agenda=second_agenda,
|
||||||
|
)
|
||||||
|
Event.objects.create(
|
||||||
|
slug='next-year-event',
|
||||||
|
start_datetime=now() + datetime.timedelta(days=365),
|
||||||
|
places=5,
|
||||||
|
agenda=second_agenda,
|
||||||
|
)
|
||||||
|
Subscription.objects.create(
|
||||||
|
agenda=first_agenda,
|
||||||
|
user_external_id='yyy',
|
||||||
|
date_start=now(),
|
||||||
|
date_end=now() + datetime.timedelta(days=10),
|
||||||
|
)
|
||||||
|
|
||||||
|
# no subscription for user xxx
|
||||||
|
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
|
||||||
|
assert len(resp.json['data']) == 0
|
||||||
|
|
||||||
|
# add subscription to first agenda
|
||||||
|
Subscription.objects.create(
|
||||||
|
agenda=first_agenda,
|
||||||
|
user_external_id='xxx',
|
||||||
|
date_start=now(),
|
||||||
|
date_end=now() + datetime.timedelta(days=10),
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
|
||||||
|
assert len(resp.json['data']) == 1
|
||||||
|
assert resp.json['data'][0]['id'] == 'first-agenda@event'
|
||||||
|
|
||||||
|
# no subscription to second agenda
|
||||||
|
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'category-a', 'user_external_id': 'xxx'})
|
||||||
|
assert len(resp.json['data']) == 0
|
||||||
|
|
||||||
|
# add subscription to second agenda
|
||||||
|
Subscription.objects.create(
|
||||||
|
agenda=second_agenda,
|
||||||
|
user_external_id='xxx',
|
||||||
|
date_start=now() + datetime.timedelta(days=15),
|
||||||
|
date_end=now() + datetime.timedelta(days=25),
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'category-a', 'user_external_id': 'xxx'})
|
||||||
|
assert len(resp.json['data']) == 1
|
||||||
|
assert resp.json['data'][0]['id'] == 'second-agenda@event'
|
||||||
|
|
||||||
|
# add new subscription (disjoint) to second agenda
|
||||||
|
Subscription.objects.create(
|
||||||
|
agenda=second_agenda,
|
||||||
|
user_external_id='xxx',
|
||||||
|
date_start=now() + datetime.timedelta(days=355),
|
||||||
|
date_end=now() + datetime.timedelta(days=375),
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'category-a', 'user_external_id': 'xxx'})
|
||||||
|
assert len(resp.json['data']) == 2
|
||||||
|
assert resp.json['data'][0]['id'] == 'second-agenda@event'
|
||||||
|
assert resp.json['data'][1]['id'] == 'second-agenda@next-year-event'
|
||||||
|
|
||||||
|
# view events from all subscriptions
|
||||||
|
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
|
||||||
|
assert len(resp.json['data']) == 3
|
||||||
|
assert resp.json['data'][0]['id'] == 'first-agenda@event'
|
||||||
|
assert resp.json['data'][1]['id'] == 'second-agenda@event'
|
||||||
|
assert resp.json['data'][2]['id'] == 'second-agenda@next-year-event'
|
||||||
|
|
||||||
|
# overlapping subscription changes nothing
|
||||||
|
Subscription.objects.create(
|
||||||
|
agenda=first_agenda,
|
||||||
|
user_external_id='xxx',
|
||||||
|
date_start=now() + datetime.timedelta(days=1),
|
||||||
|
date_end=now() + datetime.timedelta(days=11),
|
||||||
|
)
|
||||||
|
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all', 'user_external_id': 'xxx'})
|
||||||
|
assert len(resp.json['data']) == 3
|
||||||
|
|
||||||
|
# check errors
|
||||||
|
resp = app.get('/api/agendas/datetimes/', params={'subscribed': 'all'}, status=400)
|
||||||
|
assert 'required' in resp.json['errors']['user_external_id'][0]
|
||||||
|
|
||||||
|
resp = app.get(
|
||||||
|
'/api/agendas/datetimes/',
|
||||||
|
params={'subscribed': 'all', 'agendas': 'first-agenda', 'user_external_id': 'xxx'},
|
||||||
|
status=400,
|
||||||
|
)
|
||||||
|
assert 'mutually exclusive' in resp.json['errors']['non_field_errors'][0]
|
||||||
|
|
|
@ -2664,7 +2664,7 @@ def test_api_events_fillslots_multiple_agendas(app, user):
|
||||||
resp = app.post_json(
|
resp = app.post_json(
|
||||||
'/api/agendas/events/fillslots/?agendas=first-agenda,xxx,yyy', params=params, status=400
|
'/api/agendas/events/fillslots/?agendas=first-agenda,xxx,yyy', params=params, status=400
|
||||||
)
|
)
|
||||||
assert resp.json['err_desc'] == 'invalid slugs: xxx, yyy'
|
assert resp.json['errors']['agendas'][0] == 'invalid slugs: xxx, yyy'
|
||||||
|
|
||||||
# invalid agenda slugs in payload
|
# invalid agenda slugs in payload
|
||||||
params = {'user_external_id': 'user_id_3', 'slots': 'first-agenda@event,xxx@event,yyy@event'}
|
params = {'user_external_id': 'user_id_3', 'slots': 'first-agenda@event,xxx@event,yyy@event'}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from chrono.agendas.models import Agenda
|
from chrono.agendas.models import Agenda, MeetingType
|
||||||
from chrono.api.utils import Response
|
from chrono.api.utils import Response
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,6 +31,10 @@ def test_err_desc_translation(db, app, settings):
|
||||||
assert resp.json['err_desc'] == 'contenu de requête invalide'
|
assert resp.json['err_desc'] == 'contenu de requête invalide'
|
||||||
assert resp.json['err_class'] == 'invalid payload'
|
assert resp.json['err_class'] == 'invalid payload'
|
||||||
|
|
||||||
resp = app.get('/api/agendas/datetimes/?agendas=hop', status=400)
|
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
||||||
|
meeting_type = MeetingType.objects.create(agenda=agenda, slug='foo', duration=60)
|
||||||
|
resp = app.get(
|
||||||
|
'/api/agenda/%s/meetings/%s/datetimes/?resources=hop' % (agenda.slug, meeting_type.slug), status=400
|
||||||
|
)
|
||||||
assert resp.json['err_desc'] == 'slugs invalides : hop'
|
assert resp.json['err_desc'] == 'slugs invalides : hop'
|
||||||
assert resp.json['err_class'] == 'invalid slugs: hop'
|
assert resp.json['err_class'] == 'invalid slugs: hop'
|
||||||
|
|
Loading…
Reference in New Issue