generate ICS with iCalendar package
This commit is contained in:
parent
f63b0b9cda
commit
0a1442b450
|
@ -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)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
|
11
cfp/views.py
11
cfp/views.py
|
@ -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))
|
||||||
|
|
|
@ -10,3 +10,4 @@ django-colorful
|
||||||
markdown
|
markdown
|
||||||
bleach
|
bleach
|
||||||
chardet
|
chardet
|
||||||
|
icalendar
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue