0001-api-add-add-event-endpoint-47337.patch
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 |
api_url = '/api/agenda/%s/add-event/' % ('999') |
|
165 | ||
166 |
# no authentication |
|
167 |
resp = app.post(api_url, status=401) |
|
168 |
assert resp.json['detail'] == 'Authentication credentials were not provided.' |
|
169 | ||
170 |
# wrong password |
|
171 |
app.authorization = ('Basic', ('john.doe', 'wrong')) |
|
172 |
resp = app.post(api_url, status=401) |
|
173 |
assert resp.json['detail'] == 'Invalid username/password.' |
|
174 | ||
175 |
app.authorization = ('Basic', ('john.doe', 'password')) |
|
176 | ||
177 |
# missing agenda |
|
178 |
resp = app.post(api_url, status=404) |
|
179 |
assert resp.json['detail'] == 'Not found.' |
|
180 | ||
181 |
# using meeting agenda |
|
182 |
meeting_agenda = Agenda(label='Foo bar Meeting', kind='meetings') |
|
183 |
meeting_agenda.save() |
|
184 |
api_url = '/api/agenda/%s/add-event/' % (meeting_agenda.slug) |
|
185 |
resp = app.post(api_url, status=404) |
|
186 |
assert resp.json['detail'] == 'Not found.' |
|
187 | ||
188 |
agenda = Agenda(label='Foo bar') |
|
189 |
agenda.maximal_booking_delay = 0 |
|
190 |
agenda.save() |
|
191 |
api_url = '/api/agenda/%s/add-event/' % (agenda.slug) |
|
192 | ||
193 |
# missing fields |
|
194 |
resp = app.post(api_url, status=200) |
|
195 |
assert resp.json['err'] |
|
196 |
assert resp.json['errors'] == { |
|
197 |
'start_datetime': ['This field is required.'], |
|
198 |
'places': ['This field is required.'], |
|
199 |
} |
|
200 | ||
201 |
# add with errors in datetime parts |
|
202 |
params = { |
|
203 |
'start_datetime': '2021-11-15 minuit', |
|
204 |
'places': 10, |
|
205 |
} |
|
206 |
resp = app.post(api_url, params=params, status=200) |
|
207 |
assert resp.json['err'] |
|
208 |
assert resp.json['err_desc'] == 'invalid payload' |
|
209 |
assert 'Datetime has wrong format' in resp.json['errors']['start_datetime'][0] |
|
210 | ||
211 |
# add an event |
|
212 |
params = { |
|
213 |
'start_datetime': '2021-11-15 15:38', |
|
214 |
'places': 10, |
|
215 |
} |
|
216 |
resp = app.post(api_url, params=params) |
|
217 |
assert not resp.json['err'] |
|
218 |
event_id = resp.json['event_id'] |
|
219 |
event = Event.objects.filter(agenda=agenda).get(id=event_id) |
|
220 |
assert event.slug == 'foo-bar-event' |
|
221 |
assert str(event.start_datetime) == '2021-11-15 14:38:00+00:00' |
|
222 |
assert str(event.start_datetime.tzinfo) == 'UTC' |
|
223 |
assert event.places == 10 |
|
224 |
assert event.publication_date is None |
|
225 | ||
226 |
# add with almost all optional managed fields |
|
227 |
params = { |
|
228 |
'start_datetime': '2021-11-15 15:38', |
|
229 |
'duration': 42, |
|
230 |
'publication_date': '2021-09-20', |
|
231 |
'places': 11, |
|
232 |
'waiting_list_places': 3, |
|
233 |
'label': 'EO camp', |
|
234 |
'description': 'An event', |
|
235 |
'pricing': 'free', |
|
236 |
'url': 'http://example.org/foo/bar/?', |
|
237 |
} |
|
238 |
resp = app.post(api_url, params=params) |
|
239 |
event_id = resp.json['event_id'] |
|
240 |
event = Event.objects.filter(agenda=agenda).get(id=event_id) |
|
241 |
assert event.slug == 'eo-camp' |
|
242 |
assert event.duration == 42 |
|
243 |
assert event.waiting_list_places == 3 |
|
244 |
assert event.label == 'EO camp' |
|
245 |
assert event.description == 'An event' |
|
246 |
assert event.pricing == 'free' |
|
247 |
assert event.url == 'http://example.org/foo/bar/?' |
|
248 | ||
249 |
# add a recurrent event |
|
250 |
params = { |
|
251 |
'start_datetime': '2021-11-15 15:38', |
|
252 |
'places': 1, |
|
253 |
'recurrence_days': '0,3,5', |
|
254 |
'recurrence_week_interval': '2', |
|
255 |
'recurrence_end_date': '2022-11-29', |
|
256 |
'description': 'A recurrent event', |
|
257 |
} |
|
258 |
resp = app.post(api_url, params=params) |
|
259 |
event_id = resp.json['event_id'] |
|
260 |
event = Event.objects.filter(agenda=agenda).get(id=event_id) |
|
261 |
assert event.slug == 'foo-bar-event-1' |
|
262 |
assert event.description == 'A recurrent event' |
|
263 |
assert event.recurrence_days == [0, 3, 5] |
|
264 |
assert event.recurrence_week_interval == 2 |
|
265 |
assert event.recurrence_end_date == datetime.date(2022, 11, 29) |
|
161 |
- |