1.1 --- a/EventAggregatorSupport.py Sat Jul 23 15:59:27 2011 +0200
1.2 +++ b/EventAggregatorSupport.py Sat Jul 23 19:00:04 2011 +0200
1.3 @@ -94,6 +94,11 @@
1.4 date_icalendar_regexp = re.compile(date_icalendar_regexp_str, re.UNICODE)
1.5 datetime_icalendar_regexp = re.compile(datetime_icalendar_regexp_str, re.UNICODE)
1.6
1.7 +# Content type parsing.
1.8 +
1.9 +encoding_regexp_str = ur'charset=(?P<encoding>[-A-Za-z0-9]+)'
1.10 +encoding_regexp = re.compile(encoding_regexp_str)
1.11 +
1.12 # Simple content parsing.
1.13
1.14 verbatim_regexp = re.compile(ur'(?:'
1.15 @@ -123,6 +128,13 @@
1.16 category_regexp = re.compile(u'^%s$' % ur'(?P<all>Category(?P<key>(?!Template)\S+))', re.UNICODE)
1.17 return category_regexp
1.18
1.19 +def getContentEncoding(content_type):
1.20 + m = encoding_regexp.search(content_type)
1.21 + if m:
1.22 + return m.group("encoding")
1.23 + else:
1.24 + return None
1.25 +
1.26 def int_or_none(x):
1.27 if x is None:
1.28 return x
1.29 @@ -306,17 +318,6 @@
1.30
1.31 # Textual representations.
1.32
1.33 -def getHTTPTimeString(tmtuple):
1.34 - return "%s, %02d %s %04d %02d:%02d:%02d GMT" % (
1.35 - getDayLabel(tmtuple.tm_wday),
1.36 - tmtuple.tm_mday,
1.37 - getMonthLabel(tmtuple.tm_mon),
1.38 - tmtuple.tm_year,
1.39 - tmtuple.tm_hour,
1.40 - tmtuple.tm_min,
1.41 - tmtuple.tm_sec
1.42 - )
1.43 -
1.44 def getSimpleWikiText(text):
1.45
1.46 """
1.47 @@ -407,7 +408,9 @@
1.48 mtime = 0
1.49 comment = ""
1.50
1.51 - return {"timestamp" : time.gmtime(mtime), "comment" : comment}
1.52 + # Leave the time zone empty.
1.53 +
1.54 + return {"timestamp" : DateTime(time.gmtime(mtime)[:6] + (None,)), "comment" : comment}
1.55
1.56 # Category discovery and searching.
1.57
1.58 @@ -516,10 +519,20 @@
1.59
1.60 def getFormat(self):
1.61
1.62 - "Get the format used on this page."
1.63 + "Get the format used by this resource."
1.64
1.65 return "plain"
1.66
1.67 + def getMetadata(self):
1.68 +
1.69 + """
1.70 + Return a dictionary containing items describing the page's "created"
1.71 + time, "last-modified" time, "sequence" (or revision number) and the
1.72 + "last-comment" made about the last edit.
1.73 + """
1.74 +
1.75 + return {}
1.76 +
1.77 def getEvents(self):
1.78
1.79 "Return a list of events from this resource."
1.80 @@ -533,19 +546,7 @@
1.81 and optional 'query_string'.
1.82 """
1.83
1.84 - url = self.url
1.85 -
1.86 - if query_string:
1.87 - query_string = wikiutil.makeQueryString(query_string)
1.88 - url = "%s?%s" % (url, query_string)
1.89 -
1.90 - formatter = request.page and getattr(request.page, "formatter", None) or request.html_formatter
1.91 -
1.92 - output = []
1.93 - output.append(formatter.url(1, url))
1.94 - output.append(formatter.text(text))
1.95 - output.append(formatter.url(0))
1.96 - return "".join(output)
1.97 + return linkToResource(self.url, request, text, query_string)
1.98
1.99 # Formatting-related functions.
1.100
1.101 @@ -589,24 +590,38 @@
1.102
1.103 # Convert dates.
1.104
1.105 - if property in ("DTSTART", "DTEND"):
1.106 - property = property[2:].lower()
1.107 + if property in ("DTSTART", "DTEND", "CREATED", "DTSTAMP", "LAST-MODIFIED"):
1.108 + if property in ("DTSTART", "DTEND"):
1.109 + property = property[2:]
1.110 if attrs.get("VALUE") == "DATE":
1.111 value = getDateFromCalendar(value)
1.112 else:
1.113 value = getDateTimeFromCalendar(value)
1.114
1.115 + # Convert numeric data.
1.116 +
1.117 + elif property == "SEQUENCE":
1.118 + value = int(value)
1.119 +
1.120 + # Convert lists.
1.121 +
1.122 + elif property == "CATEGORIES":
1.123 + value = [v.strip() for v in value.split(",") if v.strip()]
1.124 +
1.125 # Accept other textual data as it is.
1.126
1.127 - elif property in ("CATEGORIES", "LOCATION", "SUMMARY"):
1.128 - property = property.lower()
1.129 + elif property in ("LOCATION", "SUMMARY", "URL"):
1.130 + pass
1.131 +
1.132 + # Ignore other properties.
1.133
1.134 else:
1.135 continue
1.136
1.137 + property = property.lower()
1.138 details[property] = value
1.139
1.140 - self.events.append(Event(self, details))
1.141 + self.events.append(CalendarEvent(self, details))
1.142
1.143 return self.events
1.144
1.145 @@ -619,6 +634,7 @@
1.146 self.events = None
1.147 self.body = None
1.148 self.categories = None
1.149 + self.metadata = None
1.150
1.151 def copyPage(self, page):
1.152
1.153 @@ -638,6 +654,35 @@
1.154
1.155 return self.page.pi["format"]
1.156
1.157 + def getMetadata(self):
1.158 +
1.159 + """
1.160 + Return a dictionary containing items describing the page's "created"
1.161 + time, "last-modified" time, "sequence" (or revision number) and the
1.162 + "last-comment" made about the last edit.
1.163 + """
1.164 +
1.165 + request = self.page.request
1.166 +
1.167 + # Get the initial revision of the page.
1.168 +
1.169 + revisions = self.getRevisions()
1.170 + event_page_initial = Page(request, self.getPageName(), rev=revisions[-1])
1.171 +
1.172 + # Get the created and last modified times.
1.173 +
1.174 + initial_revision = getPageRevision(event_page_initial)
1.175 +
1.176 + if self.metadata is None:
1.177 + self.metadata = {}
1.178 + self.metadata["created"] = initial_revision["timestamp"]
1.179 + latest_revision = self.getPageRevision()
1.180 + self.metadata["last-modified"] = latest_revision["timestamp"]
1.181 + self.metadata["sequence"] = len(revisions) - 1
1.182 + self.metadata["last-comment"] = latest_revision["comment"]
1.183 +
1.184 + return self.metadata
1.185 +
1.186 def getRevisions(self):
1.187
1.188 "Return a list of page revisions."
1.189 @@ -883,6 +928,8 @@
1.190 'fmt'.
1.191 """
1.192
1.193 + fmt.page = self.page
1.194 +
1.195 # Suppress line anchors.
1.196
1.197 parser_cls = self.getParserClass(request, self.getFormat())
1.198 @@ -932,6 +979,33 @@
1.199
1.200 self.page = page
1.201
1.202 + def getEventURL(self, request):
1.203 +
1.204 + "Using 'request', return the URL of this event."
1.205 +
1.206 + return self.page.getPageURL(request)
1.207 +
1.208 + def linkToEvent(self, request, text, query_string=None):
1.209 +
1.210 + """
1.211 + Using 'request', return a link to this event with the given link 'text'
1.212 + and optional 'query_string'.
1.213 + """
1.214 +
1.215 + return self.page.linkToPage(request, text, query_string)
1.216 +
1.217 + def getMetadata(self):
1.218 +
1.219 + """
1.220 + Return a dictionary containing items describing the event's "created"
1.221 + time, "last-modified" time, "sequence" (or revision number) and the
1.222 + "last-comment" made about the last edit.
1.223 + """
1.224 +
1.225 + # Delegate this to the page.
1.226 +
1.227 + return self.page.getMetadata()
1.228 +
1.229 def getSummary(self, event_parent=None):
1.230
1.231 """
1.232 @@ -994,6 +1068,40 @@
1.233 ts = self.as_timespan()
1.234 return ts and ts.as_limits()
1.235
1.236 +class CalendarEvent(Event):
1.237 +
1.238 + "An event from a remote calendar."
1.239 +
1.240 + def getEventURL(self, request):
1.241 +
1.242 + "Using 'request', return the URL of this event."
1.243 +
1.244 + return self.details.get("url") or self.page.getPageURL(request)
1.245 +
1.246 + def linkToEvent(self, request, text, query_string=None):
1.247 +
1.248 + """
1.249 + Using 'request', return a link to this event with the given link 'text'
1.250 + and optional 'query_string'.
1.251 + """
1.252 +
1.253 + return linkToResource(self.getEventURL(request), request, text, query_string)
1.254 +
1.255 + def getMetadata(self):
1.256 +
1.257 + """
1.258 + Return a dictionary containing items describing the event's "created"
1.259 + time, "last-modified" time, "sequence" (or revision number) and the
1.260 + "last-comment" made about the last edit.
1.261 + """
1.262 +
1.263 + return {
1.264 + "created" : self.details.get("created") or self.details["dtstamp"],
1.265 + "last-modified" : self.details.get("last-modified") or self.details["dtstamp"],
1.266 + "sequence" : self.details.get("sequence") or 0,
1.267 + "last-comment" : ""
1.268 + }
1.269 +
1.270 # Obtaining event containers and events from such containers.
1.271
1.272 def getEventPages(pages):
1.273 @@ -1004,6 +1112,19 @@
1.274
1.275 return map(EventPage, pages)
1.276
1.277 +def getAllEventSources(request):
1.278 +
1.279 + "Return all event sources defined in the Wiki using the 'request'."
1.280 +
1.281 + sources_page = getattr(request.cfg, "event_aggregator_sources_page", "EventSourcesDict")
1.282 +
1.283 + # Remote sources are accessed via dictionary page definitions.
1.284 +
1.285 + if request.user.may.read(sources_page):
1.286 + return request.dicts.dict(sources_page)
1.287 + else:
1.288 + return {}
1.289 +
1.290 def getEventResources(sources, calendar_start, calendar_end, request):
1.291
1.292 """
1.293 @@ -1012,13 +1133,8 @@
1.294 and the 'request' to access configuration settings in the Wiki.
1.295 """
1.296
1.297 - sources_page = getattr(request.cfg, "event_aggregator_sources_page", "EventSourcesDict")
1.298 -
1.299 - # Remote sources are accessed via dictionary page definitions.
1.300 -
1.301 - if request.user.may.read(sources_page):
1.302 - sources_dict = request.dicts.dict(sources_page)
1.303 - else:
1.304 + sources_dict = getAllEventSources(request)
1.305 + if not sources_dict:
1.306 return []
1.307
1.308 # Use dates for the calendar limits.
1.309 @@ -1061,9 +1177,12 @@
1.310
1.311 f = urllib.urlopen(url)
1.312
1.313 - # NOTE: Should look at the metadata first.
1.314 -
1.315 - uf = codecs.getreader("utf-8")(f)
1.316 + if f.headers.has_key("content-type"):
1.317 + encoding = getContentEncoding(f.headers["content-type"])
1.318 + else:
1.319 + encoding = None
1.320 +
1.321 + uf = codecs.getreader(encoding or "utf-8")(f)
1.322
1.323 try:
1.324 resources.append(resource_cls(url, parser(uf)))
1.325 @@ -1151,21 +1270,10 @@
1.326
1.327 for event in events:
1.328 event_details = event.getDetails()
1.329 - event_page = event.getPage()
1.330 -
1.331 - # Get the initial revision of the page.
1.332 -
1.333 - revisions = event_page.getRevisions()
1.334 - event_page_initial = Page(request, event_page.getPageName(), rev=revisions[-1])
1.335 -
1.336 - # Get the created and last modified times.
1.337 -
1.338 - initial_revision = getPageRevision(event_page_initial)
1.339 - event_details["created"] = initial_revision["timestamp"]
1.340 - latest_revision = event_page.getPageRevision()
1.341 - event_details["last-modified"] = latest_revision["timestamp"]
1.342 - event_details["sequence"] = len(revisions) - 1
1.343 - event_details["last-comment"] = latest_revision["comment"]
1.344 +
1.345 + # Populate the details with event metadata.
1.346 +
1.347 + event_details.update(event.getMetadata())
1.348
1.349 if latest is None or latest < event_details["last-modified"]:
1.350 latest = event_details["last-modified"]
1.351 @@ -1638,6 +1746,15 @@
1.352 else:
1.353 return ""
1.354
1.355 + def as_HTTP_datetime_string(self):
1.356 + weekday = calendar.weekday(*self.data[:3])
1.357 + return "%s, %02d %s %04d %02d:%02d:%02d GMT" % ((
1.358 + getDayLabel(weekday),
1.359 + self.data[2],
1.360 + getMonthLabel(self.data[1]),
1.361 + self.data[0]
1.362 + ) + tuple(self.data[3:6]))
1.363 +
1.364 def as_datetime(self):
1.365 return self
1.366
1.367 @@ -2434,6 +2551,25 @@
1.368 text = wikiutil.escape(text)
1.369 return page.link_to_raw(request, text, query_string)
1.370
1.371 +def linkToResource(url, request, text, query_string=None):
1.372 +
1.373 + """
1.374 + Using 'request', return a link to 'url' with the given link 'text' and
1.375 + optional 'query_string'.
1.376 + """
1.377 +
1.378 + if query_string:
1.379 + query_string = wikiutil.makeQueryString(query_string)
1.380 + url = "%s?%s" % (url, query_string)
1.381 +
1.382 + formatter = request.page and getattr(request.page, "formatter", None) or request.html_formatter
1.383 +
1.384 + output = []
1.385 + output.append(formatter.url(1, url))
1.386 + output.append(formatter.text(text))
1.387 + output.append(formatter.url(0))
1.388 + return "".join(output)
1.389 +
1.390 def getFullPageName(parent, title):
1.391
1.392 """