1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - EventAggregator resource acquisition and access 4 5 @copyright: 2008, 2009, 2010, 2011, 2012, 2013 by Paul Boddie <paul@boddie.org.uk> 6 @license: GNU GPL (v2 or later), see COPYING.txt for details. 7 """ 8 9 from EventAggregatorSupport.Filter import * 10 from EventAggregatorSupport.Types import * 11 12 from DateSupport import Date, Month 13 from MoinSupport import * 14 from MoinRemoteSupport import getCachedResource, getCachedResourceMetadata 15 16 import codecs 17 import urllib 18 19 try: 20 from cStringIO import StringIO 21 except ImportError: 22 from StringIO import StringIO 23 24 try: 25 import vCalendar 26 except ImportError: 27 vCalendar = None 28 29 # Obtaining event containers and events from such containers. 30 31 def getEventPages(pages): 32 33 "Return a list of events found on the given 'pages'." 34 35 # Get real pages instead of result pages. 36 37 return map(EventPage, pages) 38 39 def getAllEventSources(request): 40 41 "Return all event sources defined in the Wiki using the 'request'." 42 43 sources_page = getattr(request.cfg, "event_aggregator_sources_page", "EventSourcesDict") 44 45 # Remote sources are accessed via dictionary page definitions. 46 47 return getWikiDict(sources_page, request) 48 49 def getEventResources(sources, calendar_start, calendar_end, request): 50 51 """ 52 Return resource objects for the given 'sources' using the given 53 'calendar_start' and 'calendar_end' to parameterise requests to the sources, 54 and the 'request' to access configuration settings in the Wiki. 55 """ 56 57 sources_dict = getAllEventSources(request) 58 if not sources_dict: 59 return [] 60 61 # Use dates for the calendar limits. 62 63 if isinstance(calendar_start, Date): 64 pass 65 elif isinstance(calendar_start, Month): 66 calendar_start = calendar_start.as_date(1) 67 68 if isinstance(calendar_end, Date): 69 pass 70 elif isinstance(calendar_end, Month): 71 calendar_end = calendar_end.as_date(-1) 72 73 resources = [] 74 75 for source in sources: 76 try: 77 details = sources_dict[source].split() 78 details.extend([None] * (3 - len(details))) 79 url = details[0] 80 format = details[1] or "ical" 81 expected_content_type = details[2] 82 except (KeyError, ValueError): 83 pass 84 else: 85 resource = getEventResourcesFromSource(url, format, expected_content_type, calendar_start, calendar_end, request) 86 if resource: 87 resources.append(resource) 88 89 return resources 90 91 def getEventResourcesFromSource(url, format, expected_content_type, calendar_start, calendar_end, request): 92 93 """ 94 Return a resource object for the given 'url' providing content in the 95 specified 'format', insisting on the 'expected_content_type', and using the 96 given 'calendar_start' and 'calendar_end' to parameterise requests to the 97 sources and the 'request' to access configuration settings in the Wiki. 98 """ 99 100 # Prevent local file access. 101 102 if url.startswith("file:"): 103 return None 104 105 # Parameterise the URL. 106 # Where other parameters are used, care must be taken to encode them 107 # properly. 108 109 url = url.replace("{start}", urllib.quote_plus(calendar_start and str(calendar_start) or "")) 110 url = url.replace("{end}", urllib.quote_plus(calendar_end and str(calendar_end) or "")) 111 112 # Get a parser. 113 # NOTE: This could be done reactively by choosing a parser based on 114 # NOTE: the content type provided by the URL. 115 116 if format == "ical" and vCalendar is not None: 117 parser = vCalendar.parse 118 resource_cls = EventCalendar 119 required_content_type = expected_content_type or "text/calendar" 120 else: 121 return None 122 123 # Obtain the resource, using a cached version if appropriate. 124 125 max_cache_age = int(getattr(request.cfg, "event_aggregator_max_cache_age", "300")) 126 data = getCachedResource(request, url, "EventAggregator", "wiki", max_cache_age) 127 if not data: 128 return None 129 130 # Process the entry, parsing the content. 131 132 f = StringIO(data) 133 try: 134 # Get the content type and encoding, making sure that the data 135 # can be parsed. 136 137 url, content_type, encoding, metadata = getCachedResourceMetadata(f) 138 139 if content_type != required_content_type: 140 return None 141 142 # Send the data to the parser. 143 144 uf = codecs.getreader(encoding or "utf-8")(f) 145 try: 146 return resource_cls(url, parser(uf), metadata) 147 finally: 148 uf.close() 149 finally: 150 f.close() 151 152 def getEventsFromResources(resources): 153 154 "Return a list of events supplied by the given event 'resources'." 155 156 events = [] 157 158 for resource in resources: 159 160 # Get all events described by the resource. 161 162 for event in resource.getEvents(): 163 164 # Remember the event. 165 166 events.append(event) 167 168 return events 169 170 # Page-related functions. 171 172 def fillEventPageFromTemplate(template_page, new_page, event_details, category_pagenames): 173 174 """ 175 Using the given 'template_page', complete the 'new_page' by copying the 176 template and adding the given 'event_details' (a dictionary of event 177 fields), setting also the 'category_pagenames' to define category 178 membership. 179 """ 180 181 event_page = EventPage(template_page) 182 new_event_page = EventPage(new_page) 183 new_event_page.copyPage(event_page) 184 185 if new_event_page.getFormat() == "wiki": 186 new_event = Event(new_event_page, event_details) 187 new_event_page.setEvents([new_event]) 188 new_event_page.setCategoryMembership(category_pagenames) 189 new_event_page.flushEventDetails() 190 191 return new_event_page.getBody() 192 193 # Event selection from request parameters. 194 195 def getEventsUsingParameters(category_names, search_pattern, remote_sources, 196 calendar_start, calendar_end, resolution, request): 197 198 "Get the events according to the resolution of the calendar." 199 200 if search_pattern: 201 results = getPagesForSearch(search_pattern, request) 202 else: 203 results = [] 204 205 results += getAllCategoryPages(category_names, request) 206 pages = getPagesFromResults(results, request) 207 events = getEventsFromResources(getEventPages(pages)) 208 events += getEventsFromResources(getEventResources(remote_sources, calendar_start, calendar_end, request)) 209 all_shown_events = getEventsInPeriod(events, getCalendarPeriod(calendar_start, calendar_end)) 210 earliest, latest = getEventLimits(all_shown_events) 211 212 # Get a concrete period of time. 213 214 first, last = getConcretePeriod(calendar_start, calendar_end, earliest, latest, resolution) 215 216 return all_shown_events, first, last 217 218 # vim: tabstop=4 expandtab shiftwidth=4