1.1 --- a/EventAggregatorSupport.py Mon Jan 18 01:00:35 2010 +0100
1.2 +++ b/EventAggregatorSupport.py Sun Jan 24 02:55:53 2010 +0100
1.3 @@ -2,7 +2,7 @@
1.4 """
1.5 MoinMoin - EventAggregator library
1.6
1.7 - @copyright: 2008, 2009 by Paul Boddie <paul@boddie.org.uk>
1.8 + @copyright: 2008, 2009, 2010 by Paul Boddie <paul@boddie.org.uk>
1.9 @copyright: 2000-2004 Juergen Hermann <jh@web.de>,
1.10 2005-2008 MoinMoin:ThomasWaldmann.
1.11 @license: GNU GPL (v2 or later), see COPYING.txt for details.
1.12 @@ -65,8 +65,74 @@
1.13 category_regexp = re.compile(u'^%s$' % ur'(?P<all>Category(?P<key>(?!Template)\S+))', re.UNICODE)
1.14 return category_regexp
1.15
1.16 +# Textual representations.
1.17 +
1.18 +def getHTTPTimeString(tmtuple):
1.19 + return "%s, %02d %s %04d %02d:%02d:%02d GMT" % (
1.20 + weekday_labels[tmtuple.tm_wday],
1.21 + tmtuple.tm_mday,
1.22 + month_labels[tmtuple.tm_mon -1], # zero-based labels
1.23 + tmtuple.tm_year,
1.24 + tmtuple.tm_hour,
1.25 + tmtuple.tm_min,
1.26 + tmtuple.tm_sec
1.27 + )
1.28 +
1.29 +def getSimpleWikiText(text):
1.30 +
1.31 + """
1.32 + Return the plain text representation of the given 'text' which may employ
1.33 + certain Wiki syntax features, such as those providing verbatim or monospaced
1.34 + text.
1.35 + """
1.36 +
1.37 + # NOTE: Re-implementing support for verbatim text and linking avoidance.
1.38 +
1.39 + return "".join([s for s in verbatim_regexp.split(text) if s is not None])
1.40 +
1.41 +def getEncodedWikiText(text):
1.42 +
1.43 + "Encode the given 'text' in a verbatim representation."
1.44 +
1.45 + return "<<Verbatim(%s)>>" % text
1.46 +
1.47 +def getPrettyTitle(title):
1.48 +
1.49 + "Return a nicely formatted version of the given 'title'."
1.50 +
1.51 + return title.replace("_", " ").replace("/", u" » ")
1.52 +
1.53 +def getMonthLabel(month):
1.54 +
1.55 + "Return an unlocalised label for the given 'month'."
1.56 +
1.57 + return month_labels[month - 1] # zero-based labels
1.58 +
1.59 +def getDayLabel(weekday):
1.60 +
1.61 + "Return an unlocalised label for the given 'weekday'."
1.62 +
1.63 + return weekday_labels[weekday]
1.64 +
1.65 # Action support functions.
1.66
1.67 +def getPageRevision(page):
1.68 +
1.69 + "Return the revision details dictionary for the given 'page'."
1.70 +
1.71 + # From Page.edit_info...
1.72 +
1.73 + if hasattr(page, "editlog_entry"):
1.74 + line = page.editlog_entry()
1.75 + else:
1.76 + line = page._last_edited(page.request) # MoinMoin 1.5.x and 1.6.x
1.77 +
1.78 + timestamp = line.ed_time_usecs
1.79 + mtime = wikiutil.version2timestamp(long(timestamp)) # must be long for py 2.2.x
1.80 + return {"timestamp" : time.gmtime(mtime), "comment" : line.comment}
1.81 +
1.82 +# Category discovery and searching.
1.83 +
1.84 def getCategories(request):
1.85
1.86 """
1.87 @@ -95,35 +161,12 @@
1.88 mapping.sort()
1.89 return mapping
1.90
1.91 -def getPageRevision(page):
1.92 -
1.93 - # From Page.edit_info...
1.94 -
1.95 - if hasattr(page, "editlog_entry"):
1.96 - line = page.editlog_entry()
1.97 - else:
1.98 - line = page._last_edited(page.request) # MoinMoin 1.5.x and 1.6.x
1.99 -
1.100 - timestamp = line.ed_time_usecs
1.101 - mtime = wikiutil.version2timestamp(long(timestamp)) # must be long for py 2.2.x
1.102 - return {"timestamp" : time.gmtime(mtime), "comment" : line.comment}
1.103 +def getCategoryPages(pagename, request):
1.104
1.105 -def getHTTPTimeString(tmtuple):
1.106 - return "%s, %02d %s %04d %02d:%02d:%02d GMT" % (
1.107 - weekday_labels[tmtuple.tm_wday],
1.108 - tmtuple.tm_mday,
1.109 - month_labels[tmtuple.tm_mon -1], # zero-based labels
1.110 - tmtuple.tm_year,
1.111 - tmtuple.tm_hour,
1.112 - tmtuple.tm_min,
1.113 - tmtuple.tm_sec
1.114 - )
1.115 -
1.116 -# The main activity functions.
1.117 -
1.118 -def getPages(pagename, request):
1.119 -
1.120 - "Return the links minus category links for 'pagename' using the 'request'."
1.121 + """
1.122 + Return the pages associated with the given category 'pagename' using the
1.123 + 'request'.
1.124 + """
1.125
1.126 query = search.QueryParser().parse_query('category:%s' % pagename)
1.127 if isMoin15():
1.128 @@ -139,46 +182,191 @@
1.129 pages.append(page)
1.130 return pages
1.131
1.132 -def getSimpleWikiText(text):
1.133 +# The main activity functions.
1.134 +
1.135 +class EventPage:
1.136 +
1.137 + "An event page."
1.138 +
1.139 + def __init__(self, page):
1.140 + self.page = page
1.141 + self.details = None
1.142 + self.body = None
1.143 + self.categories = None
1.144 +
1.145 + def copyPage(self, page):
1.146 +
1.147 + "Copy the body of the given 'page'."
1.148 +
1.149 + self.body = page.getBody()
1.150 +
1.151 + def getPageURL(self, request):
1.152 +
1.153 + "Using 'request', return the URL of this page."
1.154
1.155 - """
1.156 - Return the plain text representation of the given 'text' which may employ
1.157 - certain Wiki syntax features, such as those providing verbatim or monospaced
1.158 - text.
1.159 - """
1.160 + page = self.page
1.161 +
1.162 + if isMoin15():
1.163 + return request.getQualifiedURL(page.url(request))
1.164 + else:
1.165 + return request.getQualifiedURL(page.url(request, relative=0))
1.166 +
1.167 + def getFormat(self):
1.168 +
1.169 + "Get the format used on this page."
1.170
1.171 - # NOTE: Re-implementing support for verbatim text and linking avoidance.
1.172 + if isMoin15():
1.173 + return "wiki" # page.pi_format
1.174 + else:
1.175 + return self.page.pi["format"]
1.176 +
1.177 + def getRevisions(self):
1.178 +
1.179 + "Return a list of page revisions."
1.180 +
1.181 + return self.page.getRevList()
1.182 +
1.183 + def getPageRevision(self):
1.184
1.185 - return "".join([s for s in verbatim_regexp.split(text) if s is not None])
1.186 + "Return the revision details dictionary for this page."
1.187 +
1.188 + return getPageRevision(self.page)
1.189 +
1.190 + def getPageName(self):
1.191 +
1.192 + "Return the page name."
1.193 +
1.194 + return self.page.page_name
1.195
1.196 -def getEncodedWikiText(text):
1.197 + def getPrettyPageName(self):
1.198 +
1.199 + "Return a nicely formatted title/name for this page."
1.200 +
1.201 + return getPrettyPageName(self.page)
1.202 +
1.203 + def getBody(self):
1.204 +
1.205 + "Get the current page body."
1.206
1.207 - "Encode the given 'text' in a verbatim representation."
1.208 + if self.body is None:
1.209 + self.body = self.page.get_raw_body()
1.210 + return self.body
1.211 +
1.212 + def getEventDetails(self):
1.213 +
1.214 + "Return a dictionary of event details from this page."
1.215 +
1.216 + if self.details is None:
1.217 + self.details = {}
1.218
1.219 - return "<<Verbatim(%s)>>" % text
1.220 + if self.getFormat() == "wiki":
1.221 + for match in definition_list_regexp.finditer(self.getBody()):
1.222 +
1.223 + # Skip commented-out items.
1.224
1.225 -def getFormat(page):
1.226 + if match.group("optcomment"):
1.227 + continue
1.228 +
1.229 + # Permit case-insensitive list terms.
1.230 +
1.231 + term = match.group("term").lower()
1.232 + desc = match.group("desc")
1.233 +
1.234 + # Special value type handling.
1.235
1.236 - "Get the format used on 'page'."
1.237 + # Dates.
1.238 +
1.239 + if term in ("start", "end"):
1.240 + desc = getDate(desc)
1.241 +
1.242 + # Lists (whose elements may be quoted).
1.243 +
1.244 + elif term in ("topics", "categories"):
1.245 + desc = [getSimpleWikiText(value.strip()) for value in desc.split(",")]
1.246 +
1.247 + # Labels which may well be quoted.
1.248 +
1.249 + elif term in ("title", "summary", "description"):
1.250 + desc = getSimpleWikiText(desc)
1.251 +
1.252 + if desc is not None:
1.253 + self.details[term] = desc
1.254 +
1.255 + return self.details
1.256 +
1.257 + def getCategoryMembership(self):
1.258
1.259 - if isMoin15():
1.260 - return "wiki" # page.pi_format
1.261 - else:
1.262 - return page.pi["format"]
1.263 + "Get the category names from this page."
1.264 +
1.265 + if self.categories is None:
1.266 + body = self.getBody()
1.267 + match = category_membership_regexp.search(body)
1.268 + self.categories = match.findall().split()
1.269 +
1.270 + return self.categories
1.271 +
1.272 + def getEventSummary(self, event_parent=None):
1.273
1.274 -def getEventDetails(page):
1.275 + """
1.276 + Return either the given title or summary of the event described by this
1.277 + page, according to the page's event details, or using the pretty version
1.278 + of the page name.
1.279 +
1.280 + If the optional 'event_parent' is specified, any page beneath the given
1.281 + 'event_parent' page in the page hierarchy will omit this parent information
1.282 + if its name is used as the summary.
1.283 + """
1.284 +
1.285 + event_details = self.getEventDetails()
1.286
1.287 - "Return a dictionary of event details from the given 'page'."
1.288 + if event_details.has_key("title"):
1.289 + return event_details["title"]
1.290 + elif event_details.has_key("summary"):
1.291 + return event_details["summary"]
1.292 + else:
1.293 + # If appropriate, remove the parent details and "/" character.
1.294 +
1.295 + title = self.getPageName()
1.296
1.297 - event_details = {}
1.298 + if event_parent is not None and title.startswith(event_parent):
1.299 + title = title[len(event_parent.rstrip("/")) + 1:]
1.300 +
1.301 + return getPrettyTitle(title)
1.302 +
1.303 + def setEventDetails(self, event_details):
1.304 +
1.305 + "Set the 'event_details' for this page."
1.306 +
1.307 + self.details = event_details
1.308 +
1.309 + def setCategoryMembership(self, category_names):
1.310
1.311 - if getFormat(page) == "wiki":
1.312 - for match in definition_list_regexp.finditer(page.get_raw_body()):
1.313 + """
1.314 + Set the category membership for the page using the specified
1.315 + 'category_names'.
1.316 + """
1.317 +
1.318 + self.categories = category_names
1.319 +
1.320 + def flushEventDetails(self):
1.321 +
1.322 + "Flush the current event details to this page's body text."
1.323
1.324 - # Skip commented-out items.
1.325 + new_body_parts = []
1.326 + end_of_last_match = 0
1.327 + body = self.getBody()
1.328 + event_details = self.getEventDetails()
1.329 +
1.330 + for match in definition_list_regexp.finditer(body):
1.331
1.332 - if match.group("optcomment"):
1.333 - continue
1.334 + # Add preceding text to the new body.
1.335 +
1.336 + new_body_parts.append(body[end_of_last_match:match.start()])
1.337 + end_of_last_match = match.end()
1.338 +
1.339 + # Get the matching regions, adding the term to the new body.
1.340 +
1.341 + new_body_parts.append(match.group("wholeterm"))
1.342
1.343 # Permit case-insensitive list terms.
1.344
1.345 @@ -187,276 +375,62 @@
1.346
1.347 # Special value type handling.
1.348
1.349 - # Dates.
1.350 -
1.351 - if term in ("start", "end"):
1.352 - desc = getDate(desc)
1.353 -
1.354 - # Lists (whose elements may be quoted).
1.355 -
1.356 - elif term in ("topics", "categories"):
1.357 - desc = [getSimpleWikiText(value.strip()) for value in desc.split(",")]
1.358 -
1.359 - # Labels which may well be quoted.
1.360 -
1.361 - elif term in ("title", "summary", "description"):
1.362 - desc = getSimpleWikiText(desc)
1.363 + if event_details.has_key(term):
1.364
1.365 - if desc is not None:
1.366 - event_details[term] = desc
1.367 -
1.368 - return event_details
1.369 -
1.370 -def setEventDetails(body, event_details):
1.371 -
1.372 - """
1.373 - Set the event details in the given page 'body' using the 'event_details'
1.374 - dictionary, returning the new body text.
1.375 - """
1.376 -
1.377 - new_body_parts = []
1.378 - end_of_last_match = 0
1.379 -
1.380 - for match in definition_list_regexp.finditer(body):
1.381 + # Dates.
1.382
1.383 - # Add preceding text to the new body.
1.384 -
1.385 - new_body_parts.append(body[end_of_last_match:match.start()])
1.386 - end_of_last_match = match.end()
1.387 -
1.388 - # Get the matching regions, adding the term to the new body.
1.389 -
1.390 - new_body_parts.append(match.group("wholeterm"))
1.391 -
1.392 - # Permit case-insensitive list terms.
1.393 -
1.394 - term = match.group("term").lower()
1.395 - desc = match.group("desc")
1.396 -
1.397 - # Special value type handling.
1.398 + if term in ("start", "end"):
1.399 + desc = desc.replace("YYYY-MM-DD", str(event_details[term]))
1.400
1.401 - if event_details.has_key(term):
1.402 -
1.403 - # Dates.
1.404 -
1.405 - if term in ("start", "end"):
1.406 - desc = desc.replace("YYYY-MM-DD", event_details[term])
1.407 + # Lists (whose elements may be quoted).
1.408
1.409 - # Lists (whose elements may be quoted).
1.410 -
1.411 - elif term in ("topics", "categories"):
1.412 - desc = ", ".join(getEncodedWikiText(event_details[term]))
1.413 -
1.414 - # Labels which may well be quoted.
1.415 -
1.416 - elif term in ("title", "summary"):
1.417 - desc = getEncodedWikiText(event_details[term])
1.418 + elif term in ("topics", "categories"):
1.419 + desc = ", ".join(getEncodedWikiText(event_details[term]))
1.420
1.421 - # Text which need not be quoted, but it will be Wiki text.
1.422 -
1.423 - elif term in ("description",):
1.424 - desc = event_details[term]
1.425 -
1.426 - new_body_parts.append(desc)
1.427 -
1.428 - else:
1.429 - new_body_parts.append(body[end_of_last_match:])
1.430 -
1.431 - return "".join(new_body_parts)
1.432 -
1.433 -def setCategoryMembership(body, category_names):
1.434 + # Labels which may well be quoted.
1.435
1.436 - """
1.437 - Set the category membership in the given page 'body' using the specified
1.438 - 'category_names' and returning the new body text.
1.439 - """
1.440 + elif term in ("title", "summary"):
1.441 + desc = getEncodedWikiText(event_details[term])
1.442
1.443 - match = category_membership_regexp.search(body)
1.444 - if match:
1.445 - return "".join([body[:match.start()], " ".join(category_names), body[match.end():]])
1.446 - else:
1.447 - return body
1.448 -
1.449 -def getEventSummary(event_page, event_details, event_parent=None):
1.450 -
1.451 - """
1.452 - Return either the given title or summary of the event described by the given
1.453 - 'event_page', according to the given 'event_details', or return the pretty
1.454 - version of the page name.
1.455 + # Text which need not be quoted, but it will be Wiki text.
1.456
1.457 - If the optional 'event_parent' is specified, any page beneath the given
1.458 - 'event_parent' page in the page hierarchy will omit this parent information
1.459 - if its name is used as the summary.
1.460 - """
1.461 -
1.462 - if event_details.has_key("title"):
1.463 - return event_details["title"]
1.464 - elif event_details.has_key("summary"):
1.465 - return event_details["summary"]
1.466 - else:
1.467 - # If appropriate, remove the parent details and "/" character.
1.468 -
1.469 - title = event_page.page_name
1.470 + elif term in ("description",):
1.471 + desc = event_details[term]
1.472
1.473 - if event_parent is not None and title.startswith(event_parent):
1.474 - title = title[len(event_parent.rstrip("/")) + 1:]
1.475 -
1.476 - return getPrettyTitle(title)
1.477 -
1.478 -def getDate(s):
1.479 -
1.480 - "Parse the string 's', extracting and returning a date string."
1.481 + new_body_parts.append(desc)
1.482
1.483 - m = date_regexp.search(s)
1.484 - if m:
1.485 - return tuple(map(int, m.groups()))
1.486 - else:
1.487 - return None
1.488 -
1.489 -def getMonth(s):
1.490 -
1.491 - "Parse the string 's', extracting and returning a month string."
1.492 + else:
1.493 + new_body_parts.append(body[end_of_last_match:])
1.494
1.495 - m = month_regexp.search(s)
1.496 - if m:
1.497 - return tuple(map(int, m.groups()))
1.498 - else:
1.499 - return None
1.500 -
1.501 -def getCurrentMonth():
1.502 -
1.503 - "Return the current month as a (year, month) tuple."
1.504 -
1.505 - today = datetime.date.today()
1.506 - return (today.year, today.month)
1.507 + self.body = "".join(new_body_parts)
1.508
1.509 -def getCurrentYear():
1.510 -
1.511 - "Return the current year."
1.512 -
1.513 - today = datetime.date.today()
1.514 - return today.year
1.515 + def flushCategoryMembership(self):
1.516
1.517 -def monthupdate(date, n):
1.518 -
1.519 - "Return 'date' updated by 'n' months."
1.520 -
1.521 - if n < 0:
1.522 - fn = prevmonth
1.523 - else:
1.524 - fn = nextmonth
1.525 + "Flush the category membership to the page body."
1.526
1.527 - i = 0
1.528 - while i < abs(n):
1.529 - date = fn(date)
1.530 - i += 1
1.531 -
1.532 - return date
1.533 -
1.534 -def daterange(first, last, step=1):
1.535 -
1.536 - """
1.537 - Get the range of dates starting at 'first' and ending on 'last', using the
1.538 - specified 'step'.
1.539 - """
1.540 -
1.541 - results = []
1.542 + body = self.getBody()
1.543 + category_names = self.getCategoryMembership()
1.544 + match = category_membership_regexp.search(body)
1.545
1.546 - months_only = len(first) == 2
1.547 - start_year = first[0]
1.548 - end_year = last[0]
1.549 + if match:
1.550 + self.body = "".join([body[:match.start()], " ".join(category_names), body[match.end():]])
1.551
1.552 - for year in range(start_year, end_year + step, step):
1.553 - if step == 1 and year < end_year:
1.554 - end_month = 12
1.555 - elif step == -1 and year > end_year:
1.556 - end_month = 1
1.557 - else:
1.558 - end_month = last[1]
1.559 -
1.560 - if step == 1 and year > start_year:
1.561 - start_month = 1
1.562 - elif step == -1 and year < start_year:
1.563 - start_month = 12
1.564 - else:
1.565 - start_month = first[1]
1.566 + def saveChanges(self):
1.567
1.568 - for month in range(start_month, end_month + step, step):
1.569 - if months_only:
1.570 - results.append((year, month))
1.571 - else:
1.572 - if step == 1 and month < end_month:
1.573 - _wd, end_day = calendar.monthrange(year, month)
1.574 - elif step == -1 and month > end_month:
1.575 - end_day = 1
1.576 - else:
1.577 - end_day = last[2]
1.578 -
1.579 - if step == 1 and month > start_month:
1.580 - start_day = 1
1.581 - elif step == -1 and month < start_month:
1.582 - _wd, start_day = calendar.monthrange(year, month)
1.583 - else:
1.584 - start_day = first[2]
1.585 + "Save changes to the event."
1.586
1.587 - for day in range(start_day, end_day + step, step):
1.588 - results.append((year, month, day))
1.589 -
1.590 - return results
1.591 -
1.592 -def nextdate(date):
1.593 -
1.594 - "Return the date following the given 'date'."
1.595 -
1.596 - year, month, day = date
1.597 - _wd, end_day = calendar.monthrange(year, month)
1.598 - if day == end_day:
1.599 - if month == 12:
1.600 - return (year + 1, 1, 1)
1.601 - else:
1.602 - return (year, month + 1, 1)
1.603 - else:
1.604 - return (year, month, day + 1)
1.605 + self.flushEventDetails()
1.606 + self.flushCategoryMembership()
1.607 + self.page.saveText(self.getBody(), 0)
1.608
1.609 -def prevdate(date):
1.610 -
1.611 - "Return the date preceding the given 'date'."
1.612 -
1.613 - year, month, day = date
1.614 - if day == 1:
1.615 - if month == 1:
1.616 - return (year - 1, 12, 31)
1.617 - else:
1.618 - _wd, end_day = calendar.monthrange(year, month - 1)
1.619 - return (year, month - 1, end_day)
1.620 - else:
1.621 - return (year, month, day - 1)
1.622 -
1.623 -def nextmonth(date):
1.624 -
1.625 - "Return the (year, month) tuple following 'date'."
1.626 + def linkToPage(self, request, text, query_string=None):
1.627
1.628 - year, month = date
1.629 - if month == 12:
1.630 - return (year + 1, 1)
1.631 - else:
1.632 - return year, month + 1
1.633 -
1.634 -def prevmonth(date):
1.635 -
1.636 - "Return the (year, month) tuple preceding 'date'."
1.637 + """
1.638 + Using 'request', return a link to this page with the given link 'text'
1.639 + and optional 'query_string'.
1.640 + """
1.641
1.642 - year, month = date
1.643 - if month == 1:
1.644 - return (year - 1, 12)
1.645 - else:
1.646 - return year, month - 1
1.647 -
1.648 -def span(start, end):
1.649 -
1.650 - "Return the difference between 'start' and 'end'."
1.651 -
1.652 - return end[0] - start[0], end[1] - start[1]
1.653 + return linkToPage(request, self.page, text, query_string)
1.654
1.655 def getEvents(request, category_names, calendar_start=None, calendar_end=None):
1.656
1.657 @@ -489,7 +463,7 @@
1.658
1.659 # Get the pages and page names in the category.
1.660
1.661 - pages_in_category = getPages(category_name, request)
1.662 + pages_in_category = getCategoryPages(category_name, request)
1.663
1.664 # Visit each page in the category.
1.665
1.666 @@ -505,20 +479,19 @@
1.667
1.668 # Get a real page, not a result page.
1.669
1.670 - real_page_in_category = Page(request, pagename)
1.671 - event_details = getEventDetails(real_page_in_category)
1.672 + event_page = EventPage(Page(request, pagename))
1.673 + event_details = event_page.getEventDetails()
1.674
1.675 - # Define the event as the page together with its details.
1.676 + # Remember the event page.
1.677
1.678 - event = (real_page_in_category, event_details)
1.679 - events.append(event)
1.680 + events.append(event_page)
1.681
1.682 # Test for the suitability of the event.
1.683
1.684 if event_details.has_key("start") and event_details.has_key("end"):
1.685
1.686 - start_month = event_details["start"][:2]
1.687 - end_month = event_details["end"][:2]
1.688 + start_month = event_details["start"].as_month()
1.689 + end_month = event_details["end"].as_month()
1.690
1.691 # Compare the months of the dates to the requested calendar
1.692 # window, if any.
1.693 @@ -526,7 +499,7 @@
1.694 if (calendar_start is None or end_month >= calendar_start) and \
1.695 (calendar_end is None or start_month <= calendar_end):
1.696
1.697 - all_shown_events.append(event)
1.698 + all_shown_events.append(event_page)
1.699
1.700 if earliest is None or start_month < earliest:
1.701 earliest = start_month
1.702 @@ -538,10 +511,10 @@
1.703 first = max(start_month, calendar_start or start_month)
1.704 last = min(end_month, calendar_end or end_month)
1.705
1.706 - for event_month in daterange(first, last):
1.707 + for event_month in first.months_until(last):
1.708 if not shown_events.has_key(event_month):
1.709 shown_events[event_month] = []
1.710 - shown_events[event_month].append(event)
1.711 + shown_events[event_month].append(event_page)
1.712
1.713 return events, shown_events, all_shown_events, earliest, latest
1.714
1.715 @@ -549,25 +522,26 @@
1.716
1.717 """
1.718 Using 'request', set timestamp details in the details dictionary of each of
1.719 - the 'events': a list of the form (event_page, event_details).
1.720 + the 'events'.
1.721
1.722 Retutn the latest timestamp found.
1.723 """
1.724
1.725 latest = None
1.726
1.727 - for event_page, event_details in events:
1.728 + for event_page in events:
1.729 + event_details = event_page.getEventDetails()
1.730
1.731 # Get the initial revision of the page.
1.732
1.733 - revisions = event_page.getRevList()
1.734 - event_page_initial = Page(request, event_page.page_name, rev=revisions[-1])
1.735 + revisions = event_page.getRevisions()
1.736 + event_page_initial = Page(request, event_page.getPageName(), rev=revisions[-1])
1.737
1.738 # Get the created and last modified times.
1.739
1.740 initial_revision = getPageRevision(event_page_initial)
1.741 event_details["created"] = initial_revision["timestamp"]
1.742 - latest_revision = getPageRevision(event_page)
1.743 + latest_revision = event_page.getPageRevision()
1.744 event_details["last-modified"] = latest_revision["timestamp"]
1.745 event_details["sequence"] = len(revisions) - 1
1.746 event_details["last-comment"] = latest_revision["comment"]
1.747 @@ -579,15 +553,10 @@
1.748
1.749 def compareEvents(event1, event2):
1.750
1.751 - """
1.752 - Compare 'event1' and 'event2' by start and end date, where both parameters
1.753 - are of the following form:
1.754 + "Compare 'event1' and 'event2' by start and end date."
1.755
1.756 - (event_page, event_details)
1.757 - """
1.758 -
1.759 - event_page1, event_details1 = event1
1.760 - event_page2, event_details2 = event2
1.761 + event_details1 = event1.getEventDetails()
1.762 + event_details2 = event2.getEventDetails()
1.763 return cmp(
1.764 (event_details1["start"], event_details1["end"]),
1.765 (event_details2["start"], event_details2["end"])
1.766 @@ -597,9 +566,7 @@
1.767
1.768 """
1.769 Return a list with the given 'events' ordered according to their start and
1.770 - end dates. Each list element must be of the following form:
1.771 -
1.772 - (event_page, event_details)
1.773 + end dates.
1.774 """
1.775
1.776 ordered_events = events[:]
1.777 @@ -651,8 +618,8 @@
1.778
1.779 # Get event details.
1.780
1.781 - for event in events:
1.782 - event_page, event_details = event
1.783 + for event_page in events:
1.784 + event_details = event_page.getEventDetails()
1.785
1.786 # Test for the event in the period.
1.787
1.788 @@ -662,7 +629,7 @@
1.789
1.790 event_start = max(event_details["start"], start)
1.791 event_end = min(event_details["end"], end)
1.792 - event_coverage = set(daterange(event_start, event_end))
1.793 + event_coverage = set(event_start.days_until(event_end))
1.794
1.795 # Update the overall coverage.
1.796
1.797 @@ -676,7 +643,7 @@
1.798 # element, add it alongside existing events.
1.799
1.800 if not coverage.intersection(event_coverage):
1.801 - covered_events.append(event)
1.802 + covered_events.append(event_page)
1.803 all_events[i] = coverage.union(event_coverage), covered_events
1.804 break
1.805
1.806 @@ -684,10 +651,185 @@
1.807 # marked alongside existing events.
1.808
1.809 else:
1.810 - all_events.append((event_coverage, [event]))
1.811 + all_events.append((event_coverage, [event_page]))
1.812
1.813 return full_coverage, all_events
1.814
1.815 +# Date-related functions.
1.816 +
1.817 +class Period:
1.818 +
1.819 + "A simple period of time."
1.820 +
1.821 + def __init__(self, data):
1.822 + self.data = data
1.823 +
1.824 + def months(self):
1.825 + return self.data[0] * 12 + self.data[1]
1.826 +
1.827 +class Month:
1.828 +
1.829 + "A simple year-month representation."
1.830 +
1.831 + def __init__(self, data):
1.832 + self.data = tuple(data)
1.833 +
1.834 + def __repr__(self):
1.835 + return "%s(%r)" % (self.__class__.__name__, self.data)
1.836 +
1.837 + def __str__(self):
1.838 + return "%04d-%02d" % self.as_tuple()[:2]
1.839 +
1.840 + def __hash__(self):
1.841 + return hash(self.as_tuple())
1.842 +
1.843 + def as_tuple(self):
1.844 + return self.data
1.845 +
1.846 + def as_date(self, day):
1.847 + return Date(self.as_tuple() + (day,))
1.848 +
1.849 + def year(self):
1.850 + return self.data[0]
1.851 +
1.852 + def month(self):
1.853 + return self.data[1]
1.854 +
1.855 + def month_properties(self):
1.856 +
1.857 + """
1.858 + Return the weekday of the 1st of the month, along with the number of
1.859 + days, as a tuple.
1.860 + """
1.861 +
1.862 + year, month = self.data
1.863 + return calendar.monthrange(year, month)
1.864 +
1.865 + def month_update(self, n=1):
1.866 +
1.867 + "Return the month updated by 'n' months."
1.868 +
1.869 + year, month = self.data
1.870 + return Month((year + (month - 1 + n) / 12, (month - 1 + n) % 12 + 1))
1.871 +
1.872 + def next_month(self):
1.873 +
1.874 + "Return the month following this one."
1.875 +
1.876 + return self.month_update(1)
1.877 +
1.878 + def previous_month(self):
1.879 +
1.880 + "Return the month preceding this one."
1.881 +
1.882 + return self.month_update(-1)
1.883 +
1.884 + def __sub__(self, start):
1.885 +
1.886 + """
1.887 + Return the difference in years and months between this month and the
1.888 + 'start' month as a period.
1.889 + """
1.890 +
1.891 + return Period([(x - y) for x, y in zip(self.data, start.data)])
1.892 +
1.893 + def __cmp__(self, other):
1.894 + return cmp(self.data, other.data)
1.895 +
1.896 + def until(self, end, nextfn, prevfn):
1.897 + month = self
1.898 + months = [month]
1.899 + if month < end:
1.900 + while month < end:
1.901 + month = nextfn(month)
1.902 + months.append(month)
1.903 + elif month > end:
1.904 + while month > end:
1.905 + month = prevfn(month)
1.906 + months.append(month)
1.907 + return months
1.908 +
1.909 + def months_until(self, end):
1.910 + return self.until(end, Month.next_month, Month.previous_month)
1.911 +
1.912 +class Date(Month):
1.913 +
1.914 + "A simple year-month-day representation."
1.915 +
1.916 + def __str__(self):
1.917 + return "%04d-%02d-%02d" % self.as_tuple()[:3]
1.918 +
1.919 + def as_month(self):
1.920 + return Month(self.data[:2])
1.921 +
1.922 + def day(self):
1.923 + return self.data[2]
1.924 +
1.925 + def next_day(self):
1.926 +
1.927 + "Return the date following this one."
1.928 +
1.929 + year, month, day = self.data
1.930 + _wd, end_day = calendar.monthrange(year, month)
1.931 + if day == end_day:
1.932 + if month == 12:
1.933 + return Date((year + 1, 1, 1))
1.934 + else:
1.935 + return Date((year, month + 1, 1))
1.936 + else:
1.937 + return Date((year, month, day + 1))
1.938 +
1.939 + def previous_day(self):
1.940 +
1.941 + "Return the date preceding this one."
1.942 +
1.943 + year, month, day = self.data
1.944 + if day == 1:
1.945 + if month == 1:
1.946 + return Date((year - 1, 12, 31))
1.947 + else:
1.948 + _wd, end_day = calendar.monthrange(year, month - 1)
1.949 + return Date((year, month - 1, end_day))
1.950 + else:
1.951 + return Date((year, month, day - 1))
1.952 +
1.953 + def days_until(self, end):
1.954 + return self.until(end, Date.next_day, Date.previous_day)
1.955 +
1.956 +def getDate(s):
1.957 +
1.958 + "Parse the string 's', extracting and returning a date string."
1.959 +
1.960 + m = date_regexp.search(s)
1.961 + if m:
1.962 + return Date(map(int, m.groups()))
1.963 + else:
1.964 + return None
1.965 +
1.966 +def getMonth(s):
1.967 +
1.968 + "Parse the string 's', extracting and returning a month string."
1.969 +
1.970 + m = month_regexp.search(s)
1.971 + if m:
1.972 + return Month(map(int, m.groups()))
1.973 + else:
1.974 + return None
1.975 +
1.976 +def getCurrentMonth():
1.977 +
1.978 + "Return the current month as a (year, month) tuple."
1.979 +
1.980 + today = datetime.date.today()
1.981 + return Month((today.year, today.month))
1.982 +
1.983 +def getCurrentYear():
1.984 +
1.985 + "Return the current year."
1.986 +
1.987 + today = datetime.date.today()
1.988 + return today.year
1.989 +
1.990 # User interface functions.
1.991
1.992 def getParameter(request, name, default=None):
1.993 @@ -704,6 +846,9 @@
1.994 return "%s-%s" % (calendar_name, argname)
1.995
1.996 def getParameterMonth(arg):
1.997 +
1.998 + "Interpret 'arg', recognising keywords and simple arithmetic operations."
1.999 +
1.1000 n = None
1.1001
1.1002 if arg.startswith("current"):
1.1003 @@ -712,12 +857,12 @@
1.1004 n = int(arg[7:])
1.1005
1.1006 elif arg.startswith("yearstart"):
1.1007 - date = (getCurrentYear(), 1)
1.1008 + date = Month((getCurrentYear(), 1))
1.1009 if len(arg) > 10:
1.1010 n = int(arg[9:])
1.1011
1.1012 elif arg.startswith("yearend"):
1.1013 - date = (getCurrentYear(), 12)
1.1014 + date = Month((getCurrentYear(), 12))
1.1015 if len(arg) > 8:
1.1016 n = int(arg[7:])
1.1017
1.1018 @@ -725,11 +870,17 @@
1.1019 date = getMonth(arg)
1.1020
1.1021 if n is not None:
1.1022 - date = monthupdate(date, n)
1.1023 + date = date.month_update(n)
1.1024
1.1025 return date
1.1026
1.1027 def getFormMonth(request, calendar_name, argname):
1.1028 +
1.1029 + """
1.1030 + Return the month from the 'request' for the calendar with the given
1.1031 + 'calendar_name' using the parameter having the given 'argname'.
1.1032 + """
1.1033 +
1.1034 arg = getQualifiedParameter(request, calendar_name, argname)
1.1035 if arg is not None:
1.1036 return getParameterMonth(arg)
1.1037 @@ -737,13 +888,22 @@
1.1038 return None
1.1039
1.1040 def getFormMonthPair(request, yeararg, montharg):
1.1041 +
1.1042 + """
1.1043 + Return the month from the 'request' for the calendar with the given
1.1044 + 'calendar_name' using the parameters having the given 'yeararg' and
1.1045 + 'montharg' names.
1.1046 + """
1.1047 +
1.1048 year = getParameter(request, yeararg)
1.1049 month = getParameter(request, montharg)
1.1050 if year and month:
1.1051 - return (int(year), int(month))
1.1052 + return Month((int(year), int(month)))
1.1053 else:
1.1054 return None
1.1055
1.1056 +# Page-related functions.
1.1057 +
1.1058 def getPrettyPageName(page):
1.1059
1.1060 "Return a nicely formatted title/name for the given 'page'."
1.1061 @@ -755,24 +915,6 @@
1.1062
1.1063 return getPrettyTitle(title)
1.1064
1.1065 -def getPrettyTitle(title):
1.1066 -
1.1067 - "Return a nicely formatted version of the given 'title'."
1.1068 -
1.1069 - return title.replace("_", " ").replace("/", u" » ")
1.1070 -
1.1071 -def getMonthLabel(month):
1.1072 -
1.1073 - "Return an unlocalised label for the given 'month'."
1.1074 -
1.1075 - return month_labels[month - 1] # zero-based labels
1.1076 -
1.1077 -def getDayLabel(weekday):
1.1078 -
1.1079 - "Return an unlocalised label for the given 'weekday'."
1.1080 -
1.1081 - return weekday_labels[weekday]
1.1082 -
1.1083 def linkToPage(request, page, text, query_string=None):
1.1084
1.1085 """
1.1086 @@ -790,13 +932,4 @@
1.1087 else:
1.1088 return page.link_to_raw(request, text, query_string)
1.1089
1.1090 -def getPageURL(request, page):
1.1091 -
1.1092 - "Using 'request', return the URL of 'page'."
1.1093 -
1.1094 - if isMoin15():
1.1095 - return request.getQualifiedURL(page.url(request))
1.1096 - else:
1.1097 - return request.getQualifiedURL(page.url(request, relative=0))
1.1098 -
1.1099 # vim: tabstop=4 expandtab shiftwidth=4