passerelle/passerelle/apps/holidays/models.py

113 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 dHiver",
'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')