# HG changeset patch # User Paul Boddie # Date 1264298153 -3600 # Node ID 0340bf1c9f224fce6aee499f51879b7a1af3475c # Parent fdf1ec151ab6b90fdabd9c721f820862f2730da4 Introduced abstractions for event pages, months and dates with substantial modifications made to the rest of the code to handle these correctly. diff -r fdf1ec151ab6 -r 0340bf1c9f22 EventAggregatorSupport.py --- a/EventAggregatorSupport.py Mon Jan 18 01:00:35 2010 +0100 +++ b/EventAggregatorSupport.py Sun Jan 24 02:55:53 2010 +0100 @@ -2,7 +2,7 @@ """ MoinMoin - EventAggregator library - @copyright: 2008, 2009 by Paul Boddie + @copyright: 2008, 2009, 2010 by Paul Boddie @copyright: 2000-2004 Juergen Hermann , 2005-2008 MoinMoin:ThomasWaldmann. @license: GNU GPL (v2 or later), see COPYING.txt for details. @@ -65,8 +65,74 @@ category_regexp = re.compile(u'^%s$' % ur'(?PCategory(?P(?!Template)\S+))', re.UNICODE) return category_regexp +# Textual representations. + +def getHTTPTimeString(tmtuple): + return "%s, %02d %s %04d %02d:%02d:%02d GMT" % ( + weekday_labels[tmtuple.tm_wday], + tmtuple.tm_mday, + month_labels[tmtuple.tm_mon -1], # zero-based labels + tmtuple.tm_year, + tmtuple.tm_hour, + tmtuple.tm_min, + tmtuple.tm_sec + ) + +def getSimpleWikiText(text): + + """ + Return the plain text representation of the given 'text' which may employ + certain Wiki syntax features, such as those providing verbatim or monospaced + text. + """ + + # NOTE: Re-implementing support for verbatim text and linking avoidance. + + return "".join([s for s in verbatim_regexp.split(text) if s is not None]) + +def getEncodedWikiText(text): + + "Encode the given 'text' in a verbatim representation." + + return "<>" % text + +def getPrettyTitle(title): + + "Return a nicely formatted version of the given 'title'." + + return title.replace("_", " ").replace("/", u" » ") + +def getMonthLabel(month): + + "Return an unlocalised label for the given 'month'." + + return month_labels[month - 1] # zero-based labels + +def getDayLabel(weekday): + + "Return an unlocalised label for the given 'weekday'." + + return weekday_labels[weekday] + # Action support functions. +def getPageRevision(page): + + "Return the revision details dictionary for the given 'page'." + + # From Page.edit_info... + + if hasattr(page, "editlog_entry"): + line = page.editlog_entry() + else: + line = page._last_edited(page.request) # MoinMoin 1.5.x and 1.6.x + + timestamp = line.ed_time_usecs + mtime = wikiutil.version2timestamp(long(timestamp)) # must be long for py 2.2.x + return {"timestamp" : time.gmtime(mtime), "comment" : line.comment} + +# Category discovery and searching. + def getCategories(request): """ @@ -95,35 +161,12 @@ mapping.sort() return mapping -def getPageRevision(page): - - # From Page.edit_info... - - if hasattr(page, "editlog_entry"): - line = page.editlog_entry() - else: - line = page._last_edited(page.request) # MoinMoin 1.5.x and 1.6.x - - timestamp = line.ed_time_usecs - mtime = wikiutil.version2timestamp(long(timestamp)) # must be long for py 2.2.x - return {"timestamp" : time.gmtime(mtime), "comment" : line.comment} +def getCategoryPages(pagename, request): -def getHTTPTimeString(tmtuple): - return "%s, %02d %s %04d %02d:%02d:%02d GMT" % ( - weekday_labels[tmtuple.tm_wday], - tmtuple.tm_mday, - month_labels[tmtuple.tm_mon -1], # zero-based labels - tmtuple.tm_year, - tmtuple.tm_hour, - tmtuple.tm_min, - tmtuple.tm_sec - ) - -# The main activity functions. - -def getPages(pagename, request): - - "Return the links minus category links for 'pagename' using the 'request'." + """ + Return the pages associated with the given category 'pagename' using the + 'request'. + """ query = search.QueryParser().parse_query('category:%s' % pagename) if isMoin15(): @@ -139,46 +182,191 @@ pages.append(page) return pages -def getSimpleWikiText(text): +# The main activity functions. + +class EventPage: + + "An event page." + + def __init__(self, page): + self.page = page + self.details = None + self.body = None + self.categories = None + + def copyPage(self, page): + + "Copy the body of the given 'page'." + + self.body = page.getBody() + + def getPageURL(self, request): + + "Using 'request', return the URL of this page." - """ - Return the plain text representation of the given 'text' which may employ - certain Wiki syntax features, such as those providing verbatim or monospaced - text. - """ + page = self.page + + if isMoin15(): + return request.getQualifiedURL(page.url(request)) + else: + return request.getQualifiedURL(page.url(request, relative=0)) + + def getFormat(self): + + "Get the format used on this page." - # NOTE: Re-implementing support for verbatim text and linking avoidance. + if isMoin15(): + return "wiki" # page.pi_format + else: + return self.page.pi["format"] + + def getRevisions(self): + + "Return a list of page revisions." + + return self.page.getRevList() + + def getPageRevision(self): - return "".join([s for s in verbatim_regexp.split(text) if s is not None]) + "Return the revision details dictionary for this page." + + return getPageRevision(self.page) + + def getPageName(self): + + "Return the page name." + + return self.page.page_name -def getEncodedWikiText(text): + def getPrettyPageName(self): + + "Return a nicely formatted title/name for this page." + + return getPrettyPageName(self.page) + + def getBody(self): + + "Get the current page body." - "Encode the given 'text' in a verbatim representation." + if self.body is None: + self.body = self.page.get_raw_body() + return self.body + + def getEventDetails(self): + + "Return a dictionary of event details from this page." + + if self.details is None: + self.details = {} - return "<>" % text + if self.getFormat() == "wiki": + for match in definition_list_regexp.finditer(self.getBody()): + + # Skip commented-out items. -def getFormat(page): + if match.group("optcomment"): + continue + + # Permit case-insensitive list terms. + + term = match.group("term").lower() + desc = match.group("desc") + + # Special value type handling. - "Get the format used on 'page'." + # Dates. + + if term in ("start", "end"): + desc = getDate(desc) + + # Lists (whose elements may be quoted). + + elif term in ("topics", "categories"): + desc = [getSimpleWikiText(value.strip()) for value in desc.split(",")] + + # Labels which may well be quoted. + + elif term in ("title", "summary", "description"): + desc = getSimpleWikiText(desc) + + if desc is not None: + self.details[term] = desc + + return self.details + + def getCategoryMembership(self): - if isMoin15(): - return "wiki" # page.pi_format - else: - return page.pi["format"] + "Get the category names from this page." + + if self.categories is None: + body = self.getBody() + match = category_membership_regexp.search(body) + self.categories = match.findall().split() + + return self.categories + + def getEventSummary(self, event_parent=None): -def getEventDetails(page): + """ + Return either the given title or summary of the event described by this + page, according to the page's event details, or using the pretty version + of the page name. + + If the optional 'event_parent' is specified, any page beneath the given + 'event_parent' page in the page hierarchy will omit this parent information + if its name is used as the summary. + """ + + event_details = self.getEventDetails() - "Return a dictionary of event details from the given 'page'." + if event_details.has_key("title"): + return event_details["title"] + elif event_details.has_key("summary"): + return event_details["summary"] + else: + # If appropriate, remove the parent details and "/" character. + + title = self.getPageName() - event_details = {} + if event_parent is not None and title.startswith(event_parent): + title = title[len(event_parent.rstrip("/")) + 1:] + + return getPrettyTitle(title) + + def setEventDetails(self, event_details): + + "Set the 'event_details' for this page." + + self.details = event_details + + def setCategoryMembership(self, category_names): - if getFormat(page) == "wiki": - for match in definition_list_regexp.finditer(page.get_raw_body()): + """ + Set the category membership for the page using the specified + 'category_names'. + """ + + self.categories = category_names + + def flushEventDetails(self): + + "Flush the current event details to this page's body text." - # Skip commented-out items. + new_body_parts = [] + end_of_last_match = 0 + body = self.getBody() + event_details = self.getEventDetails() + + for match in definition_list_regexp.finditer(body): - if match.group("optcomment"): - continue + # Add preceding text to the new body. + + new_body_parts.append(body[end_of_last_match:match.start()]) + end_of_last_match = match.end() + + # Get the matching regions, adding the term to the new body. + + new_body_parts.append(match.group("wholeterm")) # Permit case-insensitive list terms. @@ -187,276 +375,62 @@ # Special value type handling. - # Dates. - - if term in ("start", "end"): - desc = getDate(desc) - - # Lists (whose elements may be quoted). - - elif term in ("topics", "categories"): - desc = [getSimpleWikiText(value.strip()) for value in desc.split(",")] - - # Labels which may well be quoted. - - elif term in ("title", "summary", "description"): - desc = getSimpleWikiText(desc) + if event_details.has_key(term): - if desc is not None: - event_details[term] = desc - - return event_details - -def setEventDetails(body, event_details): - - """ - Set the event details in the given page 'body' using the 'event_details' - dictionary, returning the new body text. - """ - - new_body_parts = [] - end_of_last_match = 0 - - for match in definition_list_regexp.finditer(body): + # Dates. - # Add preceding text to the new body. - - new_body_parts.append(body[end_of_last_match:match.start()]) - end_of_last_match = match.end() - - # Get the matching regions, adding the term to the new body. - - new_body_parts.append(match.group("wholeterm")) - - # Permit case-insensitive list terms. - - term = match.group("term").lower() - desc = match.group("desc") - - # Special value type handling. + if term in ("start", "end"): + desc = desc.replace("YYYY-MM-DD", str(event_details[term])) - if event_details.has_key(term): - - # Dates. - - if term in ("start", "end"): - desc = desc.replace("YYYY-MM-DD", event_details[term]) + # Lists (whose elements may be quoted). - # Lists (whose elements may be quoted). - - elif term in ("topics", "categories"): - desc = ", ".join(getEncodedWikiText(event_details[term])) - - # Labels which may well be quoted. - - elif term in ("title", "summary"): - desc = getEncodedWikiText(event_details[term]) + elif term in ("topics", "categories"): + desc = ", ".join(getEncodedWikiText(event_details[term])) - # Text which need not be quoted, but it will be Wiki text. - - elif term in ("description",): - desc = event_details[term] - - new_body_parts.append(desc) - - else: - new_body_parts.append(body[end_of_last_match:]) - - return "".join(new_body_parts) - -def setCategoryMembership(body, category_names): + # Labels which may well be quoted. - """ - Set the category membership in the given page 'body' using the specified - 'category_names' and returning the new body text. - """ + elif term in ("title", "summary"): + desc = getEncodedWikiText(event_details[term]) - match = category_membership_regexp.search(body) - if match: - return "".join([body[:match.start()], " ".join(category_names), body[match.end():]]) - else: - return body - -def getEventSummary(event_page, event_details, event_parent=None): - - """ - Return either the given title or summary of the event described by the given - 'event_page', according to the given 'event_details', or return the pretty - version of the page name. + # Text which need not be quoted, but it will be Wiki text. - If the optional 'event_parent' is specified, any page beneath the given - 'event_parent' page in the page hierarchy will omit this parent information - if its name is used as the summary. - """ - - if event_details.has_key("title"): - return event_details["title"] - elif event_details.has_key("summary"): - return event_details["summary"] - else: - # If appropriate, remove the parent details and "/" character. - - title = event_page.page_name + elif term in ("description",): + desc = event_details[term] - if event_parent is not None and title.startswith(event_parent): - title = title[len(event_parent.rstrip("/")) + 1:] - - return getPrettyTitle(title) - -def getDate(s): - - "Parse the string 's', extracting and returning a date string." + new_body_parts.append(desc) - m = date_regexp.search(s) - if m: - return tuple(map(int, m.groups())) - else: - return None - -def getMonth(s): - - "Parse the string 's', extracting and returning a month string." + else: + new_body_parts.append(body[end_of_last_match:]) - m = month_regexp.search(s) - if m: - return tuple(map(int, m.groups())) - else: - return None - -def getCurrentMonth(): - - "Return the current month as a (year, month) tuple." - - today = datetime.date.today() - return (today.year, today.month) + self.body = "".join(new_body_parts) -def getCurrentYear(): - - "Return the current year." - - today = datetime.date.today() - return today.year + def flushCategoryMembership(self): -def monthupdate(date, n): - - "Return 'date' updated by 'n' months." - - if n < 0: - fn = prevmonth - else: - fn = nextmonth + "Flush the category membership to the page body." - i = 0 - while i < abs(n): - date = fn(date) - i += 1 - - return date - -def daterange(first, last, step=1): - - """ - Get the range of dates starting at 'first' and ending on 'last', using the - specified 'step'. - """ - - results = [] + body = self.getBody() + category_names = self.getCategoryMembership() + match = category_membership_regexp.search(body) - months_only = len(first) == 2 - start_year = first[0] - end_year = last[0] + if match: + self.body = "".join([body[:match.start()], " ".join(category_names), body[match.end():]]) - for year in range(start_year, end_year + step, step): - if step == 1 and year < end_year: - end_month = 12 - elif step == -1 and year > end_year: - end_month = 1 - else: - end_month = last[1] - - if step == 1 and year > start_year: - start_month = 1 - elif step == -1 and year < start_year: - start_month = 12 - else: - start_month = first[1] + def saveChanges(self): - for month in range(start_month, end_month + step, step): - if months_only: - results.append((year, month)) - else: - if step == 1 and month < end_month: - _wd, end_day = calendar.monthrange(year, month) - elif step == -1 and month > end_month: - end_day = 1 - else: - end_day = last[2] - - if step == 1 and month > start_month: - start_day = 1 - elif step == -1 and month < start_month: - _wd, start_day = calendar.monthrange(year, month) - else: - start_day = first[2] + "Save changes to the event." - for day in range(start_day, end_day + step, step): - results.append((year, month, day)) - - return results - -def nextdate(date): - - "Return the date following the given 'date'." - - year, month, day = date - _wd, end_day = calendar.monthrange(year, month) - if day == end_day: - if month == 12: - return (year + 1, 1, 1) - else: - return (year, month + 1, 1) - else: - return (year, month, day + 1) + self.flushEventDetails() + self.flushCategoryMembership() + self.page.saveText(self.getBody(), 0) -def prevdate(date): - - "Return the date preceding the given 'date'." - - year, month, day = date - if day == 1: - if month == 1: - return (year - 1, 12, 31) - else: - _wd, end_day = calendar.monthrange(year, month - 1) - return (year, month - 1, end_day) - else: - return (year, month, day - 1) - -def nextmonth(date): - - "Return the (year, month) tuple following 'date'." + def linkToPage(self, request, text, query_string=None): - year, month = date - if month == 12: - return (year + 1, 1) - else: - return year, month + 1 - -def prevmonth(date): - - "Return the (year, month) tuple preceding 'date'." + """ + Using 'request', return a link to this page with the given link 'text' + and optional 'query_string'. + """ - year, month = date - if month == 1: - return (year - 1, 12) - else: - return year, month - 1 - -def span(start, end): - - "Return the difference between 'start' and 'end'." - - return end[0] - start[0], end[1] - start[1] + return linkToPage(request, self.page, text, query_string) def getEvents(request, category_names, calendar_start=None, calendar_end=None): @@ -489,7 +463,7 @@ # Get the pages and page names in the category. - pages_in_category = getPages(category_name, request) + pages_in_category = getCategoryPages(category_name, request) # Visit each page in the category. @@ -505,20 +479,19 @@ # Get a real page, not a result page. - real_page_in_category = Page(request, pagename) - event_details = getEventDetails(real_page_in_category) + event_page = EventPage(Page(request, pagename)) + event_details = event_page.getEventDetails() - # Define the event as the page together with its details. + # Remember the event page. - event = (real_page_in_category, event_details) - events.append(event) + events.append(event_page) # Test for the suitability of the event. if event_details.has_key("start") and event_details.has_key("end"): - start_month = event_details["start"][:2] - end_month = event_details["end"][:2] + start_month = event_details["start"].as_month() + end_month = event_details["end"].as_month() # Compare the months of the dates to the requested calendar # window, if any. @@ -526,7 +499,7 @@ if (calendar_start is None or end_month >= calendar_start) and \ (calendar_end is None or start_month <= calendar_end): - all_shown_events.append(event) + all_shown_events.append(event_page) if earliest is None or start_month < earliest: earliest = start_month @@ -538,10 +511,10 @@ first = max(start_month, calendar_start or start_month) last = min(end_month, calendar_end or end_month) - for event_month in daterange(first, last): + for event_month in first.months_until(last): if not shown_events.has_key(event_month): shown_events[event_month] = [] - shown_events[event_month].append(event) + shown_events[event_month].append(event_page) return events, shown_events, all_shown_events, earliest, latest @@ -549,25 +522,26 @@ """ Using 'request', set timestamp details in the details dictionary of each of - the 'events': a list of the form (event_page, event_details). + the 'events'. Retutn the latest timestamp found. """ latest = None - for event_page, event_details in events: + for event_page in events: + event_details = event_page.getEventDetails() # Get the initial revision of the page. - revisions = event_page.getRevList() - event_page_initial = Page(request, event_page.page_name, rev=revisions[-1]) + revisions = event_page.getRevisions() + event_page_initial = Page(request, event_page.getPageName(), rev=revisions[-1]) # Get the created and last modified times. initial_revision = getPageRevision(event_page_initial) event_details["created"] = initial_revision["timestamp"] - latest_revision = getPageRevision(event_page) + latest_revision = event_page.getPageRevision() event_details["last-modified"] = latest_revision["timestamp"] event_details["sequence"] = len(revisions) - 1 event_details["last-comment"] = latest_revision["comment"] @@ -579,15 +553,10 @@ def compareEvents(event1, event2): - """ - Compare 'event1' and 'event2' by start and end date, where both parameters - are of the following form: + "Compare 'event1' and 'event2' by start and end date." - (event_page, event_details) - """ - - event_page1, event_details1 = event1 - event_page2, event_details2 = event2 + event_details1 = event1.getEventDetails() + event_details2 = event2.getEventDetails() return cmp( (event_details1["start"], event_details1["end"]), (event_details2["start"], event_details2["end"]) @@ -597,9 +566,7 @@ """ Return a list with the given 'events' ordered according to their start and - end dates. Each list element must be of the following form: - - (event_page, event_details) + end dates. """ ordered_events = events[:] @@ -651,8 +618,8 @@ # Get event details. - for event in events: - event_page, event_details = event + for event_page in events: + event_details = event_page.getEventDetails() # Test for the event in the period. @@ -662,7 +629,7 @@ event_start = max(event_details["start"], start) event_end = min(event_details["end"], end) - event_coverage = set(daterange(event_start, event_end)) + event_coverage = set(event_start.days_until(event_end)) # Update the overall coverage. @@ -676,7 +643,7 @@ # element, add it alongside existing events. if not coverage.intersection(event_coverage): - covered_events.append(event) + covered_events.append(event_page) all_events[i] = coverage.union(event_coverage), covered_events break @@ -684,10 +651,185 @@ # marked alongside existing events. else: - all_events.append((event_coverage, [event])) + all_events.append((event_coverage, [event_page])) return full_coverage, all_events +# Date-related functions. + +class Period: + + "A simple period of time." + + def __init__(self, data): + self.data = data + + def months(self): + return self.data[0] * 12 + self.data[1] + +class Month: + + "A simple year-month representation." + + def __init__(self, data): + self.data = tuple(data) + + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self.data) + + def __str__(self): + return "%04d-%02d" % self.as_tuple()[:2] + + def __hash__(self): + return hash(self.as_tuple()) + + def as_tuple(self): + return self.data + + def as_date(self, day): + return Date(self.as_tuple() + (day,)) + + def year(self): + return self.data[0] + + def month(self): + return self.data[1] + + def month_properties(self): + + """ + Return the weekday of the 1st of the month, along with the number of + days, as a tuple. + """ + + year, month = self.data + return calendar.monthrange(year, month) + + def month_update(self, n=1): + + "Return the month updated by 'n' months." + + year, month = self.data + return Month((year + (month - 1 + n) / 12, (month - 1 + n) % 12 + 1)) + + def next_month(self): + + "Return the month following this one." + + return self.month_update(1) + + def previous_month(self): + + "Return the month preceding this one." + + return self.month_update(-1) + + def __sub__(self, start): + + """ + Return the difference in years and months between this month and the + 'start' month as a period. + """ + + return Period([(x - y) for x, y in zip(self.data, start.data)]) + + def __cmp__(self, other): + return cmp(self.data, other.data) + + def until(self, end, nextfn, prevfn): + month = self + months = [month] + if month < end: + while month < end: + month = nextfn(month) + months.append(month) + elif month > end: + while month > end: + month = prevfn(month) + months.append(month) + return months + + def months_until(self, end): + return self.until(end, Month.next_month, Month.previous_month) + +class Date(Month): + + "A simple year-month-day representation." + + def __str__(self): + return "%04d-%02d-%02d" % self.as_tuple()[:3] + + def as_month(self): + return Month(self.data[:2]) + + def day(self): + return self.data[2] + + def next_day(self): + + "Return the date following this one." + + year, month, day = self.data + _wd, end_day = calendar.monthrange(year, month) + if day == end_day: + if month == 12: + return Date((year + 1, 1, 1)) + else: + return Date((year, month + 1, 1)) + else: + return Date((year, month, day + 1)) + + def previous_day(self): + + "Return the date preceding this one." + + year, month, day = self.data + if day == 1: + if month == 1: + return Date((year - 1, 12, 31)) + else: + _wd, end_day = calendar.monthrange(year, month - 1) + return Date((year, month - 1, end_day)) + else: + return Date((year, month, day - 1)) + + def days_until(self, end): + return self.until(end, Date.next_day, Date.previous_day) + +def getDate(s): + + "Parse the string 's', extracting and returning a date string." + + m = date_regexp.search(s) + if m: + return Date(map(int, m.groups())) + else: + return None + +def getMonth(s): + + "Parse the string 's', extracting and returning a month string." + + m = month_regexp.search(s) + if m: + return Month(map(int, m.groups())) + else: + return None + +def getCurrentMonth(): + + "Return the current month as a (year, month) tuple." + + today = datetime.date.today() + return Month((today.year, today.month)) + +def getCurrentYear(): + + "Return the current year." + + today = datetime.date.today() + return today.year + # User interface functions. def getParameter(request, name, default=None): @@ -704,6 +846,9 @@ return "%s-%s" % (calendar_name, argname) def getParameterMonth(arg): + + "Interpret 'arg', recognising keywords and simple arithmetic operations." + n = None if arg.startswith("current"): @@ -712,12 +857,12 @@ n = int(arg[7:]) elif arg.startswith("yearstart"): - date = (getCurrentYear(), 1) + date = Month((getCurrentYear(), 1)) if len(arg) > 10: n = int(arg[9:]) elif arg.startswith("yearend"): - date = (getCurrentYear(), 12) + date = Month((getCurrentYear(), 12)) if len(arg) > 8: n = int(arg[7:]) @@ -725,11 +870,17 @@ date = getMonth(arg) if n is not None: - date = monthupdate(date, n) + date = date.month_update(n) return date def getFormMonth(request, calendar_name, argname): + + """ + Return the month from the 'request' for the calendar with the given + 'calendar_name' using the parameter having the given 'argname'. + """ + arg = getQualifiedParameter(request, calendar_name, argname) if arg is not None: return getParameterMonth(arg) @@ -737,13 +888,22 @@ return None def getFormMonthPair(request, yeararg, montharg): + + """ + Return the month from the 'request' for the calendar with the given + 'calendar_name' using the parameters having the given 'yeararg' and + 'montharg' names. + """ + year = getParameter(request, yeararg) month = getParameter(request, montharg) if year and month: - return (int(year), int(month)) + return Month((int(year), int(month))) else: return None +# Page-related functions. + def getPrettyPageName(page): "Return a nicely formatted title/name for the given 'page'." @@ -755,24 +915,6 @@ return getPrettyTitle(title) -def getPrettyTitle(title): - - "Return a nicely formatted version of the given 'title'." - - return title.replace("_", " ").replace("/", u" » ") - -def getMonthLabel(month): - - "Return an unlocalised label for the given 'month'." - - return month_labels[month - 1] # zero-based labels - -def getDayLabel(weekday): - - "Return an unlocalised label for the given 'weekday'." - - return weekday_labels[weekday] - def linkToPage(request, page, text, query_string=None): """ @@ -790,13 +932,4 @@ else: return page.link_to_raw(request, text, query_string) -def getPageURL(request, page): - - "Using 'request', return the URL of 'page'." - - if isMoin15(): - return request.getQualifiedURL(page.url(request)) - else: - return request.getQualifiedURL(page.url(request, relative=0)) - # vim: tabstop=4 expandtab shiftwidth=4 diff -r fdf1ec151ab6 -r 0340bf1c9f22 actions/EventAggregatorNewEvent.py --- a/actions/EventAggregatorNewEvent.py Mon Jan 18 01:00:35 2010 +0100 +++ b/actions/EventAggregatorNewEvent.py Sun Jan 24 02:55:53 2010 +0100 @@ -2,7 +2,7 @@ """ MoinMoin - EventAggregatorNewEvent Action - @copyright: 2008, 2009 by Paul Boddie + @copyright: 2008, 2009, 2010 by Paul Boddie @copyright: 2000-2004 Juergen Hermann , 2003-2008 MoinMoin:ThomasWaldmann, 2004-2006 MoinMoin:AlexanderSchremmer, @@ -229,7 +229,7 @@ if not page.exists(): return 0, _("Event template not available.") - body = page.get_raw_body() + event_page = EventAggregatorSupport.EventPage(page) # Use any parent page information. @@ -245,15 +245,18 @@ if new_page.exists(): return 0, _("The specified page already exists. Please choose another name.") - if EventAggregatorSupport.getFormat(page) == "wiki": + new_event_page = EventAggregatorSupport.EventPage(new_page) + new_event_page.copyPage(event_page) + + if new_event_page.getFormat() == "wiki": event_details = { "start" : start_date, "end" : end_date, "title" : title, "summary" : title, "description" : description } - body = EventAggregatorSupport.setEventDetails(body, event_details) - body = EventAggregatorSupport.setCategoryMembership(body, category_pagenames) - new_page.saveText(body, 0) + new_event_page.setEventDetails(event_details) + new_event_page.setCategoryMembership(category_pagenames) + new_event_page.saveChanges() # Redirect and return success. diff -r fdf1ec151ab6 -r 0340bf1c9f22 actions/EventAggregatorSummary.py --- a/actions/EventAggregatorSummary.py Mon Jan 18 01:00:35 2010 +0100 +++ b/actions/EventAggregatorSummary.py Sun Jan 24 02:55:53 2010 +0100 @@ -2,7 +2,7 @@ """ MoinMoin - EventAggregatorSummary Action - @copyright: 2008, 2009 by Paul Boddie + @copyright: 2008, 2009, 2010 by Paul Boddie @copyright: 2000-2004 Juergen Hermann , 2003-2008 MoinMoin:ThomasWaldmann, 2004-2006 MoinMoin:AlexanderSchremmer, @@ -219,12 +219,13 @@ request.write("PRODID:-//MoinMoin//EventAggregatorSummary\r\n") request.write("VERSION:2.0\r\n") - for event_page, event_details in all_shown_events: + for event_page in all_shown_events: + event_details = event_page.getEventDetails() # Get the summary details. - event_summary = EventAggregatorSupport.getEventSummary(event_page, event_details) - link = EventAggregatorSupport.getPageURL(request, event_page) + event_summary = event_page.getEventSummary() + link = event_page.getPageURL(request) # Output the event details. @@ -234,8 +235,8 @@ request.write("DTSTAMP:%04d%02d%02dT%02d%02d%02dZ\r\n" % event_details["created"][:6]) request.write("LAST-MODIFIED:%04d%02d%02dT%02d%02d%02dZ\r\n" % event_details["last-modified"][:6]) request.write("SEQUENCE:%d\r\n" % event_details["sequence"]) - request.write("DTSTART;VALUE=DATE:%04d%02d%02d\r\n" % event_details["start"]) - request.write("DTEND;VALUE=DATE:%04d%02d%02d\r\n" % EventAggregatorSupport.nextdate(event_details["end"])) + request.write("DTSTART;VALUE=DATE:%04d%02d%02d\r\n" % event_details["start"].as_tuple()) + request.write("DTEND;VALUE=DATE:%04d%02d%02d\r\n" % event_details["end"].next_day().as_tuple()) request.write("SUMMARY:%s\r\n" % getQuotedText(event_summary)) # Optional details. @@ -265,21 +266,21 @@ # Sort all_shown_events by start date, reversed: # - # * events are tuples: (real_page_in_category, event_details) # * event_details are dictionaries, with the "start" entry providing # the start date # - # So we use as sorting key the "start" key from the event details (the - # second element of the tuple). + # So we use as sorting key the "start" key from the event details. - all_shown_events.sort(key=lambda x: x[1]["start"], reverse=True) + ordered_events = EventAggregatorSupport.getOrderedEvents(all_shown_events) + ordered_events.reverse() - for event_page, event_details in all_shown_events: + for event_page in ordered_events: + event_details = event_page.getEventDetails() # Get the summary details. - event_summary = EventAggregatorSupport.getEventSummary(event_page, event_details) - link = EventAggregatorSupport.getPageURL(request, event_page) + event_summary = event_page.getEventSummary() + link = event_page.getPageURL(request) request.write('\r\n') request.write('%s\r\n' % wikiutil.escape(event_summary)) diff -r fdf1ec151ab6 -r 0340bf1c9f22 macros/EventAggregator.py --- a/macros/EventAggregator.py Mon Jan 18 01:00:35 2010 +0100 +++ b/macros/EventAggregator.py Sun Jan 24 02:55:53 2010 +0100 @@ -53,18 +53,17 @@ # Store the view parameters. - span = EventAggregatorSupport.span(first, last) - self.number_of_months = span[0] * 12 + span[1] + 1 + self.number_of_months = (last - first).months() + 1 - self.previous_month_start = EventAggregatorSupport.prevmonth(first) - self.next_month_start = EventAggregatorSupport.nextmonth(first) - self.previous_month_end = EventAggregatorSupport.prevmonth(last) - self.next_month_end = EventAggregatorSupport.nextmonth(last) + self.previous_month_start = first.previous_month() + self.next_month_start = first.next_month() + self.previous_month_end = last.previous_month() + self.next_month_end = last.next_month() - self.previous_set_start = EventAggregatorSupport.monthupdate(first, -self.number_of_months) - self.next_set_start = EventAggregatorSupport.monthupdate(first, self.number_of_months) - self.previous_set_end = EventAggregatorSupport.monthupdate(last, -self.number_of_months) - self.next_set_end = EventAggregatorSupport.monthupdate(last, self.number_of_months) + self.previous_set_start = first.month_update(-self.number_of_months) + self.next_set_start = first.month_update(self.number_of_months) + self.previous_set_end = last.month_update(-self.number_of_months) + self.next_set_end = last.month_update(self.number_of_months) def getQualifiedParameterName(self, argname): return EventAggregatorSupport.getQualifiedParameterName(self.calendar_name, argname) @@ -73,7 +72,7 @@ if month is not None: if prefix: argname = self.getQualifiedParameterName(argname) - return "%s=%04d-%02d" % ((argname,) + month) + return "%s=%s" % (argname, month) else: return "" @@ -155,7 +154,7 @@ return "".join(output) - def writeMonthHeading(self, year, month): + def writeMonthHeading(self, year_month): page = self.page request = page.request fmt = page.formatter @@ -163,6 +162,7 @@ output = [] + year, month = year_month.as_tuple() month_label = _(EventAggregatorSupport.getMonthLabel(month)) # Prepare navigation links. @@ -193,11 +193,9 @@ # A link leading to this month being at the top of the calendar. full_month_label = "%s %s" % (month_label, year) - end_month = EventAggregatorSupport.monthupdate((year, month), self.number_of_months - 1) + end_month = year_month.month_update(self.number_of_months - 1) - month_link = self.getNavigationLink( - (year, month), end_month - ) + month_link = self.getNavigationLink(year_month, end_month) output.append(fmt.span(on=1, css_class="previous-month")) output.append(linkToPage(request, page, "<<", previous_set_link)) @@ -224,12 +222,13 @@ return "".join(output) - def writeDayNumberLinked(self, day, month, year): + def writeDayNumberLinked(self, date): page = self.page request = page.request fmt = page.formatter _ = request.getText + year, month, day = date.as_tuple() output = [] # Prepare navigation details for the calendar shown with the new event @@ -411,8 +410,9 @@ # Show the events in order. - for event_page, event_details in ordered_events: - event_summary = EventAggregatorSupport.getEventSummary(event_page, event_details, parent_name) + for event_page in ordered_events: + event_summary = event_page.getEventSummary(parent_name) + event_details = event_page.getEventDetails() # Prepare CSS classes with category-related styling. @@ -432,13 +432,13 @@ output.append(fmt.table_cell(on=1, attrs=attrs)) output.append(fmt.span(on=1)) - output.append(fmt.text("%04d-%02d-%02d" % event_details["start"])) + output.append(fmt.text(str(event_details["start"]))) output.append(fmt.span(on=0)) if event_details["start"] != event_details["end"]: output.append(fmt.text(" - ")) output.append(fmt.span(on=1)) - output.append(fmt.text("%04d-%02d-%02d" % event_details["end"])) + output.append(fmt.text(str(event_details["end"]))) output.append(fmt.span(on=0)) output.append(fmt.table_cell(on=0)) @@ -455,7 +455,7 @@ # Link to the page using the summary. output.append(fmt.table_cell(on=1, attrs=attrs)) - output.append(linkToPage(request, event_page, event_summary)) + output.append(event_page.linkToPage(request, event_summary)) output.append(fmt.table_cell(on=0)) output.append(fmt.table_row(on=0)) @@ -477,7 +477,7 @@ # Visit all months in the requested range, or across known events. - for year, month in EventAggregatorSupport.daterange(first, last): + for month in first.months_until(last): # Either output a calendar view... @@ -493,7 +493,7 @@ # Either write a month heading or produce links for navigable # calendars. - output.append(view.writeMonthHeading(year, month)) + output.append(view.writeMonthHeading(month)) output.append(fmt.table_cell(on=0)) output.append(fmt.table_row(on=0)) @@ -511,7 +511,7 @@ # Process the days of the month. - start_weekday, number_of_days = calendar.monthrange(year, month) + start_weekday, number_of_days = month.month_properties() # The start weekday is the weekday of day number 1. # Find the first day of the week, counting from below zero, if @@ -525,11 +525,11 @@ # Find events in this week and determine how to mark them on the # calendar. - week_start = (year, month, max(first_day, 1)) - week_end = (year, month, min(first_day + 6, number_of_days)) + week_start = month.as_date(max(first_day, 1)) + week_end = month.as_date(min(first_day + 6, number_of_days)) week_coverage, week_events = EventAggregatorSupport.getCoverage( - week_start, week_end, shown_events.get((year, month), [])) + week_start, week_end, shown_events.get(month, [])) # Output a week, starting with the day numbers. @@ -537,7 +537,7 @@ for weekday in range(0, 7): day = first_day + weekday - date = (year, month, day) + date = month.as_date(day) # Output out-of-month days. @@ -559,7 +559,7 @@ # Output the day number, making a link to a new event # action. - output.append(view.writeDayNumberLinked(day, month, year)) + output.append(view.writeDayNumberLinked(date)) # End of day. @@ -576,7 +576,6 @@ for weekday in range(0, 7): day = first_day + weekday - date = (year, month, day) # Output out-of-month days. @@ -606,7 +605,7 @@ for weekday in range(0, 7): day = first_day + weekday - date = (year, month, day) + date = month.as_date(day) # Skip out-of-month days. @@ -624,7 +623,9 @@ # Get event details for the current day. - for event_page, event_details in events: + for event_page in events: + event_details = event_page.getEventDetails() + if not (event_details["start"] <= date <= event_details["end"]): continue @@ -632,7 +633,7 @@ starts_today = event_details["start"] == date ends_today = event_details["end"] == date - event_summary = EventAggregatorSupport.getEventSummary(event_page, event_details, parent_name) + event_summary = event_page.getEventSummary(parent_name) # Generate a colour for the event. @@ -678,10 +679,10 @@ else: if event_details["end"] <= week_end: - event_length = event_details["end"][2] - day + 1 + event_length = event_details["end"].day() - day + 1 colspan = (event_length - 2) * 3 + 4 else: - event_length = week_end[2] - day + 1 + event_length = week_end.day() - day + 1 colspan = (event_length - 1) * 3 + 2 event_day_type = "event-day-multiple" @@ -711,10 +712,10 @@ else: if event_details["end"] <= week_end: - event_length = event_details["end"][2] - day + 1 + event_length = event_details["end"].day() - day + 1 colspan = (event_length - 1) * 3 + 2 else: - event_length = week_end[2] - day + 1 + event_length = week_end.day() - day + 1 colspan = event_length * 3 event_day_type = "event-day-multiple" @@ -757,13 +758,13 @@ output.append(fmt.div(on=1, css_class="event-summary-box")) output.append(fmt.div(on=1, css_class="event-summary", style=style)) - output.append(linkToPage(request, event_page, event_summary)) + output.append(event_page.linkToPage(request, event_summary)) output.append(fmt.div(on=0)) # Add a pop-up element for long summaries. output.append(fmt.div(on=1, css_class="event-summary-popup", style=style)) - output.append(linkToPage(request, event_page, event_summary)) + output.append(event_page.linkToPage(request, event_summary)) output.append(fmt.div(on=0)) output.append(fmt.div(on=0)) @@ -824,7 +825,7 @@ # Either write a month heading or produce links for navigable # calendars. - output.append(view.writeMonthHeading(year, month)) + output.append(view.writeMonthHeading(month)) output.append(fmt.div(on=0)) @@ -832,30 +833,31 @@ # Get the events in order. - ordered_events = EventAggregatorSupport.getOrderedEvents(shown_events.get((year, month), [])) + ordered_events = EventAggregatorSupport.getOrderedEvents(shown_events.get(month, [])) # Show the events in order. - for event_page, event_details in ordered_events: - event_summary = EventAggregatorSupport.getEventSummary(event_page, event_details, parent_name) + for event_page in ordered_events: + event_details = event_page.getEventDetails() + event_summary = event_page.getEventSummary(parent_name) output.append(fmt.listitem(on=1, attr={"class" : "event-listing"})) # Link to the page using the summary. output.append(fmt.paragraph(on=1)) - output.append(linkToPage(request, event_page, event_summary)) + output.append(event_page.linkToPage(request, event_summary)) output.append(fmt.paragraph(on=0)) # Start and end dates. output.append(fmt.paragraph(on=1)) output.append(fmt.span(on=1)) - output.append(fmt.text("%04d-%02d-%02d" % event_details["start"])) + output.append(fmt.text(str(event_details["start"]))) output.append(fmt.span(on=0)) output.append(fmt.text(" - ")) output.append(fmt.span(on=1)) - output.append(fmt.text("%04d-%02d-%02d" % event_details["end"])) + output.append(fmt.text(str(event_details["end"]))) output.append(fmt.span(on=0)) output.append(fmt.paragraph(on=0))