692 |
692 |
serializer_class = SlotsSerializer
|
693 |
693 |
|
694 |
694 |
def post(self, request, agenda_identifier=None, event_identifier=None, format=None):
|
695 |
|
return self.fillslot(request=request, agenda_identifier=agenda_identifier, format=format)
|
|
695 |
try:
|
|
696 |
return self.fillslot(request=request, agenda_identifier=agenda_identifier, format=format)
|
|
697 |
except APIError as e:
|
|
698 |
return e.to_response()
|
696 |
699 |
|
697 |
700 |
def fillslot(self, request, agenda_identifier=None, slots=[], format=None):
|
698 |
701 |
multiple_booking = bool(not slots)
|
... | ... | |
707 |
710 |
|
708 |
711 |
serializer = self.serializer_class(data=request.data, partial=True)
|
709 |
712 |
if not serializer.is_valid():
|
710 |
|
return Response(
|
711 |
|
{
|
712 |
|
'err': 1,
|
713 |
|
'err_class': 'invalid payload',
|
714 |
|
'err_desc': _('invalid payload'),
|
715 |
|
'errors': serializer.errors,
|
716 |
|
},
|
717 |
|
status=status.HTTP_400_BAD_REQUEST,
|
|
713 |
raise APIError(
|
|
714 |
_('invalid payload'),
|
|
715 |
err_class='invalid payload',
|
|
716 |
errors=serializer.errors,
|
|
717 |
http_status=status.HTTP_400_BAD_REQUEST,
|
718 |
718 |
)
|
719 |
719 |
payload = serializer.validated_data
|
720 |
720 |
|
721 |
721 |
if 'slots' in payload:
|
722 |
722 |
slots = payload['slots']
|
723 |
723 |
if not slots:
|
724 |
|
return Response(
|
725 |
|
{
|
726 |
|
'err': 1,
|
727 |
|
'err_class': 'slots list cannot be empty',
|
728 |
|
'err_desc': _('slots list cannot be empty'),
|
729 |
|
},
|
730 |
|
status=status.HTTP_400_BAD_REQUEST,
|
|
724 |
raise APIError(
|
|
725 |
_('slots list cannot be empty'),
|
|
726 |
err_class='slots list cannot be empty',
|
|
727 |
http_status=status.HTTP_400_BAD_REQUEST,
|
731 |
728 |
)
|
732 |
729 |
|
733 |
730 |
if 'count' in payload:
|
... | ... | |
737 |
734 |
try:
|
738 |
735 |
places_count = int(request.query_params['count'])
|
739 |
736 |
except ValueError:
|
740 |
|
return Response(
|
741 |
|
{
|
742 |
|
'err': 1,
|
743 |
|
'err_class': 'invalid value for count (%s)' % request.query_params['count'],
|
744 |
|
'err_desc': _('invalid value for count (%s)') % request.query_params['count'],
|
745 |
|
},
|
746 |
|
status=status.HTTP_400_BAD_REQUEST,
|
|
737 |
raise APIError(
|
|
738 |
_('invalid value for count (%s)') % request.query_params['count'],
|
|
739 |
err_class='invalid value for count (%s)' % request.query_params['count'],
|
|
740 |
http_status=status.HTTP_400_BAD_REQUEST,
|
747 |
741 |
)
|
748 |
742 |
else:
|
749 |
743 |
places_count = 1
|
750 |
744 |
|
751 |
745 |
if places_count <= 0:
|
752 |
|
return Response(
|
753 |
|
{
|
754 |
|
'err': 1,
|
755 |
|
'err_class': 'count cannot be less than or equal to zero',
|
756 |
|
'err_desc': _('count cannot be less than or equal to zero'),
|
757 |
|
},
|
758 |
|
status=status.HTTP_400_BAD_REQUEST,
|
|
746 |
raise APIError(
|
|
747 |
_('count cannot be less than or equal to zero'),
|
|
748 |
err_class='count cannot be less than or equal to zero',
|
|
749 |
http_status=status.HTTP_400_BAD_REQUEST,
|
759 |
750 |
)
|
760 |
751 |
|
761 |
752 |
to_cancel_booking = None
|
... | ... | |
764 |
755 |
try:
|
765 |
756 |
cancel_booking_id = int(payload.get('cancel_booking_id'))
|
766 |
757 |
except (ValueError, TypeError):
|
767 |
|
return Response(
|
768 |
|
{
|
769 |
|
'err': 1,
|
770 |
|
'err_class': 'cancel_booking_id is not an integer',
|
771 |
|
'err_desc': _('cancel_booking_id is not an integer'),
|
772 |
|
},
|
773 |
|
status=status.HTTP_400_BAD_REQUEST,
|
|
758 |
raise APIError(
|
|
759 |
_('cancel_booking_id is not an integer'),
|
|
760 |
err_class='cancel_booking_id is not an integer',
|
|
761 |
http_status=status.HTTP_400_BAD_REQUEST,
|
774 |
762 |
)
|
775 |
763 |
|
776 |
764 |
if cancel_booking_id is not None:
|
... | ... | |
790 |
778 |
cancel_error = gettext_noop('cancel booking: booking does no exist')
|
791 |
779 |
|
792 |
780 |
if cancel_error:
|
793 |
|
return Response({'err': 1, 'err_class': cancel_error, 'err_desc': _(cancel_error)})
|
|
781 |
raise APIError(_(cancel_error), err_class=cancel_error)
|
794 |
782 |
|
795 |
783 |
extra_data = {}
|
796 |
784 |
for k, v in request.data.items():
|
... | ... | |
808 |
796 |
try:
|
809 |
797 |
meeting_type_id_, datetime_str = slot.split(':')
|
810 |
798 |
except ValueError:
|
811 |
|
return Response(
|
812 |
|
{
|
813 |
|
'err': 1,
|
814 |
|
'err_class': 'invalid slot: %s' % slot,
|
815 |
|
'err_desc': _('invalid slot: %s') % slot,
|
816 |
|
},
|
817 |
|
status=status.HTTP_400_BAD_REQUEST,
|
|
799 |
raise APIError(
|
|
800 |
_('invalid slot: %s') % slot,
|
|
801 |
err_class='invalid slot: %s' % slot,
|
|
802 |
http_status=status.HTTP_400_BAD_REQUEST,
|
818 |
803 |
)
|
819 |
804 |
if meeting_type_id_ != meeting_type_id:
|
820 |
|
return Response(
|
821 |
|
{
|
822 |
|
'err': 1,
|
823 |
|
'err_class': 'all slots must have the same meeting type id (%s)'
|
824 |
|
% meeting_type_id,
|
825 |
|
'err_desc': _('all slots must have the same meeting type id (%s)')
|
826 |
|
% meeting_type_id,
|
827 |
|
},
|
828 |
|
status=status.HTTP_400_BAD_REQUEST,
|
|
805 |
raise APIError(
|
|
806 |
_('all slots must have the same meeting type id (%s)') % meeting_type_id,
|
|
807 |
err_class='all slots must have the same meeting type id (%s)' % meeting_type_id,
|
|
808 |
http_status=status.HTTP_400_BAD_REQUEST,
|
829 |
809 |
)
|
830 |
810 |
datetimes.add(make_aware(datetime.datetime.strptime(datetime_str, '%Y-%m-%d-%H%M')))
|
831 |
811 |
|
... | ... | |
842 |
822 |
# legacy access by id
|
843 |
823 |
meeting_type = agenda.get_meetingtype(id_=meeting_type_id)
|
844 |
824 |
except (MeetingType.DoesNotExist, ValueError):
|
845 |
|
return Response(
|
846 |
|
{
|
847 |
|
'err': 1,
|
848 |
|
'err_class': 'invalid meeting type id: %s' % meeting_type_id,
|
849 |
|
'err_desc': _('invalid meeting type id: %s') % meeting_type_id,
|
850 |
|
},
|
851 |
|
status=status.HTTP_400_BAD_REQUEST,
|
|
825 |
raise APIError(
|
|
826 |
_('invalid meeting type id: %s') % meeting_type_id,
|
|
827 |
err_class='invalid meeting type id: %s' % meeting_type_id,
|
|
828 |
http_status=status.HTTP_400_BAD_REQUEST,
|
852 |
829 |
)
|
853 |
830 |
all_slots = sorted(
|
854 |
831 |
get_all_slots(agenda, meeting_type, resources=resources),
|
... | ... | |
908 |
885 |
break
|
909 |
886 |
|
910 |
887 |
if available_desk is None:
|
911 |
|
return Response(
|
912 |
|
{
|
913 |
|
'err': 1,
|
914 |
|
'err_class': 'no more desk available',
|
915 |
|
'err_desc': _('no more desk available'),
|
916 |
|
}
|
|
888 |
raise APIError(
|
|
889 |
_('no more desk available'), err_class='no more desk available',
|
917 |
890 |
)
|
918 |
891 |
|
919 |
892 |
# all datetimes are free, book them in order
|
... | ... | |
957 |
930 |
)
|
958 |
931 |
|
959 |
932 |
if not events.count():
|
960 |
|
return Response(
|
961 |
|
{
|
962 |
|
'err': 1,
|
963 |
|
'err_class': 'unknown event identifiers or slugs',
|
964 |
|
'err_desc': _('unknown event identifiers or slugs'),
|
965 |
|
},
|
966 |
|
status=status.HTTP_400_BAD_REQUEST,
|
|
933 |
raise APIError(
|
|
934 |
_('unknown event identifiers or slugs'),
|
|
935 |
err_class='unknown event identifiers or slugs',
|
|
936 |
http_status=status.HTTP_400_BAD_REQUEST,
|
967 |
937 |
)
|
968 |
938 |
|
969 |
939 |
# search free places. Switch to waiting list if necessary.
|
970 |
940 |
in_waiting_list = False
|
971 |
941 |
for event in events:
|
972 |
942 |
if payload.get('force_waiting_list') and not event.waiting_list_places:
|
973 |
|
return Response({'err': 1, 'err_class': 'no waiting list', 'err_desc': _('no waiting list')})
|
|
943 |
raise APIError(
|
|
944 |
_('no waiting list'), err_class='no waiting list',
|
|
945 |
)
|
974 |
946 |
|
975 |
947 |
if event.waiting_list_places:
|
976 |
948 |
if (
|
... | ... | |
982 |
954 |
# in the waiting list.
|
983 |
955 |
in_waiting_list = True
|
984 |
956 |
if (event.waiting_list + places_count) > event.waiting_list_places:
|
985 |
|
return Response({'err': 1, 'err_class': 'sold out', 'err_desc': _('sold out')})
|
|
957 |
raise APIError(
|
|
958 |
_('sold out'), err_class='sold out',
|
|
959 |
)
|
986 |
960 |
else:
|
987 |
961 |
if (event.booked_places + places_count) > event.places:
|
988 |
|
return Response({'err': 1, 'err_class': 'sold out', 'err_desc': _('sold out')})
|
|
962 |
raise APIError(
|
|
963 |
_('sold out'), err_class='sold out',
|
|
964 |
)
|
989 |
965 |
|
990 |
966 |
with transaction.atomic():
|
991 |
967 |
if to_cancel_booking:
|
... | ... | |
1081 |
1057 |
serializer_class = SlotSerializer
|
1082 |
1058 |
|
1083 |
1059 |
def post(self, request, agenda_identifier=None, event_identifier=None, format=None):
|
1084 |
|
return self.fillslot(
|
1085 |
|
request=request,
|
1086 |
|
agenda_identifier=agenda_identifier,
|
1087 |
|
slots=[event_identifier], # fill a "list on one slot"
|
1088 |
|
format=format,
|
1089 |
|
)
|
|
1060 |
try:
|
|
1061 |
return self.fillslot(
|
|
1062 |
request=request,
|
|
1063 |
agenda_identifier=agenda_identifier,
|
|
1064 |
slots=[event_identifier], # fill a "list on one slot"
|
|
1065 |
format=format,
|
|
1066 |
)
|
|
1067 |
except APIError as e:
|
|
1068 |
return e.to_response()
|
1090 |
1069 |
|
1091 |
1070 |
|
1092 |
1071 |
fillslot = Fillslot.as_view()
|
1093 |
|
-
|