0001-agendas-add-subscription-model-58444.patch
chrono/agendas/migrations/0104_subscription.py | ||
---|---|---|
1 |
# Generated by Django 2.2.19 on 2021-11-25 13:21 |
|
2 | ||
3 |
import django.db.models.deletion |
|
4 |
from django.db import migrations, models |
|
5 | ||
6 | ||
7 |
class Migration(migrations.Migration): |
|
8 | ||
9 |
dependencies = [ |
|
10 |
('agendas', '0103_publication_datetime'), |
|
11 |
] |
|
12 | ||
13 |
operations = [ |
|
14 |
migrations.CreateModel( |
|
15 |
name='Subscription', |
|
16 |
fields=[ |
|
17 |
( |
|
18 |
'id', |
|
19 |
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), |
|
20 |
), |
|
21 |
('user_external_id', models.CharField(max_length=250)), |
|
22 |
('date_start', models.DateField()), |
|
23 |
('date_end', models.DateField()), |
|
24 |
( |
|
25 |
'agenda', |
|
26 |
models.ForeignKey( |
|
27 |
on_delete=django.db.models.deletion.CASCADE, |
|
28 |
related_name='subscriptions', |
|
29 |
to='agendas.Agenda', |
|
30 |
), |
|
31 |
), |
|
32 |
], |
|
33 |
), |
|
34 |
] |
chrono/agendas/models.py | ||
---|---|---|
2900 | 2900 |
'label': self.label, |
2901 | 2901 |
'slug': self.slug, |
2902 | 2902 |
} |
2903 | ||
2904 | ||
2905 |
class Subscription(models.Model): |
|
2906 |
agenda = models.ForeignKey(Agenda, on_delete=models.CASCADE, related_name='subscriptions') |
|
2907 |
user_external_id = models.CharField(max_length=250) |
|
2908 |
date_start = models.DateField() |
|
2909 |
date_end = models.DateField() |
chrono/api/serializers.py | ||
---|---|---|
5 | 5 |
from rest_framework import serializers |
6 | 6 |
from rest_framework.exceptions import ValidationError |
7 | 7 | |
8 |
from chrono.agendas.models import AbsenceReason, Agenda, Booking, Category, Event |
|
8 |
from chrono.agendas.models import AbsenceReason, Agenda, Booking, Category, Event, Subscription
|
|
9 | 9 | |
10 | 10 | |
11 | 11 |
class StringOrListField(serializers.ListField): |
... | ... | |
274 | 274 |
} |
275 | 275 |
) |
276 | 276 |
return attrs |
277 | ||
278 | ||
279 |
class SubscriptionSerializer(serializers.ModelSerializer): |
|
280 |
class Meta: |
|
281 |
model = Subscription |
|
282 |
fields = ['user_external_id', 'date_start', 'date_end'] |
|
283 | ||
284 |
def validate(self, attrs): |
|
285 |
super().validate(attrs) |
|
286 |
if attrs['date_start'] > attrs['date_end']: |
|
287 |
raise ValidationError(_('start_datetime must be before end_datetime')) |
|
288 |
return attrs |
chrono/api/urls.py | ||
---|---|---|
88 | 88 |
views.meeting_datetimes, |
89 | 89 |
name='api-agenda-meeting-datetimes', |
90 | 90 |
), |
91 |
url( |
|
92 |
r'^agenda/(?P<agenda_identifier>[\w-]+)/subscription/$', |
|
93 |
views.subscription, |
|
94 |
name='api-agenda-subscription', |
|
95 |
), |
|
91 | 96 |
url(r'^bookings/$', views.bookings, name='api-bookings'), |
92 | 97 |
url(r'^booking/(?P<booking_pk>\d+)/$', views.booking, name='api-booking'), |
93 | 98 |
url(r'^booking/(?P<booking_pk>\d+)/cancel/$', views.cancel_booking, name='api-cancel-booking'), |
chrono/api/views.py | ||
---|---|---|
49 | 49 |
Desk, |
50 | 50 |
Event, |
51 | 51 |
MeetingType, |
52 |
Subscription, |
|
52 | 53 |
TimePeriodException, |
53 | 54 |
) |
54 | 55 |
from chrono.api import serializers |
... | ... | |
1722 | 1723 |
agendas_events_fillslots = MultipleAgendasEventsFillslots.as_view() |
1723 | 1724 | |
1724 | 1725 | |
1726 |
class SubscriptionAPI(APIView): |
|
1727 |
serializer_class = serializers.SubscriptionSerializer |
|
1728 |
permission_classes = (permissions.IsAuthenticated,) |
|
1729 | ||
1730 |
def post(self, request, agenda_identifier): |
|
1731 |
agenda = get_object_or_404(Agenda, slug=agenda_identifier, kind='events') |
|
1732 | ||
1733 |
serializer = self.serializer_class(data=request.data) |
|
1734 |
if not serializer.is_valid(): |
|
1735 |
raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors) |
|
1736 | ||
1737 |
subscription = Subscription.objects.create(agenda=agenda, **serializer.validated_data) |
|
1738 |
return Response({'err': 0, 'id': subscription.pk}) |
|
1739 | ||
1740 | ||
1741 |
subscription = SubscriptionAPI.as_view() |
|
1742 | ||
1743 | ||
1725 | 1744 |
class BookingFilter(filters.FilterSet): |
1726 | 1745 |
agenda = filters.CharFilter(field_name='event__agenda__slug', lookup_expr='exact') |
1727 | 1746 |
category = filters.CharFilter(field_name='event__agenda__category__slug', lookup_expr='exact') |
tests/api/test_all.py | ||
---|---|---|
15 | 15 |
Event, |
16 | 16 |
MeetingType, |
17 | 17 |
Resource, |
18 |
Subscription, |
|
18 | 19 |
TimePeriodException, |
19 | 20 |
VirtualMember, |
20 | 21 |
) |
... | ... | |
729 | 730 |
assert agenda.view_role == view_group |
730 | 731 |
assert agenda.min_booking_datetime.date() == datetime.date(2021, 7, 12) |
731 | 732 |
assert agenda.category == category_a |
733 | ||
734 | ||
735 |
def test_api_create_subscription(app, user): |
|
736 |
agenda = Agenda.objects.create(label='Foo bar', kind='events') |
|
737 | ||
738 |
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, status=401) |
|
739 | ||
740 |
app.authorization = ('Basic', ('john.doe', 'password')) |
|
741 | ||
742 |
params = {'user_external_id': 'xxx', 'date_start': '2021-09-01', 'date_end': '2021-10-01'} |
|
743 |
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params=params) |
|
744 |
subscription = Subscription.objects.get(pk=resp.json['id']) |
|
745 |
assert subscription.agenda == agenda |
|
746 |
assert subscription.user_external_id == 'xxx' |
|
747 |
assert subscription.date_start == datetime.date(year=2021, month=9, day=1) |
|
748 |
assert subscription.date_end == datetime.date(year=2021, month=10, day=1) |
|
749 | ||
750 |
# check errors |
|
751 |
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params={}, status=400) |
|
752 |
assert resp.json['err_class'] == 'invalid payload' |
|
753 |
for field in ('user_external_id', 'date_start', 'date_end'): |
|
754 |
assert 'required' in resp.json['errors'][field][0] |
|
755 | ||
756 |
params = {'user_external_id': 'xxx', 'date_start': 'wrong-format', 'date_end': 'wrong-format'} |
|
757 |
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params=params, status=400) |
|
758 |
assert resp.json['err_class'] == 'invalid payload' |
|
759 |
assert 'wrong format' in resp.json['errors']['date_start'][0] |
|
760 |
assert 'wrong format' in resp.json['errors']['date_end'][0] |
|
761 | ||
762 |
params = {'user_external_id': 'xxx', 'date_start': '2021-10-01', 'date_end': '2021-09-01'} |
|
763 |
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params=params, status=400) |
|
764 |
assert resp.json['errors']['non_field_errors'][0] == 'start_datetime must be before end_datetime' |
|
732 |
- |