1.1 --- a/EventAggregatorSupport/Resources.py Wed Jan 29 19:20:21 2014 +0100
1.2 +++ b/EventAggregatorSupport/Resources.py Wed Jan 29 19:21:20 2014 +0100
1.3 @@ -11,7 +11,7 @@
1.4
1.5 from DateSupport import Date, Month
1.6 from MoinSupport import *
1.7 -from MoinRemoteSupport import getCachedResource, getCachedResourceMetadata
1.8 +from MoinRemoteSupport import getCachedResource, getCachedResourceMetadata, imapreader
1.9
1.10 import urllib
1.11
1.12 @@ -96,6 +96,16 @@
1.13 if url.startswith("file:"):
1.14 return None
1.15
1.16 + # Support IMAP access.
1.17 +
1.18 + elif url.startswith("imap"):
1.19 + reader = imapreader
1.20 +
1.21 + # Otherwise, use the default access mechanism.
1.22 +
1.23 + else:
1.24 + reader = None
1.25 +
1.26 # Parameterise the URL.
1.27 # Where other parameters are used, care must be taken to encode them
1.28 # properly.
1.29 @@ -111,15 +121,15 @@
1.30 parser = parseEventsInCalendarFromResource
1.31 required_content_type = expected_content_type or "text/calendar"
1.32 elif format == "xcal":
1.33 - parser = parseEventsInXMLCalendarFromResource
1.34 - required_content_type = expected_content_type or "application/calendar+xml"
1.35 + parser = parseEventsInXMLCalendarsFromResource
1.36 + required_content_type = expected_content_type or "multipart/mixed"
1.37 else:
1.38 return None
1.39
1.40 # Obtain the resource, using a cached version if appropriate.
1.41
1.42 max_cache_age = int(getattr(request.cfg, "event_aggregator_max_cache_age", "300"))
1.43 - data = getCachedResource(request, url, "EventAggregator", "wiki", max_cache_age)
1.44 + data = getCachedResource(request, url, "EventAggregator", "wiki", max_cache_age, reader)
1.45 if not data:
1.46 return None
1.47
2.1 --- a/EventAggregatorSupport/Types.py Wed Jan 29 19:20:21 2014 +0100
2.2 +++ b/EventAggregatorSupport/Types.py Wed Jan 29 19:21:20 2014 +0100
2.3 @@ -15,6 +15,7 @@
2.4 import vCalendar
2.5
2.6 from codecs import getreader
2.7 +from email.parser import Parser
2.8 from email.utils import parsedate
2.9 import re
2.10
2.11 @@ -131,6 +132,34 @@
2.12 else:
2.13 return None
2.14
2.15 +def parseEventsInXMLCalendarsFromResource(f, encoding=None, url=None, metadata=None):
2.16 +
2.17 + """
2.18 + Parse a collection of events in xCalendar format from the given file-like
2.19 + object 'f', with content having any specified 'encoding' and being described
2.20 + by the given 'url' and 'metadata'.
2.21 + """
2.22 +
2.23 + message = Parser().parse(f)
2.24 + resources = EventResourceCollection(url or "", metadata or {})
2.25 +
2.26 + for data in message.get_payload():
2.27 +
2.28 + # Find the calendar data.
2.29 +
2.30 + if data.is_multipart():
2.31 + for part in data.get_payload():
2.32 + if part.get_content_type() == "application/calendar+xml":
2.33 + text = part
2.34 + else:
2.35 + text = data
2.36 +
2.37 + # Obtain a calendar and merge it into the collection.
2.38 +
2.39 + resources.append(parseEventsInXMLCalendarFromResource(StringIO(text.get_payload(decode=True))))
2.40 +
2.41 + return resources
2.42 +
2.43 def parseEvents(text, event_page, fragment=None):
2.44
2.45 """
2.46 @@ -239,8 +268,10 @@
2.47
2.48 "A resource providing event information."
2.49
2.50 - def __init__(self, url):
2.51 + def __init__(self, url, metadata=None):
2.52 self.url = url
2.53 + self.metadata = metadata
2.54 + self.events = None
2.55
2.56 def getPageURL(self):
2.57
2.58 @@ -262,13 +293,13 @@
2.59 "last-comment" made about the last edit.
2.60 """
2.61
2.62 - return {}
2.63 + return self.metadata or {}
2.64
2.65 def getEvents(self):
2.66
2.67 "Return a list of events from this resource."
2.68
2.69 - return []
2.70 + return self.events or []
2.71
2.72 def linkToPage(self, request, text, query_string=None, anchor=None):
2.73
2.74 @@ -291,14 +322,30 @@
2.75
2.76 return fmt.text(text)
2.77
2.78 +class EventResourceCollection(EventResource):
2.79 +
2.80 + "A collection of resources."
2.81 +
2.82 + def __init__(self, url, metadata=None):
2.83 + self.url = url
2.84 + self.metadata = metadata
2.85 + self.resources = []
2.86 +
2.87 + def append(self, resource):
2.88 + self.resources.append(resource)
2.89 +
2.90 + def getEvents(self):
2.91 + events = []
2.92 + for resource in self.resources:
2.93 + events += resource.getEvents()
2.94 + return events
2.95 +
2.96 class EventCalendarResource(EventResource):
2.97
2.98 "A generic calendar resource."
2.99
2.100 def __init__(self, url, metadata):
2.101 - EventResource.__init__(self, url)
2.102 - self.metadata = metadata
2.103 - self.events = None
2.104 + EventResource.__init__(self, url, metadata)
2.105
2.106 if not self.metadata.has_key("created") and self.metadata.has_key("date"):
2.107 self.metadata["created"] = DateTime(parsedate(self.metadata["date"])[:7])
2.108 @@ -306,16 +353,6 @@
2.109 if self.metadata.has_key("last-modified") and not isinstance(self.metadata["last-modified"], DateTime):
2.110 self.metadata["last-modified"] = DateTime(parsedate(self.metadata["last-modified"])[:7])
2.111
2.112 - def getMetadata(self):
2.113 -
2.114 - """
2.115 - Return a dictionary containing items describing the page's "created"
2.116 - time, "last-modified" time, "sequence" (or revision number) and the
2.117 - "last-comment" made about the last edit.
2.118 - """
2.119 -
2.120 - return self.metadata
2.121 -
2.122 class EventCalendar(EventCalendarResource):
2.123
2.124 "An iCalendar resource."
2.125 @@ -324,16 +361,6 @@
2.126 EventCalendarResource.__init__(self, url, metadata)
2.127 self.calendar = calendar
2.128
2.129 - def getMetadata(self):
2.130 -
2.131 - """
2.132 - Return a dictionary containing items describing the page's "created"
2.133 - time, "last-modified" time, "sequence" (or revision number) and the
2.134 - "last-comment" made about the last edit.
2.135 - """
2.136 -
2.137 - return self.metadata
2.138 -
2.139 def getEvents(self):
2.140
2.141 "Return a list of events from this resource."
2.142 @@ -451,6 +478,8 @@
2.143
2.144 return self.events
2.145
2.146 + # Parsing methods.
2.147 +
2.148 def _getValue(self, values, type):
2.149 for element in values[0].xpath("xcal:%s" % type, namespaces=self.XCAL):
2.150 return element.textContent