manager: allow templated ICS URL (#66323)
This commit is contained in:
parent
2e9fe5b794
commit
9dbf6b1d5c
|
@ -2422,18 +2422,19 @@ class TimePeriodExceptionSource(models.Model):
|
|||
|
||||
def _check_ics_content(self):
|
||||
if self.ics_url:
|
||||
ics_url = Template(self.ics_url).render(Context(settings.TEMPLATE_VARS))
|
||||
try:
|
||||
response = requests.get(self.ics_url, proxies=settings.REQUESTS_PROXIES)
|
||||
response = requests.get(ics_url, proxies=settings.REQUESTS_PROXIES)
|
||||
response.raise_for_status()
|
||||
except requests.HTTPError as e:
|
||||
raise ICSError(
|
||||
_('Failed to retrieve remote calendar (%(url)s, HTTP error %(status_code)s).')
|
||||
% {'url': self.ics_url, 'status_code': e.response.status_code}
|
||||
% {'url': ics_url, 'status_code': e.response.status_code}
|
||||
)
|
||||
except requests.RequestException as e:
|
||||
raise ICSError(
|
||||
_('Failed to retrieve remote calendar (%(url)s, %(exception)s).')
|
||||
% {'url': self.ics_url, 'exception': e}
|
||||
% {'url': ics_url, 'exception': e}
|
||||
)
|
||||
try:
|
||||
# override response encoding received in HTTP headers as it may
|
||||
|
|
|
@ -28,9 +28,11 @@ from django import forms
|
|||
from django.conf import settings
|
||||
from django.contrib.auth.models import Group
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.core.validators import URLValidator
|
||||
from django.db import transaction
|
||||
from django.db.models import DurationField, ExpressionWrapper, F
|
||||
from django.forms import ValidationError, formset_factory
|
||||
from django.template import Context, Template, TemplateSyntaxError, VariableDoesNotExist
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.formats import date_format
|
||||
from django.utils.timezone import localtime, make_aware, now
|
||||
|
@ -1195,8 +1197,9 @@ class ExceptionsImportForm(forms.ModelForm):
|
|||
required=False,
|
||||
help_text=_('ICS file containing events which will be considered as exceptions.'),
|
||||
)
|
||||
ics_url = forms.URLField(
|
||||
ics_url = forms.CharField(
|
||||
label=_('URL'),
|
||||
max_length=200,
|
||||
required=False,
|
||||
help_text=_('URL to remote calendar which will be synchronised hourly.'),
|
||||
)
|
||||
|
@ -1206,6 +1209,20 @@ class ExceptionsImportForm(forms.ModelForm):
|
|||
if not cleaned_data.get('ics_file') and not cleaned_data.get('ics_url'):
|
||||
raise forms.ValidationError(_('Please provide an ICS File or an URL.'))
|
||||
|
||||
def clean_ics_url(self):
|
||||
url = self.cleaned_data['ics_url']
|
||||
if not url:
|
||||
return url
|
||||
|
||||
try:
|
||||
url = Template(url).render(Context(settings.TEMPLATE_VARS))
|
||||
except (TemplateSyntaxError, VariableDoesNotExist) as e:
|
||||
raise ValidationError(_('syntax error: %s') % e)
|
||||
|
||||
URLValidator()(url)
|
||||
|
||||
return self.cleaned_data['ics_url']
|
||||
|
||||
|
||||
class DeskExceptionsImportForm(ExceptionsImportForm):
|
||||
all_desks = forms.BooleanField(label=_('Apply exceptions on all desks of the agenda'), required=False)
|
||||
|
|
|
@ -772,6 +772,41 @@ def test_agenda_import_time_period_exception_from_remote_ics_with_ssl_error(mock
|
|||
assert 'Failed to retrieve remote calendar (https://example.com/foo.ics, SSL error).' in resp.text
|
||||
|
||||
|
||||
@override_settings(TEMPLATE_VARS={'passerelle_url': 'https://passerelle.publik.love/'})
|
||||
@mock.patch('chrono.agendas.models.requests.get')
|
||||
def test_agenda_import_time_period_exception_with_remote_ics_templated_url(mocked_get, app, admin_user):
|
||||
agenda = Agenda.objects.create(label='New Example', kind='meetings')
|
||||
desk = Desk.objects.create(agenda=agenda, label='New Desk')
|
||||
login(app)
|
||||
|
||||
resp = app.get('/manage/agendas/desk/%s/import-exceptions-from-ics/' % desk.pk)
|
||||
resp.form['ics_url'] = '{{ passerelle_url }}holidays/test/holidays.ics'
|
||||
mocked_response = mock.Mock()
|
||||
mocked_response.text = """BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:-//foo.bar//EN
|
||||
BEGIN:VEVENT
|
||||
DTSTART:20180101
|
||||
DTEND:20180101
|
||||
SUMMARY:New Year's Eve
|
||||
END:VEVENT
|
||||
END:VCALENDAR"""
|
||||
mocked_get.return_value = mocked_response
|
||||
resp = resp.form.submit(status=302)
|
||||
assert TimePeriodException.objects.filter(desk=desk).count() == 1
|
||||
assert TimePeriodExceptionSource.objects.filter(desk=desk).count() == 1
|
||||
assert mocked_get.call_args.args[0] == 'https://passerelle.publik.love/holidays/test/holidays.ics'
|
||||
|
||||
resp = app.get('/manage/agendas/desk/%s/import-exceptions-from-ics/' % desk.pk)
|
||||
resp.form['ics_url'] = '{{ unknown }}holidays/test/holidays.ics'
|
||||
resp = resp.form.submit(status=200)
|
||||
assert 'Enter a valid URL.' in resp.text
|
||||
|
||||
resp.form['ics_url'] = '{{ { }}holidays/test/holidays.ics'
|
||||
resp = resp.form.submit(status=200)
|
||||
assert 'syntax error' in resp.text
|
||||
|
||||
|
||||
@mock.patch('chrono.agendas.models.requests.get')
|
||||
def test_agenda_import_time_period_exception_url_desk_all_desks(mocked_get, app, admin_user):
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
|
||||
|
|
Loading…
Reference in New Issue