generate ICS with iCalendar package

This commit is contained in:
Élie Bouttier 2017-09-18 14:01:27 +02:00
parent f63b0b9cda
commit 0a1442b450
7 changed files with 29 additions and 43 deletions

View File

@ -320,18 +320,6 @@ class Talk(PonyConfModel):
else: else:
return None return None
@property
def dtstart(self):
return self.start_date.strftime('%Y%m%dT%H%M%SZ')
@property
def dtend(self):
return self.end_date.strftime('%Y%m%dT%H%M%SZ')
@property
def dtstamp(self):
return self.updated.strftime('%Y%m%dT%H%M%SZ')
#@property #@property
#def materials_name(self): #def materials_name(self):
# return basename(self.materials.name) # return basename(self.materials.name)

View File

@ -5,6 +5,7 @@ from django.utils.timezone import localtime
from django.core.cache import cache from django.core.cache import cache
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.template.loader import get_template from django.template.loader import get_template
from django.conf import settings
from datetime import datetime, timedelta from datetime import datetime, timedelta
from copy import deepcopy from copy import deepcopy
@ -12,6 +13,7 @@ from collections import OrderedDict, namedtuple
from itertools import islice from itertools import islice
from zlib import adler32 from zlib import adler32
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from icalendar import Calendar as iCalendar, Event as iEvent
from .models import Conference, Talk, Room from .models import Conference, Talk, Room
@ -252,7 +254,27 @@ class Program:
def _as_ics(self): def _as_ics(self):
if not self.initialized: if not self.initialized:
self._lazy_init() self._lazy_init()
return get_template('cfp/planning.ics').render({'site': self.site, 'talks': self.talks}) cal = iCalendar()
cal.add('prodid', '-//PonyConf.io//PonyConf//FR')
cal.add('version', '2.0')
cal.add('x-wr-calname', self.conference.name)
cal.add('x-wr-timezone', settings.TIME_ZONE)
cal.add('calscale', 'GREGORIAN')
for talk in self.talks.all():
event = iEvent()
event.add('dtstart', talk.start_date)
if not talk.end_date:
continue
event.add('dtend', talk.end_date)
event.add('dtstamp', talk.updated)
event.add('summary', talk.title)
if talk.room:
event.add('location', talk.room)
event.add('status', 'CONFIRMED' if talk.accepted else 'TENTATIVE')
event.add('description', talk.description)
event.add('uid', '%s/%s' % (self.site.domain, talk.id))
cal.add_component(event)
return cal.to_ical()
def render(self, output='html'): def render(self, output='html'):
if self.cache: if self.cache:

View File

@ -1,18 +0,0 @@
BEGIN:VCALENDAR
PRODID:-//{{ site.domain }}//{{ site.name }}//FR
X-WR-CALNAME:{{ site.name }}
X-WR-TIMEZONE:Europe/Paris
VERSION:2.0
CALSCALE:GREGORIAN
{% for talk in talks %}
BEGIN:VEVENT
DTSTAMP:{{ talk.dtstamp }}
DTSTART:{{ talk.dtstart }}
DTEND:{{ talk.dtend }}
SUMMARY:{{ talk.title }}
LOCATION:{{ talk.room }}
STATUS:{% if talk.accepted %}CONFIRMED{% else %}TENTATIVE{% endif %}
DESCRIPTION:{{ talk.description|linebreaksbr }}
UID:{{ site.domain }}/{{ talk.id }}
END:VEVENT{% endfor %}
END:VCALENDAR

View File

@ -481,17 +481,8 @@ def schedule(request, program_format, pending, cache, template):
elif program_format == 'xml': elif program_format == 'xml':
return HttpResponse(program.render('xml'), content_type="application/xml") return HttpResponse(program.render('xml'), content_type="application/xml")
elif program_format == 'ics': elif program_format == 'ics':
response = HttpResponse('', content_type='text/plain') response = HttpResponse(program.render('ics'), content_type='text/calendar')
response['Content-Disposition'] = 'attachment; filename="planning.ics"' response['Content-Disposition'] = 'attachment; filename="planning.ics"'
ics = []
for line in program.render('ics').split('\n'):
line = line.strip().replace('<br />', '')
if len(line) < 50:
ics.append(line)
else: # https://icalendar.org/iCalendar-RFC-5545/3-1-content-lines.html
for i in range(ceil(len(line) / 50)):
ics.append((' ' if i > 0 else '') + line[i * 50:(i + 1) * 50])
response.write('\r\n'.join([line for line in ics if line]).strip() + '\r\n')
return response return response
else: else:
raise Http404(_("Format '%s' not available" % program_format)) raise Http404(_("Format '%s' not available" % program_format))

View File

@ -10,3 +10,4 @@ django-colorful
markdown markdown
bleach bleach
chardet chardet
icalendar

View File

@ -15,7 +15,9 @@ django-crispy-forms==1.6.1
django-select2==5.11.1 django-select2==5.11.1
django==1.11.5 django==1.11.5
html5lib==0.999999999 # via bleach html5lib==0.999999999 # via bleach
icalendar==3.11.7
markdown==2.6.9 markdown==2.6.9
pytz==2017.2 # via django python-dateutil==2.6.1 # via icalendar
six==1.10.0 # via bleach, django-bower, html5lib pytz==2017.2 # via django, icalendar
six==1.10.0 # via bleach, django-bower, html5lib, python-dateutil
webencodings==0.5.1 # via html5lib webencodings==0.5.1 # via html5lib