110 |
110 |
kwargs={'agenda_identifier': agenda.slug})),
|
111 |
111 |
'desks_url': request.build_absolute_uri(
|
112 |
112 |
reverse('api-agenda-desks',
|
113 |
|
kwargs={'agenda_identifier': agenda.slug}))
|
|
113 |
kwargs={'agenda_identifier': agenda.slug})),
|
|
114 |
'fillslots_url': request.build_absolute_uri(
|
|
115 |
reverse('api-agenda-fillslots',
|
|
116 |
kwargs={'agenda_identifier': agenda.slug})),
|
114 |
117 |
}
|
115 |
118 |
|
116 |
119 |
return agenda_detail
|
... | ... | |
408 |
411 |
fillslot = Fillslot.as_view()
|
409 |
412 |
|
410 |
413 |
|
|
414 |
class Fillslots(GenericAPIView):
|
|
415 |
serializer_class = SlotSerializer
|
|
416 |
permission_classes = (permissions.IsAuthenticated,)
|
|
417 |
|
|
418 |
def post(self, request, agenda_identifier=None, format=None):
|
|
419 |
try:
|
|
420 |
agenda = Agenda.objects.get(slug=agenda_identifier)
|
|
421 |
except Agenda.DoesNotExist:
|
|
422 |
try:
|
|
423 |
# legacy access by agenda id
|
|
424 |
agenda = Agenda.objects.get(id=int(agenda_identifier))
|
|
425 |
except (ValueError, Agenda.DoesNotExist):
|
|
426 |
raise Http404()
|
|
427 |
if agenda.kind != 'meetings':
|
|
428 |
raise Http404('agenda found, but it was not a meetings agenda')
|
|
429 |
|
|
430 |
slots = request.data.get('slots')
|
|
431 |
if not slots:
|
|
432 |
return Response({'err': 1, 'reason': 'missing slots'})
|
|
433 |
if not isinstance(slots, list):
|
|
434 |
return Response({'err': 1, 'reason': 'slots must be a list'})
|
|
435 |
|
|
436 |
# slots came from fake event_pk (meeting_type:start_datetime)
|
|
437 |
meeting_type_id = slots[0].split(':')[0]
|
|
438 |
datetimes = set()
|
|
439 |
for slot in slots:
|
|
440 |
meeting_type_id_, datetime_str = slots.split(':')
|
|
441 |
if meeting_type_id_ != meeting_type_id:
|
|
442 |
return Response({
|
|
443 |
'err': 1,
|
|
444 |
'reason': 'all slots must have the same meeting type id (%s)' % meeting_type_id
|
|
445 |
})
|
|
446 |
datetimes.add(make_aware(datetime.datetime.strptime(datetime_str, '%Y-%m-%d-%H%M')))
|
|
447 |
|
|
448 |
# get all free slots and separate them by desk
|
|
449 |
all_slots = get_all_slots(agenda, MeetingType.objects.get(id=meeting_type_id))
|
|
450 |
all_slots = [slot for slot in all_slots if not slot.full]
|
|
451 |
datetimes_by_desk = defaultdict(set)
|
|
452 |
for slot in all_slots:
|
|
453 |
datetimes_by_desk[slot.desk.id].add(slot.start_datetime)
|
|
454 |
|
|
455 |
# search first desk where all requested slots are free
|
|
456 |
for available_desk_id in datetimes_by_desk:
|
|
457 |
if datetimes.issubset(datetimes_by_desk[available_desk_id]):
|
|
458 |
available_desk = Desk.objects.filter(id=available_desk_id)[0]
|
|
459 |
break
|
|
460 |
else:
|
|
461 |
return Response({'err': 1, 'reason': 'no more desk available'})
|
|
462 |
|
|
463 |
# all datetimes are free, book them in order
|
|
464 |
datetimes = list(datetimes)
|
|
465 |
datetimes.sort()
|
|
466 |
|
|
467 |
# create bookings and relative events (booking requires a real Event object)
|
|
468 |
first_booking = None
|
|
469 |
for start_datetime in datetimes:
|
|
470 |
event = Event.objects.create(agenda=agenda,
|
|
471 |
meeting_type_id=meeting_type_id,
|
|
472 |
start_datetime=start_datetime,
|
|
473 |
full=False, places=1,
|
|
474 |
desk=available_desk)
|
|
475 |
booking = Booking(event_id=event_pk, extra_data=request.data)
|
|
476 |
for attr in ('label', 'user_name', 'backoffice_url'):
|
|
477 |
if isinstance(request.data.get(attr), basestring):
|
|
478 |
setattr(booking, attr, request.data.get(attr))
|
|
479 |
if first_booking is not None:
|
|
480 |
additional_booking.primary_booking = first_booking
|
|
481 |
booking.save()
|
|
482 |
if first_booking is None:
|
|
483 |
first_booking = booking
|
|
484 |
|
|
485 |
response = {
|
|
486 |
'err': 0,
|
|
487 |
'in_waiting_list': 0,
|
|
488 |
'booking_id': first_booking.id,
|
|
489 |
'datetime': localtime(datetimes[0]),
|
|
490 |
'end_datetime': localtime(event.end_datetime), # it's the last created one
|
|
491 |
'desk': {
|
|
492 |
'label': available_desk.label,
|
|
493 |
'slug': available_desk.slug,
|
|
494 |
},
|
|
495 |
'api': {
|
|
496 |
'cancel_url': request.build_absolute_uri(
|
|
497 |
reverse('api-cancel-booking', kwargs={'booking_pk': first_booking.id}))
|
|
498 |
}
|
|
499 |
}
|
|
500 |
|
|
501 |
|
|
502 |
fillslots = Fillslots.as_view()
|
|
503 |
|
|
504 |
|
411 |
505 |
class BookingAPI(APIView):
|
412 |
506 |
permission_classes = (permissions.IsAuthenticated,)
|
413 |
507 |
|