1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - EventAggregatorNewEvent Action 4 5 @copyright: 2008, 2009, 2010 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.Page import Page 15 from MoinMoin.PageEditor import PageEditor 16 import EventAggregatorSupport 17 18 try: 19 import pytz 20 except ImportError: 21 pytz = None 22 23 Dependencies = ['pages'] 24 25 # Action class and supporting functions. 26 27 class EventAggregatorNewEvent(ActionBase, EventAggregatorSupport.ActionSupport): 28 29 "An event creation dialogue requesting various parameters." 30 31 def get_form_html(self, buttons_html): 32 _ = self._ 33 request = self.request 34 form = self.get_form() 35 36 # Handle advanced and basic forms, and enable/disable certain fields. 37 38 show_advanced = form.get("advanced") and not form.get("basic") 39 show_end_date = form.get("end-day") and not form.get("hide-end-date") or form.get("show-end-date") 40 show_times = (form.get("start-hour") or form.get("end-hour")) and not form.get("hide-times") or form.get("show-times") 41 42 show_zone_regime = form.get("regime") and not form.get("show-offsets") and \ 43 not form.get("hide-zone") or form.get("show-regime") 44 show_zone_offsets = form.get("start-offset") and not form.get("show-regime") and \ 45 not form.get("hide-zone") or form.get("show-offsets") 46 47 show_zones = show_zone_regime or show_zone_offsets 48 49 # Prepare the category list. 50 51 category_list = [] 52 category_pagenames = form.get("category", []) 53 54 for category_name, category_pagename in \ 55 EventAggregatorSupport.getCategoryMapping( 56 EventAggregatorSupport.getCategories(request), 57 request): 58 59 selected = self._get_selected_for_list(category_pagename, category_pagenames) 60 61 # In the advanced view, populate a menu. 62 63 if show_advanced: 64 category_list.append('<option value="%s" %s>%s</option>' % (category_pagename, selected, category_name)) 65 66 # In the basic view, use hidden fields. 67 68 elif selected: 69 category_list.append('<input value="%s" name="category" type="hidden" />' % category_pagename) 70 71 # Prepare the topics list. 72 73 topics = form.get("topics", []) 74 75 if form.get("add-topic"): 76 topics.append("") 77 else: 78 for i in range(0, len(topics)): 79 if form.get("remove-topic-%d" % i): 80 del topics[i] 81 break 82 83 # Initialise month lists. 84 85 start_month_list, end_month_list = self.get_month_lists(default_as_current=1) 86 start_year_default, end_year_default = self.get_year_defaults(default_as_current=1) 87 88 # Initialise regime lists. 89 90 regime_list = [] 91 regime_list.append('<option value=""></option>') 92 93 regime = form.get("regime", [None])[0] 94 95 # Prepare regime lists, selecting specified regimes. 96 97 if pytz is not None: 98 for pytz_regime in pytz.common_timezones: 99 selected = self._get_selected(pytz_regime, regime) 100 regime_list.append('<option value="%s" %s>%s</option>' % (pytz_regime, selected, pytz_regime)) 101 102 # Permitting configuration of the template name. 103 104 template_default = getattr(request.cfg, "event_aggregator_new_event_template", "EventTemplate") 105 106 d = { 107 "buttons_html" : buttons_html, 108 "category_label" : _("Categories"), 109 "category_list" : "\n".join(category_list), 110 111 "start_month_list" : "\n".join(start_month_list), 112 "end_month_list" : "\n".join(end_month_list), 113 114 "regime_list" : "\n".join(regime_list), 115 "use_regime_label" : _("Using local time"), 116 117 "show_end_date_label" : _("Specify end date"), 118 "hide_end_date_label" : _("End event on same day"), 119 120 "show_times_label" : _("Specify times"), 121 "hide_times_label" : _("No start and end times"), 122 123 "show_offsets_label" : _("Specify UTC offsets"), 124 "show_regime_label" : _("Specify location"), 125 "hide_zone_label" : _("Make times apply everywhere"), 126 127 "start_label" : _("Start date (day, month, year)"), 128 "start_day_default" : form.get("start-day", [""])[0], 129 "start_year_default" : start_year_default, 130 "start_time_label" : _("Start time (hour, minute, second)"), 131 "start_hour_default" : form.get("start-hour", [""])[0], 132 "start_minute_default" : form.get("start-minute", [""])[0], 133 "start_second_default" : form.get("start-second", [""])[0], 134 "start_offset_default" : form.get("start-offset", [""])[0], 135 136 "end_label" : _("End date (day, month, year) - if different"), 137 "end_day_default" : form.get("end-day", [""])[0] or form.get("start-day", [""])[0], 138 "end_year_default" : end_year_default, 139 "end_time_label" : _("End time (hour, minute, second)"), 140 "end_hour_default" : form.get("end-hour", [""])[0], 141 "end_minute_default" : form.get("end-minute", [""])[0], 142 "end_second_default" : form.get("end-second", [""])[0], 143 "end_offset_default" : form.get("end-offset", [""])[0] or form.get("start-offset", [""])[0], 144 145 "title_label" : _("Event title/summary"), 146 "title_default" : form.get("title", [""])[0], 147 "description_label" : _("Event description"), 148 "description_default" : form.get("description", [""])[0], 149 "location_label" : _("Event location"), 150 "location_default" : form.get("location", [""])[0], 151 "link_label" : _("Event URL"), 152 "link_default" : form.get("link", [""])[0], 153 154 "topics_label" : _("Topics"), 155 "add_topic_label" : _("Add topic"), 156 "remove_topic_label" : _("Remove topic"), 157 158 "template_label" : _("Event template"), 159 "template_default" : form.get("template", [""])[0] or template_default, 160 "parent_label" : _("Parent page"), 161 "parent_default" : form.get("parent", [""])[0], 162 163 "advanced_label" : _("Show advanced options"), 164 "basic_label" : _("Hide advanced options"), 165 } 166 167 # Prepare the output HTML. 168 169 html = ''' 170 <table> 171 <tr> 172 <td class="label"><label>%(title_label)s</label></td> 173 <td colspan="2"> 174 <input name="title" type="text" size="40" value="%(title_default)s" /> 175 </td> 176 </tr> 177 <tr> 178 <td class="label"><label>%(start_label)s</label></td> 179 <td colspan="2" style="white-space: nowrap"> 180 <input name="start-day" type="text" value="%(start_day_default)s" size="2" /> 181 <select name="start-month"> 182 %(start_month_list)s 183 </select> 184 <input name="start-year" type="text" value="%(start_year_default)s" size="4" /> 185 </td> 186 </tr>''' % d 187 188 # End date controls. 189 190 if show_end_date: 191 html += ''' 192 <tr> 193 <td class="label"><label>%(end_label)s</label></td> 194 <td colspan="2" style="white-space: nowrap"> 195 <input name="end-day" type="text" value="%(end_day_default)s" size="2" /> 196 <select name="end-month"> 197 %(end_month_list)s 198 </select> 199 <input name="end-year" type="text" value="%(end_year_default)s" size="4" /> 200 </td> 201 </tr> 202 <tr> 203 <td class="label"> 204 <input name="hide-end-date" type="submit" value="%(hide_end_date_label)s" /> 205 </td> 206 </tr>''' % d 207 else: 208 html += ''' 209 <tr> 210 <td class="label"> 211 <input name="show-end-date" type="submit" value="%(show_end_date_label)s" /> 212 </td> 213 </tr>''' % d 214 215 # Generic time information. 216 217 if show_times: 218 219 # Start time controls. 220 221 html += ''' 222 <tr> 223 <td class="label"><label>%(start_time_label)s</label></td> 224 <td style="white-space: nowrap"> 225 <input name="start-hour" type="text" value="%(start_hour_default)s" size="2" maxlength="2" /> 226 <input name="start-minute" type="text" value="%(start_minute_default)s" size="2" maxlength="2" /> 227 <input name="start-second" type="text" value="%(start_second_default)s" size="2" maxlength="2" /> 228 </td>''' % d 229 230 # Offset information displayed. 231 232 if show_zone_offsets: 233 html += ''' 234 <td> 235 UTC <input name="start-offset" type="text" value="%(start_offset_default)s" size="6" maxlength="6" /> 236 </td>''' % d 237 238 # Regime information displayed. 239 240 elif show_zone_regime: 241 html += ''' 242 <td> 243 %(use_regime_label)s 244 </td>''' % d 245 246 html += ''' 247 </tr>''' 248 249 # End time controls. 250 251 html += ''' 252 <tr> 253 <td class="label"><label>%(end_time_label)s</label></td> 254 <td style="white-space: nowrap"> 255 <input name="end-hour" type="text" value="%(end_hour_default)s" size="2" maxlength="2" /> 256 <input name="end-minute" type="text" value="%(end_minute_default)s" size="2" maxlength="2" /> 257 <input name="end-second" type="text" value="%(end_second_default)s" size="2" maxlength="2" /> 258 </td>''' % d 259 260 # Offset information displayed. 261 262 if show_zone_offsets: 263 html += ''' 264 <td> 265 UTC <input name="end-offset" type="text" value="%(end_offset_default)s" size="6" maxlength="6" /> 266 </td>''' % d 267 268 # Regime information displayed. 269 270 elif show_zone_regime: 271 html += ''' 272 <td> 273 <select name="regime"> 274 %(regime_list)s 275 </select> 276 </td>''' % d 277 278 # Controls for removing times. 279 280 html += ''' 281 </tr> 282 <tr> 283 <td class="label"> 284 <input name="hide-times" type="submit" value="%(hide_times_label)s" /> 285 </td> 286 <td></td>''' % d 287 288 # Time zone controls. 289 290 if show_zones: 291 292 # Offset information displayed. 293 294 if show_zone_offsets: 295 html += ''' 296 <td> 297 <input name="show-regime" type="submit" value="%(show_regime_label)s" />''' % d 298 299 # Regime information displayed. 300 301 elif show_zone_regime: 302 html += ''' 303 <td> 304 <input name="show-offsets" type="submit" value="%(show_offsets_label)s" />''' % d 305 306 # To remove zone information. 307 308 html += ''' 309 <input name="hide-zone" type="submit" value="%(hide_zone_label)s" /> 310 </td>''' % d 311 312 # No time zone information shown. 313 314 else: 315 html += ''' 316 <td> 317 <input name="show-regime" type="submit" value="%(show_regime_label)s" /> 318 <input name="show-offsets" type="submit" value="%(show_offsets_label)s" /> 319 </td>''' % d 320 321 html += ''' 322 </tr>''' 323 324 # Controls for adding times. 325 326 else: 327 html += ''' 328 <tr> 329 <td class="label"> 330 <input name="show-times" type="submit" value="%(show_times_label)s" /> 331 </td> 332 </tr>''' % d 333 334 335 # Various basic controls. 336 337 html += ''' 338 <tr> 339 <td class="label"><label>%(description_label)s</label></td> 340 <td colspan="2"> 341 <input name="description" type="text" size="40" value="%(description_default)s" /> 342 </td> 343 </tr> 344 <tr> 345 <td class="label"><label>%(location_label)s</label></td> 346 <td colspan="2"> 347 <input name="location" type="text" size="40" value="%(location_default)s" /> 348 </td> 349 </tr> 350 <tr> 351 <td class="label"><label>%(link_label)s</label></td> 352 <td colspan="2"> 353 <input name="link" type="text" size="40" value="%(link_default)s" /> 354 </td> 355 </tr>''' % d 356 357 # Topics. 358 359 for i, topic in enumerate(topics): 360 d["topic"] = topic 361 d["topic_number"] = i 362 html += ''' 363 <tr> 364 <td class="label"><label>%(topics_label)s</label></td> 365 <td colspan="2"> 366 <input name="topics" type="text" size="20" value="%(topic)s" /> 367 <input name="remove-topic-%(topic_number)s" type="submit" value="%(remove_topic_label)s" /> 368 </td> 369 </tr>''' % d 370 371 html += ''' 372 <tr> 373 <td></td> 374 <td colspan="2"> 375 <input name="add-topic" type="submit" value="%(add_topic_label)s" /> 376 </td> 377 </tr>''' % d 378 379 # Advanced options. 380 381 if show_advanced: 382 html += ''' 383 <tr> 384 <td></td> 385 <td colspan="2"> 386 <input name="basic" type="submit" value="%(basic_label)s" /> 387 <input name="advanced" type="hidden" value="true" /> 388 </td> 389 </tr> 390 <tr> 391 <td class="label"><label>%(category_label)s</label></td> 392 <td colspan="2" class="content"> 393 <select multiple="multiple" name="category"> 394 %(category_list)s 395 </select> 396 </td> 397 </tr> 398 <tr> 399 <td class="label"><label>%(template_label)s</label></td> 400 <td colspan="2"> 401 <input name="template" type="text" size="40" value="%(template_default)s" /> 402 </td> 403 </tr> 404 <tr> 405 <td class="label"><label>%(parent_label)s</label></td> 406 <td colspan="2"> 407 <input name="parent" type="text" size="40" value="%(parent_default)s" /> 408 </td> 409 </tr> 410 <tr> 411 <td></td> 412 <td colspan="2" class="buttons"> 413 %(buttons_html)s 414 </td> 415 </tr> 416 </table>''' % d 417 else: 418 html += ''' 419 <tr> 420 <td></td> 421 <td colspan="2"> 422 <input name="advanced" type="submit" value="%(advanced_label)s" /> 423 %(category_list)s 424 <input name="parent" type="hidden" value="%(parent_default)s" /> 425 <input name="template" type="hidden" value="%(template_default)s" /> 426 </td> 427 </tr> 428 <tr> 429 <td></td> 430 <td colspan="2" class="buttons"> 431 %(buttons_html)s 432 </td> 433 </tr> 434 </table>''' % d 435 436 return html 437 438 def do_action(self): 439 440 "Create the new event." 441 442 _ = self._ 443 form = self.get_form() 444 445 # If no title exists in the request, an error message is returned. 446 447 title = form.get("title", [None])[0] 448 template = form.get("template", [None])[0] 449 450 if not title: 451 return 0, _("No event title specified.") 452 453 if not template: 454 return 0, _("No page template specified.") 455 456 return self.create_event(self.request) 457 458 def render_success(self, msg, msgtype=None): 459 460 """ 461 Render neither 'msg' nor 'msgtype' since redirection should occur 462 instead. 463 NOTE: msgtype is optional because MoinMoin 1.5.x does not support it. 464 """ 465 466 pass 467 468 def create_event(self, request): 469 470 "Create an event page using the 'request'." 471 472 _ = request.getText 473 form = self.get_form() 474 475 category_pagenames = form.get("category", []) 476 description = form.get("description", [None])[0] 477 location = form.get("location", [None])[0] 478 link = form.get("link", [None])[0] 479 topics = form.get("topics", []) 480 481 regime = form.get("regime", [None])[0] 482 start_offset = form.get("start-offset", [None])[0] 483 end_offset = form.get("end-offset", [None])[0] 484 485 start_zone = regime or start_offset 486 end_zone = regime or end_offset 487 488 # Validate certain fields. 489 490 try: 491 title = form["title"][0] 492 template = form["template"][0] 493 parent = form["parent"][0] 494 except (KeyError, IndexError): 495 return 0, _("Event title or template missing.") 496 497 try: 498 start_day = self._get_input(form, "start-day") 499 start_month = self._get_input(form, "start-month") 500 start_year = self._get_input(form, "start-year") 501 502 if not start_day or not start_month or not start_year: 503 return 0, _("A start date must be specified.") 504 505 end_day = self._get_input(form, "end-day", start_day) 506 end_month = self._get_input(form, "end-month", start_month) 507 end_year = self._get_input(form, "end-year", start_year) 508 509 except (TypeError, ValueError): 510 return 0, _("Days and years must be numbers yielding a valid date!") 511 512 try: 513 start_hour = self._get_input(form, "start-hour") 514 start_minute = self._get_input(form, "start-minute") 515 start_second = self._get_input(form, "start-second") 516 517 end_hour = self._get_input(form, "end-hour") 518 end_minute = self._get_input(form, "end-minute") 519 end_second = self._get_input(form, "end-second") 520 521 except (TypeError, ValueError): 522 return 0, _("Hours, minutes and seconds must be numbers yielding a valid time!") 523 524 start_date = EventAggregatorSupport.DateTime( 525 (start_year, start_month, start_day, start_hour, start_minute, start_second, start_zone) 526 ) 527 start_date.constrain() 528 529 end_date = EventAggregatorSupport.DateTime( 530 (end_year, end_month, end_day, end_hour, end_minute, end_second, end_zone) 531 ) 532 end_date.constrain() 533 534 # An elementary date ordering check. 535 536 if (start_date.as_date() != end_date.as_date() or start_date.has_time() and end_date.has_time()) and start_date > end_date: 537 start_date, end_date = end_date, start_date 538 539 event_details = { 540 "start" : str(start_date), "end" : str(end_date), 541 "title" : title, "summary" : title, 542 "description" : description, "location" : location, "link" : link, 543 "topics" : [topic for topic in topics if topic] 544 } 545 546 # Copy the template. 547 548 template_page = PageEditor(request, template) 549 550 if not template_page.exists(): 551 return 0, _("Event template not available.") 552 553 # Use any parent page information. 554 555 full_title = EventAggregatorSupport.getFullPageName(parent, title) 556 557 # Load the new page and replace the event details in the body. 558 559 new_page = PageEditor(request, full_title) 560 561 if new_page.exists(): 562 return 0, _("The specified page already exists. Please choose another name.") 563 564 # Complete the new page. 565 566 EventAggregatorSupport.fillEventPageFromTemplate(template_page, 567 new_page, event_details, category_pagenames) 568 569 # Redirect and return success. 570 571 query = {'action' : 'edit'} 572 request.http_redirect(new_page.url(request, query)) 573 return 1, None 574 575 # Action function. 576 577 def execute(pagename, request): 578 EventAggregatorNewEvent(pagename, request).render() 579 580 # vim: tabstop=4 expandtab shiftwidth=4