1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/EventAggregatorSupport/Resources.py Tue Apr 30 23:49:32 2013 +0200
1.3 @@ -0,0 +1,205 @@
1.4 +# -*- coding: iso-8859-1 -*-
1.5 +"""
1.6 + MoinMoin - EventAggregator resource acquisition and access
1.7 +
1.8 + @copyright: 2008, 2009, 2010, 2011, 2012, 2013 by Paul Boddie <paul@boddie.org.uk>
1.9 + @license: GNU GPL (v2 or later), see COPYING.txt for details.
1.10 +"""
1.11 +
1.12 +from EventAggregatorSupport.Filter import *
1.13 +from EventAggregatorSupport.Types import *
1.14 +
1.15 +from ContentTypeSupport import getContentTypeAndEncoding
1.16 +from DateSupport import Date, Month
1.17 +from MoinSupport import *
1.18 +from MoinRemoteSupport import getCachedResource
1.19 +
1.20 +import codecs
1.21 +import urllib
1.22 +
1.23 +try:
1.24 + from cStringIO import StringIO
1.25 +except ImportError:
1.26 + from StringIO import StringIO
1.27 +
1.28 +try:
1.29 + import vCalendar
1.30 +except ImportError:
1.31 + vCalendar = None
1.32 +
1.33 +# Obtaining event containers and events from such containers.
1.34 +
1.35 +def getEventPages(pages):
1.36 +
1.37 + "Return a list of events found on the given 'pages'."
1.38 +
1.39 + # Get real pages instead of result pages.
1.40 +
1.41 + return map(EventPage, pages)
1.42 +
1.43 +def getAllEventSources(request):
1.44 +
1.45 + "Return all event sources defined in the Wiki using the 'request'."
1.46 +
1.47 + sources_page = getattr(request.cfg, "event_aggregator_sources_page", "EventSourcesDict")
1.48 +
1.49 + # Remote sources are accessed via dictionary page definitions.
1.50 +
1.51 + return getWikiDict(sources_page, request)
1.52 +
1.53 +def getEventResources(sources, calendar_start, calendar_end, request):
1.54 +
1.55 + """
1.56 + Return resource objects for the given 'sources' using the given
1.57 + 'calendar_start' and 'calendar_end' to parameterise requests to the sources,
1.58 + and the 'request' to access configuration settings in the Wiki.
1.59 + """
1.60 +
1.61 + sources_dict = getAllEventSources(request)
1.62 + if not sources_dict:
1.63 + return []
1.64 +
1.65 + # Use dates for the calendar limits.
1.66 +
1.67 + if isinstance(calendar_start, Date):
1.68 + pass
1.69 + elif isinstance(calendar_start, Month):
1.70 + calendar_start = calendar_start.as_date(1)
1.71 +
1.72 + if isinstance(calendar_end, Date):
1.73 + pass
1.74 + elif isinstance(calendar_end, Month):
1.75 + calendar_end = calendar_end.as_date(-1)
1.76 +
1.77 + resources = []
1.78 +
1.79 + for source in sources:
1.80 + try:
1.81 + details = sources_dict[source].split()
1.82 + url = details[0]
1.83 + format = (details[1:] or ["ical"])[0]
1.84 + except (KeyError, ValueError):
1.85 + pass
1.86 + else:
1.87 + # Prevent local file access.
1.88 +
1.89 + if url.startswith("file:"):
1.90 + continue
1.91 +
1.92 + # Parameterise the URL.
1.93 + # Where other parameters are used, care must be taken to encode them
1.94 + # properly.
1.95 +
1.96 + url = url.replace("{start}", urllib.quote_plus(calendar_start and str(calendar_start) or ""))
1.97 + url = url.replace("{end}", urllib.quote_plus(calendar_end and str(calendar_end) or ""))
1.98 +
1.99 + # Get a parser.
1.100 + # NOTE: This could be done reactively by choosing a parser based on
1.101 + # NOTE: the content type provided by the URL.
1.102 +
1.103 + if format == "ical" and vCalendar is not None:
1.104 + parser = vCalendar.parse
1.105 + resource_cls = EventCalendar
1.106 + required_content_type = "text/calendar"
1.107 + else:
1.108 + continue
1.109 +
1.110 + # Obtain the resource, using a cached version if appropriate.
1.111 +
1.112 + max_cache_age = int(getattr(request.cfg, "event_aggregator_max_cache_age", "300"))
1.113 + data = getCachedResource(request, url, "EventAggregator", "wiki", max_cache_age)
1.114 + if not data:
1.115 + continue
1.116 +
1.117 + # Process the entry, parsing the content.
1.118 +
1.119 + f = StringIO(data)
1.120 + try:
1.121 + url = f.readline()
1.122 +
1.123 + # Get the content type and encoding, making sure that the data
1.124 + # can be parsed.
1.125 +
1.126 + content_type, encoding = getContentTypeAndEncoding(f.readline())
1.127 + if content_type != required_content_type:
1.128 + continue
1.129 +
1.130 + # Send the data to the parser.
1.131 +
1.132 + uf = codecs.getreader(encoding or "utf-8")(f)
1.133 + try:
1.134 + resources.append(resource_cls(url, parser(uf)))
1.135 + finally:
1.136 + uf.close()
1.137 + finally:
1.138 + f.close()
1.139 +
1.140 + return resources
1.141 +
1.142 +def getEventsFromResources(resources):
1.143 +
1.144 + "Return a list of events supplied by the given event 'resources'."
1.145 +
1.146 + events = []
1.147 +
1.148 + for resource in resources:
1.149 +
1.150 + # Get all events described by the resource.
1.151 +
1.152 + for event in resource.getEvents():
1.153 +
1.154 + # Remember the event.
1.155 +
1.156 + events.append(event)
1.157 +
1.158 + return events
1.159 +
1.160 +# Page-related functions.
1.161 +
1.162 +def fillEventPageFromTemplate(template_page, new_page, event_details, category_pagenames):
1.163 +
1.164 + """
1.165 + Using the given 'template_page', complete the 'new_page' by copying the
1.166 + template and adding the given 'event_details' (a dictionary of event
1.167 + fields), setting also the 'category_pagenames' to define category
1.168 + membership.
1.169 + """
1.170 +
1.171 + event_page = EventPage(template_page)
1.172 + new_event_page = EventPage(new_page)
1.173 + new_event_page.copyPage(event_page)
1.174 +
1.175 + if new_event_page.getFormat() == "wiki":
1.176 + new_event = Event(new_event_page, event_details)
1.177 + new_event_page.setEvents([new_event])
1.178 + new_event_page.setCategoryMembership(category_pagenames)
1.179 + new_event_page.flushEventDetails()
1.180 +
1.181 + return new_event_page.getBody()
1.182 +
1.183 +# Event selection from request parameters.
1.184 +
1.185 +def getEventsUsingParameters(category_names, search_pattern, remote_sources,
1.186 + calendar_start, calendar_end, resolution, request):
1.187 +
1.188 + "Get the events according to the resolution of the calendar."
1.189 +
1.190 + if search_pattern:
1.191 + results = getPagesForSearch(search_pattern, request)
1.192 + else:
1.193 + results = []
1.194 +
1.195 + results += getAllCategoryPages(category_names, request)
1.196 + pages = getPagesFromResults(results, request)
1.197 + events = getEventsFromResources(getEventPages(pages))
1.198 + events += getEventsFromResources(getEventResources(remote_sources, calendar_start, calendar_end, request))
1.199 + all_shown_events = getEventsInPeriod(events, getCalendarPeriod(calendar_start, calendar_end))
1.200 + earliest, latest = getEventLimits(all_shown_events)
1.201 +
1.202 + # Get a concrete period of time.
1.203 +
1.204 + first, last = getConcretePeriod(calendar_start, calendar_end, earliest, latest, resolution)
1.205 +
1.206 + return all_shown_events, first, last
1.207 +
1.208 +# vim: tabstop=4 expandtab shiftwidth=4