Projet

Général

Profil

0001-api-return-only-agenda-with-open-events-44294.patch

Lauréline Guérin, 31 août 2020 14:38

Télécharger (8,35 ko)

Voir les différences:

Subject: [PATCH] api: return only agenda with open events (#44294)

 chrono/agendas/models.py | 41 ++++++++++++++-----------
 chrono/api/views.py      | 24 ++++++++++++++-
 tests/test_api.py        | 66 ++++++++++++++++++++++++++++++++++++++--
 3 files changed, 111 insertions(+), 20 deletions(-)
chrono/agendas/models.py
430 430
                for weektime_interval in IntervalSet.simple(*time_period_interval) - closed_hours_by_days:
431 431
                    yield SharedTimePeriod.from_weektime_interval(weektime_interval, desks=desks)
432 432

  
433
    def get_open_events(self):
433
    def get_open_events(self, prefetched_queryset=False):
434 434
        assert self.kind == 'events'
435 435

  
436
        entries = self.event_set.all()
437
        entries = self.event_set.filter(cancelled=False)
438
        # we never want to allow booking for past events.
439
        entries = entries.filter(start_datetime__gte=localtime(now()))
440
        # exclude non published events
441
        entries = entries.filter(
442
            Q(publication_date__isnull=True) | Q(publication_date__lte=localtime(now()).date())
443
        )
444
        if self.minimal_booking_delay:
436
        if prefetched_queryset:
437
            entries = self.prefetched_events
438
        else:
439
            entries = self.event_set.filter(cancelled=False)
440
            # we never want to allow booking for past events.
441
            entries = entries.filter(start_datetime__gte=localtime(now()))
442
            # exclude non published events
445 443
            entries = entries.filter(
446
                start_datetime__gte=localtime(
447
                    now() + datetime.timedelta(days=self.minimal_booking_delay)
448
                ).replace(hour=0, minute=0)
444
                Q(publication_date__isnull=True) | Q(publication_date__lte=localtime(now()).date())
449 445
            )
446

  
447
        if self.minimal_booking_delay:
448
            min_start = localtime(now() + datetime.timedelta(days=self.minimal_booking_delay)).replace(
449
                hour=0, minute=0
450
            )
451
            if prefetched_queryset:
452
                entries = [e for e in entries if e.start_datetime >= min_start]
453
            else:
454
                entries = entries.filter(start_datetime__gte=min_start)
450 455
        if self.maximal_booking_delay:
451
            entries = entries.filter(
452
                start_datetime__lt=localtime(
453
                    now() + datetime.timedelta(days=self.maximal_booking_delay)
454
                ).replace(hour=0, minute=0)
456
            max_start = localtime(now() + datetime.timedelta(days=self.maximal_booking_delay)).replace(
457
                hour=0, minute=0
455 458
            )
459
            if prefetched_queryset:
460
                entries = [e for e in entries if e.start_datetime < max_start]
461
            else:
462
                entries = entries.filter(start_datetime__lt=max_start)
456 463
        return entries
457 464

  
458 465

  
chrono/api/views.py
21 21

  
22 22

  
23 23
from django.db import transaction
24
from django.db.models import Prefetch, Q
24 25
from django.http import Http404, HttpResponse
25 26
from django.shortcuts import get_object_or_404
26 27
from django.urls import reverse
......
352 353

  
353 354
    def get(self, request, format=None):
354 355
        agendas_queryset = Agenda.objects.all().prefetch_related('resources').order_by('label')
356

  
355 357
        if 'q' in request.GET:
356 358
            if not request.GET['q']:
357 359
                return Response({'data': []})
358 360
            agendas_queryset = agendas_queryset.filter(slug__icontains=request.GET['q'])
359
        agendas = [get_agenda_detail(request, agenda) for agenda in agendas_queryset]
361

  
362
        if 'with_open_events' in request.GET:
363
            # return only events agenda
364
            event_queryset = Event.objects.filter(
365
                Q(publication_date__isnull=True) | Q(publication_date__lte=localtime(now()).date()),
366
                cancelled=False,
367
                start_datetime__gte=localtime(now()),
368
            ).order_by()
369
            agendas_queryset = agendas_queryset.filter(kind='events').prefetch_related(
370
                Prefetch('event_set', queryset=event_queryset, to_attr='prefetched_events',)
371
            )
372

  
373
        agendas = []
374
        for agenda in agendas_queryset:
375
            if 'with_open_events' in request.GET and not any(
376
                not e.full for e in agenda.get_open_events(prefetched_queryset=True)
377
            ):
378
                # exclude agendas without open events
379
                continue
380
            agendas.append(get_agenda_detail(request, agenda))
381

  
360 382
        return Response({'data': agendas})
361 383

  
362 384

  
tests/test_api.py
129 129

  
130 130

  
131 131
def test_agendas_api(app):
132
    Agenda.objects.create(label='Foo bar')
133
    Agenda.objects.create(label='Foo bar 2')
132
    event_agenda = Agenda.objects.create(label='Foo bar')
133
    event_agenda2 = Agenda.objects.create(label='Foo bar 2')
134 134
    meetings_agenda1 = Agenda.objects.create(label='Foo bar Meeting', kind='meetings')
135 135
    Agenda.objects.create(label='Foo bar Meeting 2', kind='meetings')
136 136
    resource1 = Resource.objects.create(label='Resource 1', description='Foo bar Resource 1')
......
228 228
        resp = app.get('/api/agenda/', params={'q': 'MEET'})
229 229
        assert len(ctx.captured_queries) == 2
230 230

  
231
    resp = app.get('/api/agenda/', params={'with_open_events': ''})
232
    assert len(resp.json['data']) == 0
233

  
234
    first_date = localtime(now()).replace(hour=17, minute=0, second=0, microsecond=0)
235
    first_date += datetime.timedelta(days=1)
236
    event1 = Event.objects.create(
237
        start_datetime=(now() + datetime.timedelta(days=5)).replace(hour=10, minute=0),
238
        places=20,
239
        agenda=event_agenda,
240
    )
241
    event2 = Event.objects.create(
242
        start_datetime=(now() + datetime.timedelta(days=10)).replace(hour=10, minute=0),
243
        places=20,
244
        agenda=event_agenda,
245
    )
246
    event3 = Event.objects.create(
247
        start_datetime=(now() + datetime.timedelta(days=15)).replace(hour=10, minute=0),
248
        places=20,
249
        agenda=event_agenda,
250
    )
251

  
252
    # all events are free
253
    resp = app.get('/api/agenda/', params={'with_open_events': ''})
254
    assert len(resp.json['data']) == 1
255

  
256
    # one event is full
257
    Event.objects.filter(pk=event1.pk).update(full=True)
258
    resp = app.get('/api/agenda/', params={'with_open_events': ''})
259
    assert len(resp.json['data']) == 1
260

  
261
    # all events are full
262
    Event.objects.update(full=True)
263
    resp = app.get('/api/agenda/', params={'with_open_events': ''})
264
    assert len(resp.json['data']) == 0
265

  
266
    # event1 is not full but too soon
267
    Event.objects.filter(pk=event1.pk).update(full=False)
268
    event_agenda.minimal_booking_delay = 10
269
    event_agenda.save()
270
    assert list(event_agenda.get_open_events()) == [event2, event3]
271
    resp = app.get('/api/agenda/', params={'with_open_events': ''})
272
    assert len(resp.json['data']) == 0
273

  
274
    # event3 is not full but too late
275
    Event.objects.filter(pk=event3.pk).update(full=False)
276
    event_agenda.maximal_booking_delay = 12
277
    event_agenda.save()
278
    assert list(event_agenda.get_open_events()) == [event2]
279
    resp = app.get('/api/agenda/', params={'with_open_events': ''})
280
    assert len(resp.json['data']) == 0
281

  
282
    # events are not full but not published
283
    Event.objects.update(full=False)
284
    event_agenda.event_set.update(publication_date=now().date() + datetime.timedelta(days=20))
285
    assert list(event_agenda.get_open_events()) == []
286
    resp = app.get('/api/agenda/', params={'with_open_events': ''})
287
    assert len(resp.json['data']) == 0
288

  
289
    with CaptureQueriesContext(connection) as ctx:
290
        resp = app.get('/api/agenda/', params={'with_open_events': ''})
291
        assert len(ctx.captured_queries) == 3
292

  
231 293

  
232 294
def test_agendas_meetingtypes_api(app, some_data, meetings_agenda):
233 295
    resp = app.get('/api/agenda/%s/meetings/' % meetings_agenda.slug)
234
-