1.1 --- a/EventAggregatorSupport.py Sat Sep 29 17:13:22 2012 +0200
1.2 +++ b/EventAggregatorSupport.py Sat Sep 29 17:49:35 2012 +0200
1.3 @@ -8,6 +8,7 @@
1.4 @license: GNU GPL (v2 or later), see COPYING.txt for details.
1.5 """
1.6
1.7 +from GeneralSupport import *
1.8 from LocationSupport import *
1.9 from MoinDateSupport import *
1.10 from MoinRemoteSupport import *
1.11 @@ -16,7 +17,6 @@
1.12
1.13 from MoinMoin.Page import Page
1.14 from MoinMoin.action import AttachFile
1.15 -from MoinMoin import search
1.16 from MoinMoin import wikiutil
1.17
1.18 import codecs
1.19 @@ -42,10 +42,6 @@
1.20
1.21 __version__ = "0.9"
1.22
1.23 -# Regular expressions where MoinMoin does not provide the required support.
1.24 -
1.25 -category_regexp = None
1.26 -
1.27 # Page parsing.
1.28
1.29 definition_list_regexp = re.compile(ur'(?P<wholeterm>^(?P<optcomment>#*)\s+(?P<term>.*?):: )(?P<desc>.*?)$', re.UNICODE | re.MULTILINE)
1.30 @@ -55,44 +51,8 @@
1.31
1.32 country_code_regexp = re.compile(ur'(?:^|\W)(?P<code>[A-Z]{2})(?:$|\W+$)', re.UNICODE)
1.33
1.34 -# Simple content parsing.
1.35 -
1.36 -verbatim_regexp = re.compile(ur'(?:'
1.37 - ur'<<Verbatim\((?P<verbatim>.*?)\)>>'
1.38 - ur'|'
1.39 - ur'\[\[Verbatim\((?P<verbatim2>.*?)\)\]\]'
1.40 - ur'|'
1.41 - ur'!(?P<verbatim3>.*?)(\s|$)?'
1.42 - ur'|'
1.43 - ur'`(?P<monospace>.*?)`'
1.44 - ur'|'
1.45 - ur'{{{(?P<preformatted>.*?)}}}'
1.46 - ur')', re.UNICODE)
1.47 -
1.48 # Utility functions.
1.49
1.50 -def getCategoryPattern(request):
1.51 - global category_regexp
1.52 -
1.53 - try:
1.54 - return request.cfg.cache.page_category_regexact
1.55 - except AttributeError:
1.56 -
1.57 - # Use regular expression from MoinMoin 1.7.1 otherwise.
1.58 -
1.59 - if category_regexp is None:
1.60 - category_regexp = re.compile(u'^%s$' % ur'(?P<all>Category(?P<key>(?!Template)\S+))', re.UNICODE)
1.61 - return category_regexp
1.62 -
1.63 -def getWikiDict(pagename, request):
1.64 - if pagename and Page(request, pagename).exists() and request.user.may.read(pagename):
1.65 - if hasattr(request.dicts, "dict"):
1.66 - return request.dicts.dict(pagename)
1.67 - else:
1.68 - return request.dicts[pagename]
1.69 - else:
1.70 - return None
1.71 -
1.72 def getLocationPosition(location, locations):
1.73
1.74 """
1.75 @@ -111,31 +71,6 @@
1.76
1.77 return latitude, longitude
1.78
1.79 -def to_list(s, sep):
1.80 - return [x.strip() for x in s.split(sep) if x.strip()]
1.81 -
1.82 -def sort_none_first(x, y):
1.83 - if x is None:
1.84 - return -1
1.85 - elif y is None:
1.86 - return 1
1.87 - else:
1.88 - return cmp(x, y)
1.89 -
1.90 -def sort_start_first(x, y):
1.91 - x_ts = x.as_limits()
1.92 - if x_ts is not None:
1.93 - x_start, x_end = x_ts
1.94 - y_ts = y.as_limits()
1.95 - if y_ts is not None:
1.96 - y_start, y_end = y_ts
1.97 - start_order = cmp(x_start, y_start)
1.98 - if start_order == 0:
1.99 - return cmp(x_end, y_end)
1.100 - else:
1.101 - return start_order
1.102 - return 0
1.103 -
1.104 # Utility classes and associated functions.
1.105
1.106 class ActionSupport(ActionSupport):
1.107 @@ -212,127 +147,22 @@
1.108
1.109 return start_day_default, end_day_default
1.110
1.111 -# Textual representations.
1.112 -
1.113 -def getSimpleWikiText(text):
1.114 -
1.115 - """
1.116 - Return the plain text representation of the given 'text' which may employ
1.117 - certain Wiki syntax features, such as those providing verbatim or monospaced
1.118 - text.
1.119 - """
1.120 -
1.121 - # NOTE: Re-implementing support for verbatim text and linking avoidance.
1.122 -
1.123 - return "".join([s for s in verbatim_regexp.split(text) if s is not None])
1.124 -
1.125 -def getEncodedWikiText(text):
1.126 -
1.127 - "Encode the given 'text' in a verbatim representation."
1.128 -
1.129 - return "<<Verbatim(%s)>>" % text
1.130 -
1.131 -def getPrettyTitle(title):
1.132 -
1.133 - "Return a nicely formatted version of the given 'title'."
1.134 -
1.135 - return title.replace("_", " ").replace("/", u" » ")
1.136 -
1.137 -# Category discovery and searching.
1.138 -
1.139 -def getCategories(request):
1.140 -
1.141 - """
1.142 - From the AdvancedSearch macro, return a list of category page names using
1.143 - the given 'request'.
1.144 - """
1.145 -
1.146 - # This will return all pages with "Category" in the title.
1.147 -
1.148 - cat_filter = getCategoryPattern(request).search
1.149 - return request.rootpage.getPageList(filter=cat_filter)
1.150 -
1.151 -def getCategoryMapping(category_pagenames, request):
1.152 -
1.153 - """
1.154 - For the given 'category_pagenames' return a list of tuples of the form
1.155 - (category name, category page name) using the given 'request'.
1.156 - """
1.157 -
1.158 - cat_pattern = getCategoryPattern(request)
1.159 - mapping = []
1.160 - for pagename in category_pagenames:
1.161 - name = cat_pattern.match(pagename).group("key")
1.162 - if name != "Category":
1.163 - mapping.append((name, pagename))
1.164 - mapping.sort()
1.165 - return mapping
1.166 -
1.167 -def getCategoryPages(pagename, request):
1.168 -
1.169 - """
1.170 - Return the pages associated with the given category 'pagename' using the
1.171 - 'request'.
1.172 - """
1.173 -
1.174 - query = search.QueryParser().parse_query('category:%s' % pagename)
1.175 - results = search.searchPages(request, query, "page_name")
1.176 -
1.177 - cat_pattern = getCategoryPattern(request)
1.178 - pages = []
1.179 - for page in results.hits:
1.180 - if not cat_pattern.match(page.page_name):
1.181 - pages.append(page)
1.182 - return pages
1.183 -
1.184 -def getAllCategoryPages(category_names, request):
1.185 -
1.186 - """
1.187 - Return all pages belonging to the categories having the given
1.188 - 'category_names', using the given 'request'.
1.189 - """
1.190 -
1.191 - pages = []
1.192 - pagenames = set()
1.193 -
1.194 - for category_name in category_names:
1.195 -
1.196 - # Get the pages and page names in the category.
1.197 -
1.198 - pages_in_category = getCategoryPages(category_name, request)
1.199 -
1.200 - # Visit each page in the category.
1.201 -
1.202 - for page_in_category in pages_in_category:
1.203 - pagename = page_in_category.page_name
1.204 -
1.205 - # Only process each page once.
1.206 -
1.207 - if pagename in pagenames:
1.208 - continue
1.209 - else:
1.210 - pagenames.add(pagename)
1.211 -
1.212 - pages.append(page_in_category)
1.213 -
1.214 - return pages
1.215 -
1.216 -def getPagesFromResults(result_pages, request):
1.217 -
1.218 - "Return genuine pages for the given 'result_pages' using the 'request'."
1.219 -
1.220 - return [Page(request, page.page_name) for page in result_pages]
1.221 -
1.222 # Event parsing from page texts.
1.223
1.224 -def parseEvents(text, event_page):
1.225 +def parseEvents(text, event_page, fragment=None):
1.226
1.227 """
1.228 Parse events in the given 'text', returning a list of event objects for the
1.229 - given 'event_page'.
1.230 + given 'event_page'. An optional 'fragment' can be specified to indicate a
1.231 + specific region of the event page.
1.232 """
1.233
1.234 + template_details = {}
1.235 + if fragment:
1.236 + template_details["fragment"] = fragment
1.237 +
1.238 details = {}
1.239 + details.update(template_details)
1.240 events = [Event(event_page, details)]
1.241
1.242 for match in definition_list_regexp.finditer(text):
1.243 @@ -351,12 +181,12 @@
1.244
1.245 # Dates.
1.246
1.247 - if term in ("start", "end"):
1.248 + if term in Event.date_terms:
1.249 desc = getDateTime(desc)
1.250
1.251 # Lists (whose elements may be quoted).
1.252
1.253 - elif term in ("topics", "categories"):
1.254 + elif term in Event.list_terms:
1.255 desc = map(getSimpleWikiText, to_list(desc, ","))
1.256
1.257 # Position details.
1.258 @@ -371,9 +201,14 @@
1.259
1.260 # Labels which may well be quoted.
1.261
1.262 - elif term in ("title", "summary", "description", "location"):
1.263 + elif term in Event.title_terms:
1.264 desc = getSimpleWikiText(desc.strip())
1.265
1.266 + # Plain Wiki text terms.
1.267 +
1.268 + elif term in Event.other_terms:
1.269 + desc = desc.strip()
1.270 +
1.271 if desc is not None:
1.272
1.273 # Handle apparent duplicates by creating a new set of
1.274 @@ -384,6 +219,7 @@
1.275 # Make a new event.
1.276
1.277 details = {}
1.278 + details.update(template_details)
1.279 events.append(Event(event_page, details))
1.280
1.281 details[term] = desc
1.282 @@ -427,14 +263,14 @@
1.283
1.284 return []
1.285
1.286 - def linkToPage(self, request, text, query_string=None):
1.287 + def linkToPage(self, request, text, query_string=None, anchor=None):
1.288
1.289 """
1.290 Using 'request', return a link to this page with the given link 'text'
1.291 - and optional 'query_string'.
1.292 + and optional 'query_string' and 'anchor'.
1.293 """
1.294
1.295 - return linkToResource(self.url, request, text, query_string)
1.296 + return linkToResource(self.url, request, text, query_string, anchor)
1.297
1.298 # Formatting-related functions.
1.299
1.300 @@ -602,10 +438,10 @@
1.301 "Return a list of events from this page."
1.302
1.303 if self.events is None:
1.304 + self.events = []
1.305 if self.getFormat() == "wiki":
1.306 - self.events = parseEvents(self.getBody(), self)
1.307 - else:
1.308 - self.events = []
1.309 + for format, attributes, region in getFragments(self.getBody(), True):
1.310 + self.events += parseEvents(region, self, attributes.get("fragment"))
1.311
1.312 return self.events
1.313
1.314 @@ -685,17 +521,17 @@
1.315
1.316 # Dates.
1.317
1.318 - if term in ("start", "end"):
1.319 + if term in event.date_terms:
1.320 desc = desc.replace("YYYY-MM-DD", str(event_details[term]))
1.321
1.322 # Lists (whose elements may be quoted).
1.323
1.324 - elif term in ("topics", "categories"):
1.325 + elif term in event.list_terms:
1.326 desc = ", ".join([getEncodedWikiText(item) for item in event_details[term]])
1.327
1.328 # Labels which must be quoted.
1.329
1.330 - elif term in ("title", "summary"):
1.331 + elif term in event.title_terms:
1.332 desc = getEncodedWikiText(event_details[term])
1.333
1.334 # Position details.
1.335 @@ -705,7 +541,7 @@
1.336
1.337 # Text which need not be quoted, but it will be Wiki text.
1.338
1.339 - elif term in ("description", "link", "location"):
1.340 + elif term in event.other_terms:
1.341 desc = event_details[term]
1.342
1.343 replaced_terms.add(term)
1.344 @@ -743,14 +579,14 @@
1.345 self.flushCategoryMembership()
1.346 self.page.saveText(self.getBody(), 0)
1.347
1.348 - def linkToPage(self, request, text, query_string=None):
1.349 + def linkToPage(self, request, text, query_string=None, anchor=None):
1.350
1.351 """
1.352 Using 'request', return a link to this page with the given link 'text'
1.353 - and optional 'query_string'.
1.354 + and optional 'query_string' and 'anchor'.
1.355 """
1.356
1.357 - return linkToPage(request, self.page, text, query_string)
1.358 + return linkToPage(request, self.page, text, query_string, anchor)
1.359
1.360 # Formatting-related functions.
1.361
1.362 @@ -781,6 +617,13 @@
1.363
1.364 "A description of an event."
1.365
1.366 + title_terms = "title", "summary"
1.367 + date_terms = "start", "end"
1.368 + list_terms = "topics", "categories"
1.369 + other_terms = "description", "location", "link"
1.370 + geo_terms = "geo",
1.371 + all_terms = title_terms + date_terms + list_terms + other_terms + geo_terms
1.372 +
1.373 def __init__(self, page, details):
1.374 self.page = page
1.375 self.details = details
1.376 @@ -826,7 +669,8 @@
1.377
1.378 "Return the URL of this event."
1.379
1.380 - return self.page.getPageURL()
1.381 + fragment = self.details.get("fragment")
1.382 + return self.page.getPageURL() + (fragment and "#" + fragment or "")
1.383
1.384 def linkToEvent(self, request, text, query_string=None):
1.385
1.386 @@ -835,7 +679,7 @@
1.387 and optional 'query_string'.
1.388 """
1.389
1.390 - return self.page.linkToPage(request, text, query_string)
1.391 + return self.page.linkToPage(request, text, query_string, self.details.get("fragment"))
1.392
1.393 def getMetadata(self):
1.394
1.395 @@ -945,14 +789,14 @@
1.396
1.397 return self.details.get("url") or self.page.getPageURL()
1.398
1.399 - def linkToEvent(self, request, text, query_string=None):
1.400 + def linkToEvent(self, request, text, query_string=None, anchor=None):
1.401
1.402 """
1.403 Using 'request', return a link to this event with the given link 'text'
1.404 - and optional 'query_string'.
1.405 + and optional 'query_string' and 'anchor'.
1.406 """
1.407
1.408 - return linkToResource(self.getEventURL(), request, text, query_string)
1.409 + return linkToResource(self.getEventURL(), request, text, query_string, anchor)
1.410
1.411 def getMetadata(self):
1.412
1.413 @@ -1320,6 +1164,24 @@
1.414
1.415 return scale
1.416
1.417 +# Event sorting.
1.418 +
1.419 +def sort_start_first(x, y):
1.420 + x_ts = x.as_limits()
1.421 + if x_ts is not None:
1.422 + x_start, x_end = x_ts
1.423 + y_ts = y.as_limits()
1.424 + if y_ts is not None:
1.425 + y_start, y_end = y_ts
1.426 + start_order = cmp(x_start, y_start)
1.427 + if start_order == 0:
1.428 + return cmp(x_end, y_end)
1.429 + else:
1.430 + return start_order
1.431 + return 0
1.432 +
1.433 +# Country code parsing.
1.434 +
1.435 def getCountry(s):
1.436
1.437 "Find a country code in the given string 's'."
1.438 @@ -3358,11 +3220,12 @@
1.439 event_details = event.getDetails()
1.440 write = write or request.write
1.441
1.442 + if event_details.has_key("fragment"):
1.443 + write(fmt.anchordef(event_details["fragment"]))
1.444 +
1.445 write(fmt.definition_list(on=1))
1.446
1.447 - for term in ("title", "summary", "start", "end", "description", "link",
1.448 - "location", "geo", "topics", "categories"):
1.449 -
1.450 + for term in event.all_terms:
1.451 if event_details.has_key(term):
1.452 value = event_details[term]
1.453 if value:
1.454 @@ -3370,7 +3233,10 @@
1.455 write(fmt.text(term))
1.456 write(fmt.definition_term(on=0))
1.457 write(fmt.definition_desc(on=1))
1.458 - write(formatText(str(value), request, fmt))
1.459 + if term in event.list_terms:
1.460 + write(", ".join([formatText(str(v), request, fmt) for v in value]))
1.461 + else:
1.462 + write(formatText(str(value), request, fmt))
1.463 write(fmt.definition_desc(on=0))
1.464
1.465 write(fmt.definition_list(on=0))
1.466 @@ -3530,7 +3396,7 @@
1.467 link = event.getEventURL()
1.468
1.469 write('<item>\r\n')
1.470 - write('<title>%s</title>\r\n' % wikiutil.escape(event_summary))
1.471 + write('<title>%s</title>\r\n' % escape(event_summary))
1.472 write('<link>%s</link>\r\n' % link)
1.473
1.474 # Write a description according to the preferred source of