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