api: return only agenda with open events (#44294)

This commit is contained in:
Lauréline Guérin 2020-08-31 14:37:43 +02:00
parent 6fdb1bf4c5
commit eb8026c790
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
3 changed files with 112 additions and 20 deletions

View File

@ -462,29 +462,36 @@ class Agenda(models.Model):
for weektime_interval in IntervalSet.simple(*time_period_interval) - closed_hours_by_days:
yield SharedTimePeriod.from_weektime_interval(weektime_interval, desks=desks)
def get_open_events(self):
def get_open_events(self, prefetched_queryset=False):
assert self.kind == 'events'
entries = self.event_set.all()
entries = self.event_set.filter(cancelled=False)
# we never want to allow booking for past events.
entries = entries.filter(start_datetime__gte=localtime(now()))
# exclude non published events
entries = entries.filter(
Q(publication_date__isnull=True) | Q(publication_date__lte=localtime(now()).date())
)
if prefetched_queryset:
entries = self.prefetched_events
else:
entries = self.event_set.filter(cancelled=False)
# we never want to allow booking for past events.
entries = entries.filter(start_datetime__gte=localtime(now()))
# exclude non published events
entries = entries.filter(
Q(publication_date__isnull=True) | Q(publication_date__lte=localtime(now()).date())
)
if self.minimal_booking_delay:
entries = entries.filter(
start_datetime__gte=localtime(
now() + datetime.timedelta(days=self.minimal_booking_delay)
).replace(hour=0, minute=0)
min_start = localtime(now() + datetime.timedelta(days=self.minimal_booking_delay)).replace(
hour=0, minute=0
)
if prefetched_queryset:
entries = [e for e in entries if e.start_datetime >= min_start]
else:
entries = entries.filter(start_datetime__gte=min_start)
if self.maximal_booking_delay:
entries = entries.filter(
start_datetime__lt=localtime(
now() + datetime.timedelta(days=self.maximal_booking_delay)
).replace(hour=0, minute=0)
max_start = localtime(now() + datetime.timedelta(days=self.maximal_booking_delay)).replace(
hour=0, minute=0
)
if prefetched_queryset:
entries = [e for e in entries if e.start_datetime < max_start]
else:
entries = entries.filter(start_datetime__lt=max_start)
return entries

View File

@ -21,6 +21,7 @@ import uuid
from django.db import transaction
from django.db.models import Prefetch, Q
from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404
from django.urls import reverse
@ -349,11 +350,33 @@ class Agendas(APIView):
def get(self, request, format=None):
agendas_queryset = Agenda.objects.all().prefetch_related('resources').order_by('label')
if 'q' in request.GET:
if not request.GET['q']:
return Response({'data': []})
agendas_queryset = agendas_queryset.filter(slug__icontains=request.GET['q'])
agendas = [get_agenda_detail(request, agenda) for agenda in agendas_queryset]
with_open_events = request.GET.get('with_open_events') in ['1', 'true']
if with_open_events:
# return only events agenda
event_queryset = Event.objects.filter(
Q(publication_date__isnull=True) | Q(publication_date__lte=localtime(now()).date()),
cancelled=False,
start_datetime__gte=localtime(now()),
).order_by()
agendas_queryset = agendas_queryset.filter(kind='events').prefetch_related(
Prefetch('event_set', queryset=event_queryset, to_attr='prefetched_events',)
)
agendas = []
for agenda in agendas_queryset:
if with_open_events and not any(
not e.full for e in agenda.get_open_events(prefetched_queryset=True)
):
# exclude agendas without open events
continue
agendas.append(get_agenda_detail(request, agenda))
return Response({'data': agendas})

View File

@ -129,8 +129,8 @@ def virtual_meetings_agenda(meetings_agenda):
def test_agendas_api(app):
Agenda.objects.create(label='Foo bar')
Agenda.objects.create(label='Foo bar 2')
event_agenda = Agenda.objects.create(label='Foo bar')
event_agenda2 = Agenda.objects.create(label='Foo bar 2')
meetings_agenda1 = Agenda.objects.create(label='Foo bar Meeting', kind='meetings')
Agenda.objects.create(label='Foo bar Meeting 2', kind='meetings')
resource1 = Resource.objects.create(label='Resource 1', description='Foo bar Resource 1')
@ -228,6 +228,68 @@ def test_agendas_api(app):
resp = app.get('/api/agenda/', params={'q': 'MEET'})
assert len(ctx.captured_queries) == 2
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(resp.json['data']) == 0
first_date = localtime(now()).replace(hour=17, minute=0, second=0, microsecond=0)
first_date += datetime.timedelta(days=1)
event1 = Event.objects.create(
start_datetime=(now() + datetime.timedelta(days=5)).replace(hour=10, minute=0),
places=20,
agenda=event_agenda,
)
event2 = Event.objects.create(
start_datetime=(now() + datetime.timedelta(days=10)).replace(hour=10, minute=0),
places=20,
agenda=event_agenda,
)
event3 = Event.objects.create(
start_datetime=(now() + datetime.timedelta(days=15)).replace(hour=10, minute=0),
places=20,
agenda=event_agenda,
)
# all events are free
resp = app.get('/api/agenda/', params={'with_open_events': 'true'})
assert len(resp.json['data']) == 1
# one event is full
Event.objects.filter(pk=event1.pk).update(full=True)
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(resp.json['data']) == 1
# all events are full
Event.objects.update(full=True)
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(resp.json['data']) == 0
# event1 is not full but too soon
Event.objects.filter(pk=event1.pk).update(full=False)
event_agenda.minimal_booking_delay = 10
event_agenda.save()
assert list(event_agenda.get_open_events()) == [event2, event3]
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(resp.json['data']) == 0
# event3 is not full but too late
Event.objects.filter(pk=event3.pk).update(full=False)
event_agenda.maximal_booking_delay = 12
event_agenda.save()
assert list(event_agenda.get_open_events()) == [event2]
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(resp.json['data']) == 0
# events are not full but not published
Event.objects.update(full=False)
event_agenda.event_set.update(publication_date=now().date() + datetime.timedelta(days=20))
assert list(event_agenda.get_open_events()) == []
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(resp.json['data']) == 0
with CaptureQueriesContext(connection) as ctx:
resp = app.get('/api/agenda/', params={'with_open_events': '1'})
assert len(ctx.captured_queries) == 3
def test_agendas_meetingtypes_api(app, some_data, meetings_agenda):
resp = app.get('/api/agenda/%s/meetings/' % meetings_agenda.slug)