1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - EventAggregatorSummary Action 4 5 @copyright: 2008, 2009 by Paul Boddie <paul@boddie.org.uk> 6 @copyright: 2000-2004 Juergen Hermann <jh@web.de>, 7 2003-2008 MoinMoin:ThomasWaldmann, 8 2004-2006 MoinMoin:AlexanderSchremmer, 9 2007 MoinMoin:ReimarBauer. 10 @license: GNU GPL (v2 or later), see COPYING.txt for details. 11 """ 12 13 from MoinMoin.action import ActionBase 14 from MoinMoin import config 15 from MoinMoin.Page import Page 16 import MoinMoin.util # for MoinMoin 1.5.x 17 from MoinMoin import wikiutil 18 import EventAggregatorSupport 19 20 Dependencies = ['pages'] 21 22 # Action class and supporting functions. 23 24 class EventAggregatorSummary(ActionBase): 25 26 "A summary dialogue requesting various parameters." 27 28 def get_form_html(self, buttons_html): 29 _ = self._ 30 request = self.request 31 32 category_list = [] 33 34 for category_name, category_pagename in \ 35 EventAggregatorSupport.getCategoryMapping( 36 EventAggregatorSupport.getCategories(request), 37 request): 38 39 category_list.append('<option value="%s">%s</option>' % (category_pagename, category_name)) 40 41 month_list = [] 42 month_list.append('<option value=""></option>') 43 44 for month in range(1, 13): 45 month_label = _(EventAggregatorSupport.getMonthLabel(month)) 46 month_list.append('<option value="%02d">%s</option>' % (month, month_label)) 47 48 descriptions_list = [ 49 '<option value="%s">%s</option>' % ("page", _("page")), 50 '<option value="%s">%s</option>' % ("comment", _("comment")) 51 ] 52 53 format_list = [ 54 '<option value="%s">%s</option>' % ("iCalendar", _("iCalendar")), 55 '<option value="%s">%s</option>' % ("RSS", _("RSS 2.0")) 56 ] 57 58 d = { 59 "buttons_html" : buttons_html, 60 "category_label" : _("Categories"), 61 "category_list" : "\n".join(category_list), 62 "month_list" : "\n".join(month_list), 63 "start_label" : _("Start year and month"), 64 "start_year_default" : "", 65 "end_label" : _("End year and month"), 66 "end_year_default" : "", 67 "descriptions_label" : _("Use descriptions from..."), 68 "descriptions_list" : "\n".join(descriptions_list), 69 "format_label" : _("Summary format"), 70 "format_list" : "\n".join(format_list), 71 } 72 73 return ''' 74 <table> 75 <tr> 76 <td class="label"><label>%(category_label)s</label></td> 77 <td class="content"> 78 <select multiple="multiple" name="category"> 79 %(category_list)s 80 </select> 81 </td> 82 </tr> 83 <tr> 84 <td class="label"><label>%(start_label)s</label></td> 85 <td> 86 <select name="start-month"> 87 %(month_list)s 88 </select> 89 <input name="start-year" type="text" value="%(start_year_default)s" size="4" /> 90 </td> 91 </tr> 92 <tr> 93 <td class="label"><label>%(end_label)s</label></td> 94 <td> 95 <select name="end-month"> 96 %(month_list)s 97 </select> 98 <input name="end-year" type="text" value="%(end_year_default)s" size="4" /> 99 </td> 100 </tr> 101 <tr> 102 <td class="label"><label>%(descriptions_label)s</label></td> 103 <td class="content"> 104 <select name="descriptions"> 105 %(descriptions_list)s 106 </select> 107 </td> 108 </tr> 109 <tr> 110 <td class="label"><label>%(format_label)s</label></td> 111 <td class="content"> 112 <select name="format"> 113 %(format_list)s 114 </select> 115 </td> 116 </tr> 117 <tr> 118 <td></td> 119 <td class="buttons"> 120 %(buttons_html)s 121 </td> 122 </tr> 123 </table> 124 ''' % d 125 126 def do_action(self): 127 128 "Write the iCalendar resource." 129 130 _ = self._ 131 form = self.request.form 132 133 # If no category names exist in the request, an error message is 134 # returned. 135 136 category_names = form.get("category", []) 137 138 if not category_names: 139 return 0, _("No categories specified.") 140 141 write_resource(self.request) 142 return 1, None 143 144 def render_success(self, msg, msgtype=None): 145 146 """ 147 Render neither 'msg' nor 'msgtype' since a resource has already been 148 produced. 149 NOTE: msgtype is optional because MoinMoin 1.5.x does not support it. 150 """ 151 152 pass 153 154 def getQuotedText(text): 155 156 "Return the 'text' quoted for iCalendar purposes." 157 158 return text.replace(";", r"\;").replace(",", r"\,") 159 160 def write_resource(request): 161 162 """ 163 For the given 'request', write an iCalendar summary of the event data found 164 in the categories specified via the "category" request parameter, using the 165 "start" and "end" parameters (if specified). Multiple "category" parameters 166 can be specified. 167 """ 168 169 form = request.form 170 171 category_names = form.get("category", []) 172 format = form.get("format", ["iCalendar"])[0] 173 descriptions = form.get("descriptions", ["page"])[0] 174 175 # Otherwise, produce an iCalendar resource. 176 177 calendar_start = EventAggregatorSupport.getFormMonth(request, None, "start") 178 calendar_end = EventAggregatorSupport.getFormMonth(request, None, "end") 179 180 # Look for separate start and end years and months. 181 182 if calendar_start is None: 183 calendar_start = EventAggregatorSupport.getFormMonthPair(request, "start-year", "start-month") 184 185 if calendar_end is None: 186 calendar_end = EventAggregatorSupport.getFormMonthPair(request, "end-year", "end-month") 187 188 events, shown_events, all_shown_events, earliest, latest = \ 189 EventAggregatorSupport.getEvents(request, category_names, calendar_start, calendar_end) 190 191 latest_timestamp = EventAggregatorSupport.setEventTimestamps(request, all_shown_events) 192 193 # Output summary data... 194 195 if EventAggregatorSupport.isMoin15(): 196 send_headers = request.http_headers 197 else: 198 send_headers = request.emit_http_headers 199 200 # Define headers. 201 202 if format == "iCalendar": 203 headers = ["Content-Type: text/calendar; charset=%s" % config.charset] 204 elif format == "RSS": 205 headers = ["Content-Type: application/rss+xml; charset=%s" % config.charset] 206 207 # Define the last modified time. 208 209 if latest_timestamp is not None: 210 headers.append("Last-Modified: %s" % EventAggregatorSupport.getHTTPTimeString(latest_timestamp)) 211 212 send_headers(headers) 213 214 # iCalendar output... 215 216 if format == "iCalendar": 217 request.write("BEGIN:VCALENDAR\r\n") 218 request.write("PRODID:-//MoinMoin//EventAggregatorSummary\r\n") 219 request.write("VERSION:2.0\r\n") 220 221 for event_page, event_details in all_shown_events: 222 223 # Get the summary details. 224 225 event_summary = EventAggregatorSupport.getEventSummary(event_page, event_details) 226 link = EventAggregatorSupport.getPageURL(request, event_page) 227 228 # Output the event details. 229 230 request.write("BEGIN:VEVENT\r\n") 231 request.write("UID:%s\r\n" % link) 232 request.write("URL:%s\r\n" % link) 233 request.write("DTSTAMP:%04d%02d%02dT%02d%02d%02dZ\r\n" % event_details["created"][:6]) 234 request.write("LAST-MODIFIED:%04d%02d%02dT%02d%02d%02dZ\r\n" % event_details["last-modified"][:6]) 235 request.write("SEQUENCE:%d\r\n" % event_details["sequence"]) 236 request.write("DTSTART;VALUE=DATE:%04d%02d%02d\r\n" % event_details["start"]) 237 request.write("DTEND;VALUE=DATE:%04d%02d%02d\r\n" % EventAggregatorSupport.nextdate(event_details["end"])) 238 request.write("SUMMARY:%s\r\n" % getQuotedText(event_summary)) 239 240 # Optional details. 241 242 if event_details.has_key("topics") or event_details.has_key("categories"): 243 request.write("CATEGORIES:%s\r\n" % ",".join( 244 [getQuotedText(topic) for topic in event_details.get("topics") or event_details.get("categories")] 245 )) 246 if event_details.has_key("location"): 247 request.write("LOCATION:%s\r\n" % getQuotedText(event_details["location"])) 248 249 request.write("END:VEVENT\r\n") 250 251 request.write("END:VCALENDAR\r\n") 252 253 elif format == "RSS": 254 request.write('<rss version="2.0">\r\n') 255 request.write('<channel>\r\n') 256 request.write('<title>Events</title>\r\n') 257 request.write('<link>%s</link>\r\n' % request.getBaseURL()) 258 request.write('<description>Events published on %s</description>\r\n' % request.getBaseURL()) 259 request.write('<lastBuildDate>%s</lastBuildDate>\r\n' % EventAggregatorSupport.getHTTPTimeString(latest_timestamp)) 260 261 for event_page, event_details in all_shown_events: 262 263 # Get the summary details. 264 265 event_summary = EventAggregatorSupport.getEventSummary(event_page, event_details) 266 link = EventAggregatorSupport.getPageURL(request, event_page) 267 268 request.write('<item>\r\n') 269 request.write('<title>%s</title>\r\n' % wikiutil.escape(event_summary)) 270 request.write('<link>%s</link>\r\n' % link) 271 272 # Write a description according to the preferred source of 273 # descriptions. 274 275 if descriptions == "page": 276 description = event_details.get("description", "") 277 else: 278 description = event_details["last-comment"] 279 280 request.write('<description>%s</description>\r\n' % wikiutil.escape(description)) 281 282 for topic in event_details.get("topics") or event_details.get("categories") or []: 283 request.write('<category>%s</category>\r\n' % topic) 284 285 request.write('<pubDate>%s</pubDate>\r\n' % EventAggregatorSupport.getHTTPTimeString(event_details["created"])) 286 request.write('<guid>%s#%s</guid>\r\n' % (link, event_details["sequence"])) 287 request.write('</item>\r\n') 288 289 request.write('</channel>\r\n') 290 request.write('</rss>\r\n') 291 292 if EventAggregatorSupport.isMoin15(): 293 raise MoinMoin.util.MoinMoinNoFooter 294 295 # Action function. 296 297 def execute(pagename, request): 298 EventAggregatorSummary(pagename, request).render() 299 300 # vim: tabstop=4 expandtab shiftwidth=4