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 |
class Meta: |
|
140 |
model = Event |
|
141 |
fields = [ |
|
142 |
'start_datetime', |
|
143 |
'duration', |
|
144 |
'publication_date', |
|
145 |
'places', |
|
146 |
'waiting_list_places', |
|
147 |
'label', |
|
148 |
'description', |
|
149 |
'pricing', |
|
150 |
'url', |
|
151 |
] |
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': '2020-12-08 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 |
assert Event.objects.filter(agenda=agenda).count() == 1 |
|
181 |
event = Event.objects.filter(agenda=agenda, id=event_id)[0] |
|
182 |
assert str(event.start_datetime) == '2020-12-08 14:38:00+00:00' |
|
183 |
assert str(event.start_datetime.tzinfo) == 'UTC' |
|
184 |
assert event.places == 10 |
|
185 |
assert event.publication_date is None |
|
186 | ||
187 |
# add with a description |
|
188 |
params = { |
|
189 |
'start_datetime': '2020-12-08 15:38', |
|
190 |
'publication_date': '2020-05-11', |
|
191 |
'description': 'A description', |
|
192 |
'places': 11, |
|
193 |
} |
|
194 |
resp = app.post(api_url, params=params) |
|
195 |
event_id = resp.json['event_id'] |
|
196 |
event = Event.objects.filter(agenda=agenda, id=event_id)[0] |
|
197 |
assert event.description == 'A description' |
|
198 |
assert event.publication_date == datetime.date(2020, 5, 11) |
|
199 | ||
200 |
# add with errors in datetime parts |
|
201 |
params = { |
|
202 |
'start_datetime': '2020-12-08 minuit', |
|
203 |
'places': 10, |
|
204 |
} |
|
205 |
resp = app.post(api_url, params=params, status=200) |
|
206 |
assert resp.json['err'] |
|
207 |
assert resp.json['err_desc'] == 'invalid payload' |
|
208 |
assert 'Datetime has wrong format' in resp.json['errors']['start_datetime'][0] |
|
209 |
assert Event.objects.filter(agenda=agenda).count() == 2 |
|
210 | ||
211 | ||
212 |
def test_add_event_on_missing_agenda(app, user): |
|
213 |
agenda = Agenda(label='Foo bar Meeting', kind='meetings') |
|
214 |
agenda.save() |
|
215 |
api_url = '/api/agenda/%s/add-event/' % ('999') |
|
216 | ||
217 |
# no authentication |
|
218 |
resp = app.post(api_url, status=401) |
|
219 |
assert resp.json['detail'] == 'Authentication credentials were not provided.' |
|
220 | ||
221 |
# wrong password |
|
222 |
app.authorization = ('Basic', ('john.doe', 'wrong')) |
|
223 |
resp = app.post(api_url, status=401) |
|
224 |
assert resp.json['detail'] == 'Invalid username/password.' |
|
225 | ||
226 |
# missing agenda |
|
227 |
app.authorization = ('Basic', ('john.doe', 'password')) |
|
228 |
resp = app.post(api_url, status=404) |
|
229 |
assert resp.json['detail'] == 'Not found.' |
|
230 | ||
231 |
# meeting agenda |
|
232 |
api_url = '/api/agenda/%s/add-event/' % (agenda.slug) |
|
233 |
resp = app.post(api_url, status=404) |
|
234 |
assert resp.json['detail'] == 'Not found.' |
|
161 |
- |