agendas: add subscription model (#58444)

This commit is contained in:
Valentin Deniaud 2021-11-25 14:07:16 +01:00
parent da133c7b0c
commit 48a8af32d2
6 changed files with 111 additions and 1 deletions

View File

@ -0,0 +1,34 @@
# Generated by Django 2.2.19 on 2021-11-25 13:21
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('agendas', '0103_publication_datetime'),
]
operations = [
migrations.CreateModel(
name='Subscription',
fields=[
(
'id',
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
('user_external_id', models.CharField(max_length=250)),
('date_start', models.DateField()),
('date_end', models.DateField()),
(
'agenda',
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name='subscriptions',
to='agendas.Agenda',
),
),
],
),
]

View File

@ -2900,3 +2900,10 @@ class AbsenceReason(models.Model):
'label': self.label,
'slug': self.slug,
}
class Subscription(models.Model):
agenda = models.ForeignKey(Agenda, on_delete=models.CASCADE, related_name='subscriptions')
user_external_id = models.CharField(max_length=250)
date_start = models.DateField()
date_end = models.DateField()

View File

@ -5,7 +5,7 @@ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from chrono.agendas.models import AbsenceReason, Agenda, Booking, Category, Event
from chrono.agendas.models import AbsenceReason, Agenda, Booking, Category, Event, Subscription
class StringOrListField(serializers.ListField):
@ -274,3 +274,15 @@ class AgendaSerializer(serializers.ModelSerializer):
}
)
return attrs
class SubscriptionSerializer(serializers.ModelSerializer):
class Meta:
model = Subscription
fields = ['user_external_id', 'date_start', 'date_end']
def validate(self, attrs):
super().validate(attrs)
if attrs['date_start'] > attrs['date_end']:
raise ValidationError(_('start_datetime must be before end_datetime'))
return attrs

View File

@ -88,6 +88,11 @@ urlpatterns = [
views.meeting_datetimes,
name='api-agenda-meeting-datetimes',
),
url(
r'^agenda/(?P<agenda_identifier>[\w-]+)/subscription/$',
views.subscription,
name='api-agenda-subscription',
),
url(r'^bookings/$', views.bookings, name='api-bookings'),
url(r'^booking/(?P<booking_pk>\d+)/$', views.booking, name='api-booking'),
url(r'^booking/(?P<booking_pk>\d+)/cancel/$', views.cancel_booking, name='api-cancel-booking'),

View File

@ -49,6 +49,7 @@ from chrono.agendas.models import (
Desk,
Event,
MeetingType,
Subscription,
TimePeriodException,
)
from chrono.api import serializers
@ -1722,6 +1723,24 @@ class MultipleAgendasEventsFillslots(EventsFillslots):
agendas_events_fillslots = MultipleAgendasEventsFillslots.as_view()
class SubscriptionAPI(APIView):
serializer_class = serializers.SubscriptionSerializer
permission_classes = (permissions.IsAuthenticated,)
def post(self, request, agenda_identifier):
agenda = get_object_or_404(Agenda, slug=agenda_identifier, kind='events')
serializer = self.serializer_class(data=request.data)
if not serializer.is_valid():
raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors)
subscription = Subscription.objects.create(agenda=agenda, **serializer.validated_data)
return Response({'err': 0, 'id': subscription.pk})
subscription = SubscriptionAPI.as_view()
class BookingFilter(filters.FilterSet):
agenda = filters.CharFilter(field_name='event__agenda__slug', lookup_expr='exact')
category = filters.CharFilter(field_name='event__agenda__category__slug', lookup_expr='exact')

View File

@ -15,6 +15,7 @@ from chrono.agendas.models import (
Event,
MeetingType,
Resource,
Subscription,
TimePeriodException,
VirtualMember,
)
@ -729,3 +730,35 @@ def test_add_agenda(app, user, settings):
assert agenda.view_role == view_group
assert agenda.min_booking_datetime.date() == datetime.date(2021, 7, 12)
assert agenda.category == category_a
def test_api_create_subscription(app, user):
agenda = Agenda.objects.create(label='Foo bar', kind='events')
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, status=401)
app.authorization = ('Basic', ('john.doe', 'password'))
params = {'user_external_id': 'xxx', 'date_start': '2021-09-01', 'date_end': '2021-10-01'}
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params=params)
subscription = Subscription.objects.get(pk=resp.json['id'])
assert subscription.agenda == agenda
assert subscription.user_external_id == 'xxx'
assert subscription.date_start == datetime.date(year=2021, month=9, day=1)
assert subscription.date_end == datetime.date(year=2021, month=10, day=1)
# check errors
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params={}, status=400)
assert resp.json['err_class'] == 'invalid payload'
for field in ('user_external_id', 'date_start', 'date_end'):
assert 'required' in resp.json['errors'][field][0]
params = {'user_external_id': 'xxx', 'date_start': 'wrong-format', 'date_end': 'wrong-format'}
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params=params, status=400)
assert resp.json['err_class'] == 'invalid payload'
assert 'wrong format' in resp.json['errors']['date_start'][0]
assert 'wrong format' in resp.json['errors']['date_end'][0]
params = {'user_external_id': 'xxx', 'date_start': '2021-10-01', 'date_end': '2021-09-01'}
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params=params, status=400)
assert resp.json['errors']['non_field_errors'][0] == 'start_datetime must be before end_datetime'