Projet

Général

Profil

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

Lauréline Guérin, 28 septembre 2020 10:38

Télécharger (8,41 ko)

Voir les différences:

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

 chrono/agendas/models.py | 41 ++++++++++++++-----------
 chrono/api/views.py      | 25 ++++++++++++++-
 tests/test_api.py        | 66 ++++++++++++++++++++++++++++++++++++++--
 3 files changed, 112 insertions(+), 20 deletions(-)
chrono/agendas/models.py
462 462
                for weektime_interval in IntervalSet.simple(*time_period_interval) - closed_hours_by_days:
463 463
                    yield SharedTimePeriod.from_weektime_interval(weektime_interval, desks=desks)
464 464

  
465
    def get_open_events(self):
465
    def get_open_events(self, prefetched_queryset=False):
466 466
        assert self.kind == 'events'
467 467

  
468
        entries = self.event_set.all()
469
        entries = self.event_set.filter(cancelled=False)
470
        # we never want to allow booking for past events.
471
        entries = entries.filter(start_datetime__gte=localtime(now()))
472
        # exclude non published events
473
        entries = entries.filter(
474
            Q(publication_date__isnull=True) | Q(publication_date__lte=localtime(now()).date())
475
        )
476
        if self.minimal_booking_delay:
468
        if prefetched_queryset:
469
            entries = self.prefetched_events
470
        else:
471
            entries = self.event_set.filter(cancelled=False)
472
            # we never want to allow booking for past events.
473
            entries = entries.filter(start_datetime__gte=localtime(now()))
474
            # exclude non published events
477 475
            entries = entries.filter(
478
                start_datetime__gte=localtime(
479
                    now() + datetime.timedelta(days=self.minimal_booking_delay)
480
                ).replace(hour=0, minute=0)
476
                Q(publication_date__isnull=True) | Q(publication_date__lte=localtime(now()).date())
481 477
            )
478

  
479
        if self.minimal_booking_delay:
480
            min_start = localtime(now() + datetime.timedelta(days=self.minimal_booking_delay)).replace(
481
                hour=0, minute=0
482
            )
483
            if prefetched_queryset:
484
                entries = [e for e in entries if e.start_datetime >= min_start]
485
            else:
486
                entries = entries.filter(start_datetime__gte=min_start)
482 487
        if self.maximal_booking_delay:
483
            entries = entries.filter(
484
                start_datetime__lt=localtime(
485
                    now() + datetime.timedelta(days=self.maximal_booking_delay)
486
                ).replace(hour=0, minute=0)
488
            max_start = localtime(now() + datetime.timedelta(days=self.maximal_booking_delay)).replace(
489
                hour=0, minute=0
487 490
            )
491
            if prefetched_queryset:
492
                entries = [e for e in entries if e.start_datetime < max_start]
493
            else:
494
                entries = entries.filter(start_datetime__lt=max_start)
488 495
        return entries
489 496

  
490 497

  
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
......
349 350

  
350 351
    def get(self, request, format=None):
351 352
        agendas_queryset = Agenda.objects.all().prefetch_related('resources').order_by('label')
353

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

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

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

  
357 380
        return Response({'data': agendas})
358 381

  
359 382

  
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': '1'})
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': 'true'})
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': '1'})
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': '1'})
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': '1'})
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': '1'})
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': '1'})
287
    assert len(resp.json['data']) == 0
288

  
289
    with CaptureQueriesContext(connection) as ctx:
290
        resp = app.get('/api/agenda/', params={'with_open_events': '1'})
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
-