1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - EventAggregator library 4 5 @copyright: 2008, 2009 by Paul Boddie <paul@boddie.org.uk> 6 @copyright: 2000-2004 Juergen Hermann <jh@web.de>, 7 2005-2008 MoinMoin:ThomasWaldmann. 8 @license: GNU GPL (v2 or later), see COPYING.txt for details. 9 """ 10 11 from MoinMoin.Page import Page 12 from MoinMoin import search, version 13 import calendar 14 import re 15 16 __version__ = "0.1" 17 18 # Regular expressions where MoinMoin does not provide the required support. 19 20 category_regexp = None 21 definition_list_regexp = re.compile(ur'^\s+(?P<term>.*?)::\s(?P<desc>.*?)$', re.UNICODE | re.MULTILINE) 22 date_regexp = re.compile(ur'(?P<year>[0-9]{4})-(?P<month>[0-9]{2})-(?P<day>[0-9]{2})', re.UNICODE) 23 month_regexp = re.compile(ur'(?P<year>[0-9]{4})-(?P<month>[0-9]{2})', re.UNICODE) 24 25 # Utility functions. 26 27 def isMoin15(): 28 return version.release.startswith("1.5.") 29 30 def getCategoryPattern(request): 31 global category_regexp 32 33 try: 34 return request.cfg.cache.page_category_regexact 35 except AttributeError: 36 37 # Use regular expression from MoinMoin 1.7.1 otherwise. 38 39 if category_regexp is None: 40 category_regexp = re.compile(u'^%s$' % ur'(?P<all>Category(?P<key>(?!Template)\S+))', re.UNICODE) 41 return category_regexp 42 43 # The main activity functions. 44 45 def getPages(pagename, request): 46 47 "Return the links minus category links for 'pagename' using the 'request'." 48 49 query = search.QueryParser().parse_query('category:%s' % pagename) 50 if isMoin15(): 51 results = search.searchPages(request, query) 52 results.sortByPagename() 53 else: 54 results = search.searchPages(request, query, "page_name") 55 56 cat_pattern = getCategoryPattern(request) 57 pages = [] 58 for page in results.hits: 59 if not cat_pattern.match(page.page_name): 60 pages.append(page) 61 return pages 62 63 def getPrettyPageName(page): 64 65 "Return a nicely formatted title/name for the given 'page'." 66 67 return page.split_title(force=1).replace("_", " ").replace("/", u" ? ") 68 69 def getEventDetails(page): 70 71 "Return a dictionary of event details from the given 'page'." 72 73 event_details = {} 74 75 if page.pi["format"] == "wiki": 76 for match in definition_list_regexp.finditer(page.body): 77 78 # Permit case-insensitive list terms. 79 80 term = match.group("term").lower() 81 desc = match.group("desc") 82 83 # Special value type handling. 84 85 if term in ("start", "end"): 86 desc = getDate(desc) 87 elif term in ("topics",): 88 desc = [value.strip() for value in desc.split(",")] 89 90 if desc is not None: 91 event_details[term] = desc 92 93 return event_details 94 95 def getDate(s): 96 97 "Parse the string 's', extracting and returning a date string." 98 99 m = date_regexp.search(s) 100 if m: 101 return tuple(map(int, m.groups())) 102 else: 103 return None 104 105 def getMonth(s): 106 107 "Parse the string 's', extracting and returning a month string." 108 109 m = month_regexp.search(s) 110 if m: 111 return tuple(map(int, m.groups())) 112 else: 113 return None 114 115 def daterange(first, last): 116 results = [] 117 118 months_only = len(first) == 2 119 start_year = first[0] 120 end_year = last[0] 121 122 for year in range(start_year, end_year + 1): 123 if year < end_year: 124 end_month = 12 125 else: 126 end_month = last[1] 127 128 if year > start_year: 129 start_month = 1 130 else: 131 start_month = first[1] 132 133 for month in range(start_month, end_month + 1): 134 if months_only: 135 results.append((year, month)) 136 else: 137 if month < end_month: 138 _wd, end_day = calendar.monthrange(year, month) 139 else: 140 end_day = last[2] 141 142 if month > start_month: 143 start_day = 1 144 else: 145 start_day = first[2] 146 147 for day in range(start_day, end_day + 1): 148 results.append((year, month, day)) 149 150 return results 151 152 def nextdate(date): 153 year, month, day = date 154 _wd, end_day = calendar.monthrange(year, month) 155 if day == end_day: 156 if month == 12: 157 return (year + 1, 1, 1) 158 else: 159 return (year, month + 1, 1) 160 else: 161 return (year, month, day + 1) 162 163 def getEvents(request, category_names, calendar_start=None, calendar_end=None): 164 165 """ 166 Using the 'request', generate a list of events found on pages belonging to 167 the specified 'category_names', using the optional 'calendar_start' and 168 'calendar_end' month tuples of the form (year, month) to indicate a window 169 of interest. 170 171 Return a list of events, a dictionary mapping months to event lists (within 172 the window of interest), a list of all events within the window of interest, 173 the earliest month of an event within the window of interest, and the latest 174 month of an event within the window of interest. 175 """ 176 177 events = [] 178 shown_events = {} 179 all_shown_events = [] 180 181 earliest = None 182 latest = None 183 184 for category_name in category_names: 185 186 # Get the pages and page names in the category. 187 188 pages_in_category = getPages(category_name, request) 189 190 # Visit each page in the category. 191 192 for page_in_category in pages_in_category: 193 pagename = page_in_category.page_name 194 195 # Get a real page, not a result page. 196 197 real_page_in_category = Page(request, pagename) 198 event_details = getEventDetails(real_page_in_category) 199 200 # Define the event as the page together with its details. 201 202 event = (real_page_in_category, event_details) 203 events.append(event) 204 205 # Test for the suitability of the event. 206 207 if event_details.has_key("start") and event_details.has_key("end"): 208 209 start_month = event_details["start"][:2] 210 end_month = event_details["end"][:2] 211 212 # Compare the months of the dates to the requested calendar 213 # window, if any. 214 215 if (calendar_start is None or end_month >= calendar_start) and \ 216 (calendar_end is None or start_month <= calendar_end): 217 218 all_shown_events.append(event) 219 220 if earliest is None or start_month < earliest: 221 earliest = start_month 222 if latest is None or end_month > latest: 223 latest = end_month 224 225 # Store the event in the month-specific dictionary. 226 227 first = max(start_month, calendar_start or start_month) 228 last = min(end_month, calendar_end or end_month) 229 230 for event_month in daterange(first, last): 231 if not shown_events.has_key(event_month): 232 shown_events[event_month] = [] 233 shown_events[event_month].append(event) 234 235 return events, shown_events, all_shown_events, earliest, latest 236 237 # vim: tabstop=4 expandtab shiftwidth=4