138 lines
5.5 KiB
Python
138 lines
5.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import datetime
|
|
import urllib2
|
|
import vobject
|
|
import rfc822
|
|
|
|
from zope import component
|
|
from zope.event import notify
|
|
from zope.lifecycleevent import ObjectAddedEvent, ObjectModifiedEvent
|
|
|
|
from Products.CMFCore.WorkflowCore import WorkflowException
|
|
from Products.CMFCore.utils import getToolByName
|
|
from Products.Five.browser import BrowserView
|
|
from plone.registry.interfaces import IRegistry
|
|
from plone.app.textfield.value import RichTextValue
|
|
|
|
from tabellio.config.interfaces import ITabellioSettings
|
|
|
|
class IcalImport(BrowserView):
|
|
def __call__(self):
|
|
self.settings = component.getUtility(IRegistry).forInterface(ITabellioSettings, False)
|
|
self.plone_utils = getToolByName(self.context, 'plone_utils')
|
|
self.portal_workflow = getToolByName(self.context, 'portal_workflow')
|
|
url = self.request.form.get('url')
|
|
|
|
if self.settings.ical_username:
|
|
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
|
|
password_mgr.add_password(None, url,
|
|
self.settings.ical_username, self.settings.ical_password)
|
|
handler = urllib2.HTTPBasicAuthHandler(password_mgr)
|
|
opener = urllib2.build_opener(handler)
|
|
urlopen = opener.open
|
|
else:
|
|
urlopen = urllib2.urlopen
|
|
content = urlopen(url).read()
|
|
parsed_cal = vobject.readOne(content)
|
|
seen_ids = []
|
|
created = 0
|
|
updated = 0
|
|
for vevent in parsed_cal.vevent_list:
|
|
title = vevent.summary.value
|
|
date_start = vevent.dtstart.value
|
|
if isinstance(date_start, datetime.datetime):
|
|
date_start = datetime.datetime(*date_start.timetuple()[:6])
|
|
elif isinstance(date_start, datetime.date):
|
|
date_start = datetime.datetime.fromordinal(date_start.toordinal())
|
|
try:
|
|
date_end = vevent.dtend.value
|
|
if isinstance(date_end, datetime.datetime):
|
|
date_end = datetime.datetime(*date_end.timetuple()[:6])
|
|
elif isinstance(date_end, datetime.date):
|
|
date_end = datetime.datetime.fromordinal(date_end.toordinal())
|
|
except:
|
|
date_end = None
|
|
|
|
location = None
|
|
try:
|
|
location = vevent.location.value
|
|
except:
|
|
pass
|
|
|
|
if location and '@' in location:
|
|
try:
|
|
location, email = rfc822.parseaddr(location)
|
|
except:
|
|
pass
|
|
|
|
if location:
|
|
# some special substitutions for PCF common locations
|
|
location = location.replace(u'HL ', u'Hôtel de Ligne - ')
|
|
location = location.replace(u'HG ', u'Hôtel du Greffe - ')
|
|
|
|
base_id = '%(year)04d%(month)02d%(day)02d'
|
|
base_parts = {'year': date_start.year,
|
|
'month': date_start.month,
|
|
'day': date_start.day}
|
|
if date_start.hour != 0 and date_start.minute != 0:
|
|
base_id = base_id + '-%(hour)02d%(minute)02d'
|
|
base_parts.update({'hour': date_start.hour,
|
|
'minute': date_start.minute})
|
|
if location:
|
|
base_id = base_id + '-%(location)s'
|
|
base_parts.update({'location': location})
|
|
if title:
|
|
base_id = base_id + '-%(title)s'
|
|
base_parts.update({'title': title})
|
|
event_id = self.plone_utils.normalizeString(base_id % base_parts)
|
|
if not hasattr(self.context, event_id):
|
|
self.context.invokeFactory('tabellio.agenda.event', event_id, title=title)
|
|
created += 1
|
|
else:
|
|
updated += 1
|
|
event = getattr(self.context, event_id)
|
|
event.title = title
|
|
event.start = date_start
|
|
event.end = date_end
|
|
description = None
|
|
try:
|
|
description = vevent.description.value
|
|
except:
|
|
pass
|
|
if description:
|
|
event.text = RichTextValue(raw=description,
|
|
mimeType='text/plain', outputMimeType='text/x-html-safe')
|
|
description = None
|
|
try:
|
|
description = vevent.x_alt_desc.value
|
|
except:
|
|
pass
|
|
if description and type(description) is unicode:
|
|
# there's some bug in the transformation chain that will at
|
|
# the wrong time convert the   and turn it into an invalid
|
|
# utf-8 character, therefore we replace all of them right now,
|
|
# as it's safe to do.
|
|
description = description.replace(' ', u'\xa0')
|
|
if description:
|
|
event.text = RichTextValue(raw=description,
|
|
mimeType='text/html', outputMimeType='text/x-html-safe')
|
|
|
|
event.place = location
|
|
|
|
notify(ObjectModifiedEvent(event))
|
|
try:
|
|
self.portal_workflow.doActionFor(getattr(self.context, event_id), 'publish')
|
|
except WorkflowException:
|
|
pass
|
|
seen_ids.append(event.id)
|
|
|
|
deleted = 0
|
|
for event_id in self.context.objectIds():
|
|
if event_id in seen_ids:
|
|
continue
|
|
self.context.manage_delObjects(event_id)
|
|
deleted += 1
|
|
|
|
return 'OK (created: %s, updated: %s, deleted: %s)' % (created, updated, deleted)
|