Projet

Général

Profil

0001-api-add-add-event-endpoint-47337.patch

Nicolas Roche, 20 septembre 2021 18:49

Télécharger (7,82 ko)

Voir les différences:

Subject: [PATCH] api: add add-event endpoint (#47337)

 chrono/api/serializers.py | 25 ++++++++++-
 chrono/api/urls.py        |  5 +++
 chrono/api/views.py       | 22 ++++++++++
 tests/api/test_event.py   | 92 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 143 insertions(+), 1 deletion(-)
chrono/api/serializers.py
1 1
from django.utils.translation import ugettext_lazy as _
2 2
from rest_framework import serializers
3 3
from rest_framework.exceptions import ValidationError
4 4

  
5
from chrono.agendas.models import AbsenceReason, Booking
5
from chrono.agendas.models import AbsenceReason, Booking, Event
6 6

  
7 7

  
8 8
class StringOrListField(serializers.ListField):
9 9
    def to_internal_value(self, data):
10 10
        if isinstance(data, str):
11 11
            data = [s.strip() for s in data.split(',') if s.strip()]
12 12
        return super().to_internal_value(data)
13 13

  
......
128 128
            )
129 129
        return attrs
130 130

  
131 131

  
132 132
class MultipleAgendasDatetimesSerializer(DatetimesSerializer):
133 133
    agendas = CommaSeparatedStringField(
134 134
        required=True, child=serializers.SlugField(max_length=160, allow_blank=False)
135 135
    )
136

  
137

  
138
class EventSerializer(serializers.ModelSerializer):
139
    recurrence_days = CommaSeparatedStringField(
140
        required=False, child=serializers.SlugField(max_length=160, allow_blank=False)
141
    )
142

  
143
    class Meta:
144
        model = Event
145
        fields = [
146
            'start_datetime',
147
            'recurrence_days',
148
            'recurrence_week_interval',
149
            'recurrence_end_date',
150
            'duration',
151
            'publication_date',
152
            'places',
153
            'waiting_list_places',
154
            'label',
155
            'description',
156
            'pricing',
157
            'url',
158
        ]
chrono/api/urls.py
59 59
        views.event_bookings,
60 60
        name='api-event-bookings',
61 61
    ),
62 62
    url(
63 63
        r'^agenda/(?P<agenda_identifier>[\w-]+)/check/(?P<event_identifier>[\w:-]+)/$',
64 64
        views.event_check,
65 65
        name='api-event-check',
66 66
    ),
67
    url(
68
        r'^agenda/(?P<agenda_identifier>[\w-]+)/add-event/$',
69
        views.agenda_add_event,
70
        name='api-agenda-add-event',
71
    ),
67 72
    url(
68 73
        r'^agenda/meetings/(?P<meeting_identifier>[\w-]+)/datetimes/$',
69 74
        views.meeting_datetimes,
70 75
        name='api-agenda-meeting-datetimes-legacy',
71 76
    ),
72 77
    url(r'^agenda/(?P<agenda_identifier>[\w-]+)/meetings/$', views.meeting_list, name='api-agenda-meetings'),
73 78
    url(
74 79
        r'^agenda/(?P<agenda_identifier>[\w-]+)/meetings/(?P<meeting_identifier>[\w-]+)/$',
chrono/api/views.py
2402 2402
                    'series': series,
2403 2403
                },
2404 2404
                'err': 0,
2405 2405
            }
2406 2406
        )
2407 2407

  
2408 2408

  
2409 2409
bookings_statistics = BookingsStatistics.as_view()
2410

  
2411

  
2412
class AgendaAddEventView(APIView):
2413
    permission_classes = (permissions.IsAuthenticated,)
2414
    serializer_class = serializers.EventSerializer
2415

  
2416
    def post(self, request, agenda_identifier):
2417
        agenda = get_object_or_404(Agenda, slug=agenda_identifier, kind='events')
2418

  
2419
        serializer = self.serializer_class(data=request.data)
2420
        if not serializer.is_valid():
2421
            return APIError(
2422
                _('invalid payload'), err_class='invalid payload', errors=serializer.errors
2423
            ).to_response()
2424

  
2425
        payload = serializer.validated_data
2426
        event = Event.objects.create(agenda=agenda, **payload)
2427
        response = {'err': 0, 'event_id': event.pk}
2428
        return Response(response)
2429

  
2430

  
2431
agenda_add_event = AgendaAddEventView.as_view()
tests/api/test_event.py
153 153

  
154 154
    # wrong kind
155 155
    agenda.kind = 'meetings'
156 156
    agenda.save()
157 157
    app.post('/api/agenda/%s/check/%s/' % (agenda.slug, event.slug), status=404)
158 158
    agenda.kind = 'virtual'
159 159
    agenda.save()
160 160
    app.post('/api/agenda/%s/check/%s/' % (agenda.slug, event.slug), status=404)
161

  
162

  
163
def test_add_event(app, user):
164
    agenda = Agenda(label='Foo bar')
165
    agenda.maximal_booking_delay = 0
166
    agenda.save()
167

  
168
    params = {
169
        'start_datetime': '2021-11-15 15:38',
170
        'places': 10,
171
        'slug': 123,
172
    }
173
    api_url = '/api/agenda/%s/add-event/' % (agenda.slug)
174
    app.authorization = ('Basic', ('john.doe', 'password'))
175

  
176
    # add an event
177
    resp = app.post(api_url, params=params)
178
    assert not resp.json['err']
179
    event_id = resp.json['event_id']
180
    event = Event.objects.filter(agenda=agenda).get(id=event_id)
181
    assert str(event.start_datetime) == '2021-11-15 14:38:00+00:00'
182
    assert str(event.start_datetime.tzinfo) == 'UTC'
183
    assert event.places == 10
184
    assert event.publication_date is None
185

  
186
    # add with a description
187
    params = {
188
        'start_datetime': '2021-11-15 15:38',
189
        'publication_date': '2021-09-20',
190
        'description': 'A description',
191
        'places': 11,
192
    }
193
    resp = app.post(api_url, params=params)
194
    event_id = resp.json['event_id']
195
    event = Event.objects.filter(agenda=agenda).get(id=event_id)
196
    assert event.description == 'A description'
197
    assert event.publication_date == datetime.date(2021, 9, 20)
198

  
199
    # add a recurent event
200
    params = {
201
        'start_datetime': '2021-11-15 15:38',
202
        'publication_date': '2021-09-20',
203
        'description': 'A recurent event',
204
        'places': 1,
205
        'recurrence_days': '0,3,5',
206
        'recurrence_week_interval': '2',
207
        'recurrence_end_date': '2022-11-29',
208
    }
209
    resp = app.post(api_url, params=params)
210
    event_id = resp.json['event_id']
211
    event = Event.objects.filter(agenda=agenda).get(id=event_id)
212
    assert event.description == 'A recurent event'
213
    assert event.recurrence_days == [0, 3, 5]
214
    assert event.recurrence_week_interval == 2
215
    assert event.recurrence_end_date == datetime.date(2022, 11, 29)
216

  
217
    # add with errors in datetime parts
218
    params = {
219
        'start_datetime': '2021-11-15 minuit',
220
        'places': 10,
221
    }
222
    assert Event.objects.filter(agenda=agenda).count() == 3
223
    resp = app.post(api_url, params=params, status=200)
224
    assert Event.objects.filter(agenda=agenda).count() == 3
225
    assert resp.json['err']
226
    assert resp.json['err_desc'] == 'invalid payload'
227
    assert 'Datetime has wrong format' in resp.json['errors']['start_datetime'][0]
228

  
229

  
230
def test_add_event_on_missing_agenda(app, user):
231
    agenda = Agenda(label='Foo bar Meeting', kind='meetings')
232
    agenda.save()
233
    api_url = '/api/agenda/%s/add-event/' % ('999')
234

  
235
    # no authentication
236
    resp = app.post(api_url, status=401)
237
    assert resp.json['detail'] == 'Authentication credentials were not provided.'
238

  
239
    # wrong password
240
    app.authorization = ('Basic', ('john.doe', 'wrong'))
241
    resp = app.post(api_url, status=401)
242
    assert resp.json['detail'] == 'Invalid username/password.'
243

  
244
    # missing agenda
245
    app.authorization = ('Basic', ('john.doe', 'password'))
246
    resp = app.post(api_url, status=404)
247
    assert resp.json['detail'] == 'Not found.'
248

  
249
    # meeting agenda
250
    api_url = '/api/agenda/%s/add-event/' % (agenda.slug)
251
    resp = app.post(api_url, status=404)
252
    assert resp.json['detail'] == 'Not found.'
161
-