API: Add endpoints for scheduled exports (#3659)

* API: Add endpoints for scheduled exports

* ADd note to docs
This commit is contained in:
Raphael Michel
2023-10-27 17:15:53 +02:00
committed by GitHub
parent 26cbc24a10
commit 3b64e6046c
10 changed files with 1389 additions and 14 deletions

View File

@@ -79,7 +79,7 @@ class AbstractScheduledExport(LoggedModel):
)
schedule_rrule = models.TextField(
null=True, blank=True, validators=[RRuleValidator()]
null=True, blank=True, validators=[RRuleValidator(enforce_simple=True)]
)
schedule_rrule_time = models.TimeField(
verbose_name=_("Requested start time"),

View File

@@ -19,7 +19,9 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from dateutil.rrule import rrulestr
import calendar
from dateutil.rrule import DAILY, MONTHLY, WEEKLY, YEARLY, rrule, rrulestr
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
@@ -40,7 +42,6 @@ from django.utils.translation import gettext_lazy as _
class BanlistValidator:
banlist = []
def __call__(self, value):
@@ -55,7 +56,6 @@ class BanlistValidator:
@deconstructible
class EventSlugBanlistValidator(BanlistValidator):
banlist = [
'download',
'healthcheck',
@@ -77,7 +77,6 @@ class EventSlugBanlistValidator(BanlistValidator):
@deconstructible
class OrganizerSlugBanlistValidator(BanlistValidator):
banlist = [
'download',
'healthcheck',
@@ -98,7 +97,6 @@ class OrganizerSlugBanlistValidator(BanlistValidator):
@deconstructible
class EmailBanlistValidator(BanlistValidator):
banlist = [
settings.PRETIX_EMAIL_NONE_VALUE,
]
@@ -112,8 +110,45 @@ def multimail_validate(val):
class RRuleValidator:
def __init__(self, enforce_simple=False):
self.enforce_simple = enforce_simple
def __call__(self, value):
try:
rrulestr(value)
parsed = rrulestr(value)
except Exception:
raise ValidationError("Not a valid rrule.")
if self.enforce_simple:
# Validate that only things are used that we can represent in our UI for later editing
if not isinstance(parsed, rrule):
raise ValidationError("Only a single RRULE is allowed, no combination of rules.")
if parsed._freq not in (YEARLY, MONTHLY, WEEKLY, DAILY):
raise ValidationError("Unsupported FREQ value")
if parsed._wkst != calendar.firstweekday():
raise ValidationError("Unsupported WKST value")
if parsed._bysetpos:
if len(parsed._bysetpos) > 1:
raise ValidationError("Only one BYSETPOS value allowed")
if parsed._freq == YEARLY and parsed._bysetpos not in (1, 2, 3, -1):
raise ValidationError("BYSETPOS value not allowed, should be 1, 2, 3 or -1")
elif parsed._freq == MONTHLY and parsed._bysetpos not in (1, 2, 3, -1):
raise ValidationError("BYSETPOS value not allowed, should be 1, 2, 3 or -1")
elif parsed._freq not in (YEARLY, MONTHLY):
raise ValidationError("BYSETPOS not allowed for this FREQ")
if parsed._bymonthday:
raise ValidationError("BYMONTHDAY not supported")
if parsed._byyearday:
raise ValidationError("BYYEARDAY not supported")
if parsed._byeaster:
raise ValidationError("BYEASTER not supported")
if parsed._byweekno:
raise ValidationError("BYWEEKNO not supported")
if len(parsed._byhour) > 1 or set(parsed._byhour) != {parsed._dtstart.hour}:
raise ValidationError("BYHOUR not supported")
if len(parsed._byminute) > 1 or set(parsed._byminute) != {parsed._dtstart.minute}:
raise ValidationError("BYMINUTE not supported")
if len(parsed._bysecond) > 1 or set(parsed._bysecond) != {parsed._dtstart.second}:
raise ValidationError("BYSECOND not supported")