api: subscriptions with overlapping is forbidden (#61631)
This commit is contained in:
parent
15fdd07141
commit
0d919518be
|
@ -1989,6 +1989,18 @@ class SubscriptionsAPI(ListAPIView):
|
|||
raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors)
|
||||
extra_data = {k: v for k, v in request.data.items() if k not in serializer.validated_data}
|
||||
|
||||
date_start = serializer.validated_data['date_start']
|
||||
date_end = serializer.validated_data['date_end']
|
||||
overlapping_subscription_qs = Subscription.objects.filter(
|
||||
agenda=self.agenda,
|
||||
user_external_id=serializer.validated_data['user_external_id'],
|
||||
).extra(
|
||||
where=["(date_start, date_end) OVERLAPS (%s, %s) OR date_start = %s OR date_end = %s"],
|
||||
params=[date_start, date_end, date_end, date_start],
|
||||
)
|
||||
if overlapping_subscription_qs.exists():
|
||||
raise APIErrorBadRequest(N_('another subscription overlapping this period already exists'))
|
||||
|
||||
subscription = Subscription.objects.create(
|
||||
agenda=self.agenda, extra_data=extra_data, **serializer.validated_data
|
||||
)
|
||||
|
@ -2019,10 +2031,30 @@ class SubscriptionAPI(APIView):
|
|||
|
||||
def patch(self, request, *args, **kwargs):
|
||||
serializer = self.serializer_class(self.subscription, data=request.data, partial=True)
|
||||
old_date_start = self.subscription.date_start
|
||||
old_date_end = self.subscription.date_end
|
||||
|
||||
if not serializer.is_valid():
|
||||
raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors, err=4)
|
||||
|
||||
date_start = serializer.validated_data.get('date_start') or old_date_start
|
||||
date_end = serializer.validated_data.get('date_end') or old_date_end
|
||||
overlapping_subscription_qs = (
|
||||
Subscription.objects.filter(
|
||||
agenda=self.subscription.agenda,
|
||||
user_external_id=self.subscription.user_external_id,
|
||||
)
|
||||
.exclude(pk=self.subscription.pk)
|
||||
.extra(
|
||||
where=["(date_start, date_end) OVERLAPS (%s, %s) OR date_start = %s OR date_end = %s"],
|
||||
params=[date_start, date_end, date_end, date_start],
|
||||
)
|
||||
)
|
||||
if (
|
||||
old_date_start != date_start or old_date_end != date_end
|
||||
) and overlapping_subscription_qs.exists():
|
||||
raise APIErrorBadRequest(N_('another subscription overlapping this period already exists'))
|
||||
|
||||
serializer.save()
|
||||
extra_data = {k: v for k, v in request.data.items() if k not in serializer.validated_data}
|
||||
if extra_data:
|
||||
|
|
|
@ -162,6 +162,7 @@ def test_api_create_subscription(app, user):
|
|||
assert subscription.extra_data == {'foo': 'bar'}
|
||||
assert subscription.date_start == datetime.date(year=2021, month=9, day=1)
|
||||
assert subscription.date_end == datetime.date(year=2021, month=10, day=1)
|
||||
subscription.delete()
|
||||
|
||||
params = {
|
||||
'user_external_id': 'xxx',
|
||||
|
@ -211,6 +212,86 @@ def test_api_create_subscription(app, user):
|
|||
assert resp.json['errors']['non_field_errors'][0] == 'start_datetime must be before end_datetime'
|
||||
|
||||
|
||||
def test_api_create_subscription_check_dates(app, user):
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='xxx',
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=9, day=30),
|
||||
)
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='yyy', # another user
|
||||
date_start=datetime.date(year=2021, month=8, day=1),
|
||||
date_end=datetime.date(year=2021, month=8, day=31),
|
||||
)
|
||||
other_agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
Subscription.objects.create(
|
||||
agenda=other_agenda, # another agenda
|
||||
user_external_id='xxx',
|
||||
date_start=datetime.date(year=2021, month=8, day=1),
|
||||
date_end=datetime.date(year=2021, month=8, day=31),
|
||||
)
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
|
||||
params = {
|
||||
'user_external_id': 'xxx',
|
||||
'user_first_name': 'Foo',
|
||||
'user_last_name': 'BAR',
|
||||
'date_start': '2021-09-10',
|
||||
'date_end': '2021-09-20',
|
||||
}
|
||||
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params=params, status=400)
|
||||
assert resp.json['err_desc'] == 'another subscription overlapping this period already exists'
|
||||
|
||||
params.update(
|
||||
{
|
||||
'date_start': '2021-09-01',
|
||||
'date_end': '2021-09-30',
|
||||
}
|
||||
)
|
||||
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params=params, status=400)
|
||||
assert resp.json['err_desc'] == 'another subscription overlapping this period already exists'
|
||||
|
||||
params.update(
|
||||
{
|
||||
'date_start': '2021-08-01',
|
||||
'date_end': '2021-09-01',
|
||||
}
|
||||
)
|
||||
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params=params, status=400)
|
||||
assert resp.json['err_desc'] == 'another subscription overlapping this period already exists'
|
||||
|
||||
params.update(
|
||||
{
|
||||
'date_start': '2021-09-30',
|
||||
'date_end': '2021-10-31',
|
||||
}
|
||||
)
|
||||
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params=params, status=400)
|
||||
assert resp.json['err_desc'] == 'another subscription overlapping this period already exists'
|
||||
|
||||
params.update(
|
||||
{
|
||||
'date_start': '2021-08-01',
|
||||
'date_end': '2021-08-31',
|
||||
}
|
||||
)
|
||||
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params=params)
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
params.update(
|
||||
{
|
||||
'date_start': '2021-10-01',
|
||||
'date_end': '2021-10-31',
|
||||
}
|
||||
)
|
||||
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params=params)
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
|
||||
def test_api_get_subscription(app, user):
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
subscription = Subscription.objects.create(
|
||||
|
@ -426,3 +507,109 @@ def test_api_patch_subscription(app, user):
|
|||
agenda.kind = kind
|
||||
agenda.save()
|
||||
app.patch('/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), status=404)
|
||||
|
||||
|
||||
def test_api_patch_subscription_check_dates(app, user):
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='xxx',
|
||||
date_start=datetime.date(year=2021, month=9, day=1),
|
||||
date_end=datetime.date(year=2021, month=9, day=30),
|
||||
)
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='yyy', # another user
|
||||
date_start=datetime.date(year=2021, month=8, day=1),
|
||||
date_end=datetime.date(year=2021, month=8, day=31),
|
||||
)
|
||||
other_agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
Subscription.objects.create(
|
||||
agenda=other_agenda, # another agenda
|
||||
user_external_id='xxx',
|
||||
date_start=datetime.date(year=2021, month=8, day=1),
|
||||
date_end=datetime.date(year=2021, month=8, day=31),
|
||||
)
|
||||
|
||||
# subscription to update
|
||||
subscription = Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='xxx',
|
||||
date_start=datetime.date(year=2021, month=8, day=1),
|
||||
date_end=datetime.date(year=2021, month=8, day=31),
|
||||
)
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
|
||||
params = {
|
||||
'date_end': '2021-09-01',
|
||||
}
|
||||
resp = app.patch(
|
||||
'/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params, status=400
|
||||
)
|
||||
assert resp.json['err_desc'] == 'another subscription overlapping this period already exists'
|
||||
|
||||
params = {
|
||||
'date_start': '2021-09-10',
|
||||
'date_end': '2021-09-20',
|
||||
}
|
||||
resp = app.patch(
|
||||
'/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params, status=400
|
||||
)
|
||||
assert resp.json['err_desc'] == 'another subscription overlapping this period already exists'
|
||||
|
||||
params = {
|
||||
'date_start': '2021-09-01',
|
||||
'date_end': '2021-09-30',
|
||||
}
|
||||
resp = app.patch(
|
||||
'/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params, status=400
|
||||
)
|
||||
assert resp.json['err_desc'] == 'another subscription overlapping this period already exists'
|
||||
|
||||
params = {
|
||||
'date_start': '2021-08-01',
|
||||
'date_end': '2021-09-01',
|
||||
}
|
||||
resp = app.patch(
|
||||
'/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params, status=400
|
||||
)
|
||||
assert resp.json['err_desc'] == 'another subscription overlapping this period already exists'
|
||||
|
||||
params = {
|
||||
'date_start': '2021-09-30',
|
||||
'date_end': '2021-10-31',
|
||||
}
|
||||
resp = app.patch(
|
||||
'/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params, status=400
|
||||
)
|
||||
assert resp.json['err_desc'] == 'another subscription overlapping this period already exists'
|
||||
|
||||
params = {
|
||||
'date_start': '2021-08-01',
|
||||
'date_end': '2021-08-31',
|
||||
}
|
||||
resp = app.patch('/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params)
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
params = {
|
||||
'date_start': '2021-10-01',
|
||||
'date_end': '2021-10-31',
|
||||
}
|
||||
resp = app.patch('/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params)
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
params = {
|
||||
'date_start': '2021-10-02',
|
||||
'date_end': '2021-10-31',
|
||||
}
|
||||
resp = app.patch('/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params)
|
||||
assert resp.json['err'] == 0
|
||||
|
||||
params = {
|
||||
'date_start': '2021-09-30',
|
||||
}
|
||||
resp = app.patch(
|
||||
'/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params, status=400
|
||||
)
|
||||
assert resp.json['err_desc'] == 'another subscription overlapping this period already exists'
|
||||
|
|
Loading…
Reference in New Issue