113 lines
3.9 KiB
Python
113 lines
3.9 KiB
Python
# Copyright (C) 2022 Entr'ouvert
|
||
#
|
||
# This program is free software: you can redistribute it and/or modify it
|
||
# under the terms of the GNU Affero General Public License as published
|
||
# by the Free Software Foundation, either version 3 of the License, or
|
||
# (at your option) any later version.
|
||
#
|
||
# This program is distributed in the hope that it will be useful,
|
||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
# GNU Affero General Public License for more details.
|
||
#
|
||
# You should have received a copy of the GNU Affero General Public License
|
||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
import requests
|
||
import vobject
|
||
from django.contrib.postgres.fields import ArrayField
|
||
from django.db import models
|
||
from django.http import HttpResponse
|
||
from django.utils.translation import gettext_lazy as _
|
||
|
||
from passerelle.base.models import BaseResource
|
||
from passerelle.utils.api import endpoint
|
||
from passerelle.utils.jsonresponse import APIError
|
||
|
||
from .forms import HolidaysConnectorForm
|
||
|
||
ZONE_CHOICES = (
|
||
('a', 'A'),
|
||
('b', 'B'),
|
||
('c', 'C'),
|
||
)
|
||
|
||
HOLIDAYS_LABELS = {
|
||
'winter_holidays': "Vacances d’Hiver",
|
||
'spring_holidays': 'Vacances de Pâques',
|
||
'summer_holidays': "Vacances d’Été",
|
||
'all_saints_holidays': 'Vacances de la Toussaint',
|
||
'christmas_holidays': 'Vacances de Noël',
|
||
}
|
||
|
||
|
||
HOLIDAYS_CHOICES = [(x[0], x[1]) for x in HOLIDAYS_LABELS.items()]
|
||
|
||
|
||
ZONE_URLS = {
|
||
'a': 'https://fr.ftp.opendatasoft.com/openscol/fr-en-calendrier-scolaire/Zone-A.ics',
|
||
'b': 'https://fr.ftp.opendatasoft.com/openscol/fr-en-calendrier-scolaire/Zone-B.ics',
|
||
'c': 'https://fr.ftp.opendatasoft.com/openscol/fr-en-calendrier-scolaire/Zone-C.ics',
|
||
}
|
||
|
||
|
||
HOLIDAYS_MAPPING = {
|
||
"Vacances d'Hiver": 'winter_holidays',
|
||
'Vacances de Printemps': 'spring_holidays',
|
||
"Vacances d'Été": 'summer_holidays',
|
||
'Vacances de la Toussaint': 'all_saints_holidays',
|
||
'Vacances de Noël': 'christmas_holidays',
|
||
}
|
||
|
||
|
||
class Holidays(BaseResource):
|
||
zone = models.CharField(_('Zone'), max_length=16, choices=ZONE_CHOICES)
|
||
holidays = ArrayField(
|
||
models.CharField(max_length=32, choices=HOLIDAYS_CHOICES),
|
||
verbose_name=_('Holidays'),
|
||
blank=False,
|
||
null=False,
|
||
)
|
||
|
||
category = _('Misc')
|
||
manager_form_base_class = HolidaysConnectorForm
|
||
|
||
class Meta:
|
||
verbose_name = _('School holidays')
|
||
|
||
def get_holidays_display(self):
|
||
return ', '.join(HOLIDAYS_LABELS[holiday] for holiday in self.holidays)
|
||
|
||
@endpoint(name='holidays.ics', description=_('Get holidays ICS.'), perm='OPEN')
|
||
def holidays_ics(self, request):
|
||
try:
|
||
response = self.requests.get(ZONE_URLS[self.zone])
|
||
response.raise_for_status()
|
||
except requests.exceptions.RequestException as e:
|
||
raise APIError('Error while getting ICS file: %s' % e)
|
||
|
||
try:
|
||
parsed = vobject.readOne(response.text)
|
||
except vobject.base.ParseError as e:
|
||
raise APIError('Invalid ICS file: %s' % e)
|
||
|
||
if not parsed.contents.get('vevent'):
|
||
raise APIError('ICS file does not contain events.')
|
||
|
||
cal = vobject.iCalendar()
|
||
for vevent in parsed.contents.get('vevent'):
|
||
description = vevent.contents['summary'][0].value
|
||
|
||
holiday_id = HOLIDAYS_MAPPING.get(description)
|
||
if holiday_id not in self.holidays:
|
||
continue
|
||
|
||
new_vevent = cal.add('vevent')
|
||
new_vevent.add('summary').value = HOLIDAYS_LABELS[holiday_id]
|
||
new_vevent.add('uid').value = '%s-%s' % (holiday_id, vevent.dtstart.value.year)
|
||
new_vevent.add('categories').value = [holiday_id]
|
||
new_vevent.add('dtstart').value = vevent.dtstart.value
|
||
new_vevent.add('dtend').value = vevent.dtend.value
|
||
|
||
return HttpResponse(cal.serialize(), content_type='text/calendar')
|