From 02583328b6aeab958839b32ed062a69bddb2c6b7 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Mon, 21 Nov 2022 16:48:07 +0100 Subject: [PATCH] Apply sane limits to retention periods --- CHANGES.rst | 1 + .../js/form_setup/ItemSettingsModal.jsx | 3 +- .../controllers/management/fields.py | 4 +++ indico/modules/events/registration/forms.py | 32 ++++++++++++++----- .../WTFParticipantVisibilityField.jsx | 3 +- 5 files changed, 33 insertions(+), 10 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index f617d0d8848..f034befce03 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -18,6 +18,7 @@ Bugfixes - Fix broken links in some notification emails (:pr:`5567`) - Fix always-disabled submit button when submitting an agreement response on someone's behalf (:pr:`5574`) +- Disallow nonsensical retention periods and visibility durations (:pr:`5576`) Version 3.2.1 diff --git a/indico/modules/events/registration/client/js/form_setup/ItemSettingsModal.jsx b/indico/modules/events/registration/client/js/form_setup/ItemSettingsModal.jsx index 795098d9579..a707e99dda6 100644 --- a/indico/modules/events/registration/client/js/form_setup/ItemSettingsModal.jsx +++ b/indico/modules/events/registration/client/js/form_setup/ItemSettingsModal.jsx @@ -154,7 +154,8 @@ export default function ItemSettingsModal({id, sectionId, defaultNewItemType, on placeholder={Translate.string('Permanent')} step="1" min="1" - validate={v.optional(v.min(1))} + max="521" + validate={v.optional(v.range(1, 521))} label={Translate.string('Retention period (weeks)')} /> diff --git a/indico/modules/events/registration/controllers/management/fields.py b/indico/modules/events/registration/controllers/management/fields.py index 038d97fd839..3dfa6fe0f77 100644 --- a/indico/modules/events/registration/controllers/management/fields.py +++ b/indico/modules/events/registration/controllers/management/fields.py @@ -5,6 +5,8 @@ # modify it under the terms of the MIT License; see the # LICENSE file for more details. +from datetime import timedelta + from flask import jsonify, request, session from marshmallow import EXCLUDE, ValidationError, fields, post_load, validates from werkzeug.exceptions import BadRequest @@ -51,6 +53,8 @@ def _check_retention_period(self, retention_period, **kwargs): if retention_period is not None: if retention_period.days < 7: raise ValidationError('Retention period must be at least 1 week') + if retention_period > timedelta(days=3650): + raise ValidationError('Retention period cannot be longer than 10 years') if field.type == RegistrationFormItemType.field_pd and field.personal_data_type.is_required: raise ValidationError('Cannot add retention period to required field') diff --git a/indico/modules/events/registration/forms.py b/indico/modules/events/registration/forms.py index 2c35238fce7..01ac04c2a8c 100644 --- a/indico/modules/events/registration/forms.py +++ b/indico/modules/events/registration/forms.py @@ -144,15 +144,23 @@ def validate_visibility(self, field): if participant_visibility.value < public_visibility.value: raise ValidationError(_('Participant visibility cannot be more restrictive for other participants than ' 'for the public')) - if field.data[2] is not None and not field.data[2]: - raise ValidationError(_('The visibility duration cannot be zero.')) + if field.data[2] is not None: + visibility_duration = timedelta(weeks=field.data[2]) + if visibility_duration <= timedelta(): + raise ValidationError(_('The visibility duration cannot be zero.')) + elif visibility_duration > timedelta(days=3650): + raise ValidationError(_('The visibility duration cannot be longer than 10 years. Leave the field empty ' + 'for indefinite.')) def validate_retention_period(self, field): retention_period = field.data if retention_period is None: return - elif not retention_period: - raise ValidationError(_('The retention period cannot be zero.')) + elif retention_period <= timedelta(): + raise ValidationError(_('The retention period cannot be zero or negative.')) + elif retention_period > timedelta(days=3650): + raise ValidationError(_('The retention period cannot be longer than 10 years. Leave the field empty for ' + 'indefinite.')) visibility_duration = (timedelta(weeks=self.visibility.data[2]) if self.visibility.data[2] is not None else None) if visibility_duration and visibility_duration > retention_period: @@ -555,15 +563,23 @@ def validate_visibility(self, field): ~Registration.created_by_manager).has_rows() ): raise ValidationError(_("'Show all participants' can only be set if there are no registered users.")) - if field.data[2] is not None and not field.data[2]: - raise ValidationError(_('The visibility duration cannot be zero.')) + if field.data[2] is not None: + visibility_duration = timedelta(weeks=field.data[2]) + if visibility_duration <= timedelta(): + raise ValidationError(_('The visibility duration cannot be zero.')) + elif visibility_duration > timedelta(days=3650): + raise ValidationError(_('The visibility duration cannot be longer than 10 years. Leave the field empty ' + 'for indefinite.')) def validate_retention_period(self, field): retention_period = field.data if retention_period is None: return - elif not retention_period: - raise ValidationError(_('The retention period cannot be zero.')) + elif retention_period <= timedelta(): + raise ValidationError(_('The retention period cannot be zero or negative.')) + elif retention_period > timedelta(days=3650): + raise ValidationError(_('The retention period cannot be longer than 10 years. Leave the field empty for ' + 'indefinite.')) visibility_duration = (timedelta(weeks=self.visibility.data[2]) if self.visibility.data[2] is not None else None) if visibility_duration and visibility_duration > retention_period: diff --git a/indico/web/client/js/react/components/WTFParticipantVisibilityField.jsx b/indico/web/client/js/react/components/WTFParticipantVisibilityField.jsx index 0fb27237861..5d4e8c7f224 100644 --- a/indico/web/client/js/react/components/WTFParticipantVisibilityField.jsx +++ b/indico/web/client/js/react/components/WTFParticipantVisibilityField.jsx @@ -90,7 +90,8 @@ export default function WTFParticipantVisibilityField({fieldId, wrapperId, value type="number" placeholder={Translate.string('Permanent')} step="1" - min="0" + min="1" + max="521" value={visibilityDuration === null ? '' : visibilityDuration} onChange={(evt, {value}) => setVisibilityDuration(value === '' ? null : +value)} disabled={participantVisibility === 'hide_all'}