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