1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - EventAggregatorNewEvent Action 4 5 @copyright: 2008, 2009, 2010, 2011, 2012, 2013 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 EventAggregatorSupport import * 14 from EventAggregatorSupport.Actions import ActionSupport 15 16 from MoinMoin.action import ActionBase 17 from MoinMoin.Page import Page 18 from MoinMoin.PageEditor import PageEditor 19 from MoinMoin import config 20 import re 21 22 try: 23 import pytz 24 except ImportError: 25 pytz = None 26 27 Dependencies = ['pages'] 28 29 # Action class and supporting functions. 30 31 class EventAggregatorNewEvent(ActionBase, ActionSupport): 32 33 "An event creation dialogue requesting various parameters." 34 35 def get_form_html(self, buttons_html): 36 _ = self._ 37 request = self.request 38 form = self.get_form() 39 40 # Handle advanced and basic forms, and enable/disable certain fields. 41 42 show_advanced = form.get("advanced") and not form.get("basic") 43 show_end_date = form.get("end-day") and not form.get("hide-end-date") or form.get("show-end-date") 44 show_times = (form.get("start-hour") or form.get("end-hour")) and not form.get("hide-times") or form.get("show-times") 45 show_location = form.get("show-location") or form.get("new-location") and not form.get("hide-location") 46 choose_page_name = form.get("page-name") and not form.get("auto-page-name") or form.get("choose-page-name") 47 48 # Define the overridden page name, if appropriate. 49 50 page_name = choose_page_name and form.get("page-name", ["@PARENT@/@TITLE@"])[0] or "" 51 52 # Prepare the category list. 53 54 category_list = [] 55 category_pagenames = form.get("category", []) 56 57 for category_name, category_pagename in getCategoryMapping(getCategories(request), 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>' % ( 65 escattr(category_pagename), selected, escape(category_name))) 66 67 # In the basic view, use hidden fields. 68 69 elif selected: 70 category_list.append('<input value="%s" name="category" type="hidden" />' % escattr(category_pagename)) 71 72 # Prepare the topics list. 73 74 topics = form.get("topics", []) 75 76 if form.get("add-topic"): 77 topics.append("") 78 else: 79 for i in range(0, len(topics)): 80 if form.get("remove-topic-%d" % i): 81 del topics[i] 82 break 83 84 # Initialise month lists. 85 86 start_month_list, end_month_list = self.get_month_lists(default_as_current=1) 87 start_year_default, end_year_default = self.get_year_defaults(default_as_current=1) 88 89 # Initialise the locations list. 90 91 locations_page = getLocationsPage(request) 92 locations = getWikiDict(locations_page, request) 93 94 locations_list = [] 95 locations_list.append('<option value=""></option>') 96 97 location = (form.get("location") or form.get("new-location") or [""])[0] 98 99 # Prepare the locations list, selecting the specified location. 100 101 if locations: 102 locations_list += self.get_option_list(location, locations) or [] 103 104 locations_list.sort() 105 106 # Initialise the time regime from the location. 107 108 start_regime = form.get("start-regime", [None])[0] 109 end_regime = form.get("end-regime", [None])[0] 110 111 if not start_regime: 112 start_regime = Location(location, locations).getTimeRegime() 113 end_regime = end_regime or start_regime 114 115 # Initialise regime lists. 116 117 start_regime_list = [] 118 start_regime_list.append('<option value="">%s</option>' % escape(_("<The event location (if known)>"))) 119 end_regime_list = [] 120 end_regime_list.append('<option value="">%s</option>' % escape(_("<Same as start time>"))) 121 122 # Prepare regime lists, selecting specified regimes. 123 124 if pytz is not None: 125 start_regime_list += self.get_option_list(start_regime, pytz.common_timezones) 126 end_regime_list += self.get_option_list(end_regime, pytz.common_timezones) 127 128 # Show time zone-related information depending on various fields. 129 130 show_zone_regime = ( 131 form.get("start-regime") # have a regime 132 and not form.get("show-offsets") # are not switching to offsets 133 and not form.get("hide-zone") # are not removing zone information 134 or form.get("show-regime") # are switching to a regime 135 or form.get("show-times") and start_regime # are showing times with a regime 136 ) 137 show_zone_offsets = ( 138 form.get("start-offset") # have an offset 139 and not form.get("show-regime") # are not switching to a regime 140 and not form.get("hide-zone") # are not removing zone information 141 or form.get("show-offsets") # are switching to offsets 142 ) 143 144 show_zones = show_zone_regime or show_zone_offsets 145 146 # Permitting configuration of the template name. 147 148 template_default = getattr(request.cfg, "event_aggregator_new_event_template", "EventTemplate") 149 150 # Help page location. 151 152 help_page_name = getattr(request.cfg, "event_aggregator_new_event_help", "HelpOnEventAggregatorNewEvent") 153 help_page_url = Page(request, help_page_name).url(request) 154 155 # Substitution of parameters. 156 157 d = { 158 "buttons_html" : buttons_html, 159 "form_trigger" : escattr(self.form_trigger), 160 "form_cancel" : escattr(self.form_cancel), 161 162 "category_label" : escape(_("Categories")), 163 "category_list" : "\n".join(category_list), 164 165 "start_month_list" : "\n".join(start_month_list), 166 "end_month_list" : "\n".join(end_month_list), 167 168 "start_regime_list" : "\n".join(start_regime_list), 169 "end_regime_list" : "\n".join(end_regime_list), 170 "use_regime_label" : escape(_("Using local time in...")), 171 172 "show_end_date_label" : escape(_("Specify end date")), 173 "hide_end_date_label" : escape(_("End event on same day")), 174 175 "show_times_label" : escape(_("Specify times")), 176 "hide_times_label" : escape(_("No start and end times")), 177 178 "show_offsets_label" : escape(_("Specify UTC offsets")), 179 "show_regime_label" : escape(_("Use local time")), 180 "hide_zone_label" : escape(_("Make times apply everywhere")), 181 182 "start_label" : escape(_("Start date (day, month, year)")), 183 "start_day_default" : escattr(form.get("start-day", [""])[0]), 184 "start_year_default" : escattr(start_year_default), 185 "start_time_label" : escape(_("Start time (hour, minute, second)")), 186 "start_hour_default" : escattr(form.get("start-hour", [""])[0]), 187 "start_minute_default" : escattr(form.get("start-minute", [""])[0]), 188 "start_second_default" : escattr(form.get("start-second", [""])[0]), 189 "start_offset_default" : escattr(form.get("start-offset", [""])[0]), 190 191 "end_label" : escape(_("End date (day, month, year) - if different")), 192 "end_day_default" : escattr(form.get("end-day", [""])[0].strip() or form.get("start-day", [""])[0]), 193 "end_year_default" : escattr(end_year_default), 194 "end_time_label" : escape(_("End time (hour, minute, second)")), 195 "end_hour_default" : escattr(form.get("end-hour", [""])[0]), 196 "end_minute_default" : escattr(form.get("end-minute", [""])[0]), 197 "end_second_default" : escattr(form.get("end-second", [""])[0]), 198 "end_offset_default" : escattr(form.get("end-offset", [""])[0].strip() or form.get("start-offset", [""])[0]), 199 200 "title_label" : escape(_("Event title/summary")), 201 "title_default" : escattr(form.get("title", [""])[0]), 202 "choose_page_name_label": escape(_("Choose page name")), 203 "auto_page_name_label" : escape(_("Auto page name")), 204 "page_name_label" : escape(_("Page name")), 205 "page_name_default" : escattr(form.get("page-name", [page_name])[0]), 206 "description_label" : escape(_("Event description")), 207 "description_default" : escattr(form.get("description", [""])[0]), 208 209 "location_label" : escape(_("Event location")), 210 "locations_list" : "\n".join(locations_list), 211 "show_location_label" : escattr(_("Specify a different location")), 212 "hide_location_label" : escattr(_("Choose a known location")), 213 "new_location" : escattr(form.get("new-location", [location])[0]), 214 215 "latitude_label" : escape(_("Latitude")), 216 "latitude_default" : escattr(form.get("latitude", [""])[0]), 217 "longitude_label" : escape(_("Longitude")), 218 "longitude_default" : escattr(form.get("longitude", [""])[0]), 219 "link_label" : escape(_("External URL")), 220 "link_default" : escattr(form.get("link", [""])[0]), 221 222 "topics_label" : escape(_("Topics")), 223 "add_topic_label" : escape(_("Add topic")), 224 "remove_topic_label" : escape(_("Remove topic")), 225 226 "template_label" : escape(_("Event template")), 227 "template_default" : escattr(form.get("template", [""])[0].strip() or template_default), 228 "parent_label" : escape(_("Parent page")), 229 "parent_default" : escattr(form.get("parent", [""])[0]), 230 231 "advanced_label" : escape(_("Show advanced options")), 232 "basic_label" : escape(_("Hide advanced options")), 233 234 "help_page_url" : escattr(help_page_url), 235 "help_page_label" : escape(_("Help on creating events")), 236 } 237 238 # Prepare the output HTML. 239 240 html = ''' 241 <input name="update-form-only" value="false" type="hidden" /> 242 <table> 243 <tr> 244 <td class="label"><label>%(title_label)s</label></td> 245 <td colspan="2"> 246 <input name="title" type="text" size="40" value="%(title_default)s" /> 247 </td> 248 </tr>''' % d 249 250 # Page name options. 251 252 if choose_page_name: 253 html += ''' 254 <tr> 255 <td class="label"><label>%(page_name_label)s</label></td> 256 <td colspan="2"> 257 <input name="page-name" type="text" size="40" value="%(page_name_default)s" /> 258 </td> 259 <tr> 260 <td class="label"> 261 <input name="auto-page-name" type="submit" value="%(auto_page_name_label)s" /> 262 </td> 263 </tr>''' % d 264 else: 265 html += ''' 266 <tr> 267 <td class="label"> 268 <input name="choose-page-name" type="submit" value="%(choose_page_name_label)s" /> 269 </td> 270 </tr>''' % d 271 272 # Location options. 273 274 html += ''' 275 <tr> 276 <td class="label"><label>%(location_label)s</label></td> 277 <td colspan="2">''' % d 278 279 if not show_location: 280 html += ''' 281 <select name="location"> 282 %(locations_list)s 283 </select> 284 <input name="show-location" type="submit" value="%(show_location_label)s" />''' % d 285 286 else: 287 html += ''' 288 <input name="new-location" type="text" size="30" value="%(new_location)s" /> 289 <input name="hide-location" type="submit" value="%(hide_location_label)s" />''' % d 290 291 html += ''' 292 </td> 293 </tr>''' % d 294 295 # Latitude and longitude. 296 297 if show_location: 298 html += ''' 299 <tr> 300 <td class="label"><label>%(latitude_label)s</label></td> 301 <td colspan="2"> 302 <input name="latitude" type="text" size="40" value="%(latitude_default)s" /> 303 </td> 304 </tr> 305 <tr> 306 <td class="label"><label>%(longitude_label)s</label></td> 307 <td colspan="2"> 308 <input name="longitude" type="text" size="40" value="%(longitude_default)s" /> 309 </td> 310 </tr>''' % d 311 312 # Start date controls. 313 314 html += ''' 315 <tr> 316 <td class="label"><label>%(start_label)s</label></td> 317 <td colspan="2" style="white-space: nowrap"> 318 <input name="start-day" type="text" value="%(start_day_default)s" size="2" /> 319 <select name="start-month"> 320 %(start_month_list)s 321 </select> 322 <input name="start-year" type="text" value="%(start_year_default)s" size="4" /> 323 </td> 324 </tr>''' % d 325 326 # End date controls. 327 328 if show_end_date: 329 html += ''' 330 <tr> 331 <td class="label"><label>%(end_label)s</label></td> 332 <td colspan="2" style="white-space: nowrap"> 333 <input name="end-day" type="text" value="%(end_day_default)s" size="2" /> 334 <select name="end-month"> 335 %(end_month_list)s 336 </select> 337 <input name="end-year" type="text" value="%(end_year_default)s" size="4" /> 338 </td> 339 </tr> 340 <tr> 341 <td class="label"> 342 <input name="hide-end-date" type="submit" value="%(hide_end_date_label)s" /> 343 </td> 344 </tr>''' % d 345 else: 346 html += ''' 347 <tr> 348 <td class="label"> 349 <input name="show-end-date" type="submit" value="%(show_end_date_label)s" /> 350 </td> 351 </tr>''' % d 352 353 # Generic time information. 354 355 if show_times: 356 357 # Start time controls. 358 359 html += ''' 360 <tr> 361 <td class="label event-time-selection"><label>%(start_time_label)s</label></td> 362 <td style="white-space: nowrap" class="event-time-selection"> 363 <input name="start-hour" type="text" value="%(start_hour_default)s" size="2" maxlength="2" /> 364 <input name="start-minute" type="text" value="%(start_minute_default)s" size="2" maxlength="2" /> 365 <input name="start-second" type="text" value="%(start_second_default)s" size="2" maxlength="2" /> 366 </td>''' % d 367 368 # Offset information displayed. 369 370 if show_zone_offsets: 371 html += ''' 372 <td class="event-zone-selection"> 373 UTC <input name="start-offset" type="text" value="%(start_offset_default)s" size="6" maxlength="6" /> 374 </td>''' % d 375 376 # Regime information displayed. 377 378 elif show_zone_regime: 379 html += ''' 380 <td class="event-regime-selection"> 381 <label>%(use_regime_label)s</label><br/> 382 <select name="start-regime"> 383 %(start_regime_list)s 384 </select> 385 </td>''' % d 386 387 html += ''' 388 </tr>''' 389 390 # End time controls. 391 392 html += ''' 393 <tr> 394 <td class="label event-time-selection"><label>%(end_time_label)s</label></td> 395 <td style="white-space: nowrap" class="event-time-selection"> 396 <input name="end-hour" type="text" value="%(end_hour_default)s" size="2" maxlength="2" /> 397 <input name="end-minute" type="text" value="%(end_minute_default)s" size="2" maxlength="2" /> 398 <input name="end-second" type="text" value="%(end_second_default)s" size="2" maxlength="2" /> 399 </td>''' % d 400 401 # Offset information displayed. 402 403 if show_zone_offsets: 404 html += ''' 405 <td class="event-zone-selection"> 406 UTC <input name="end-offset" type="text" value="%(end_offset_default)s" size="6" maxlength="6" /> 407 </td>''' % d 408 409 # Regime information displayed. 410 411 elif show_zone_regime: 412 html += ''' 413 <td class="event-regime-selection event-end-time"> 414 <select name="end-regime"> 415 %(end_regime_list)s 416 </select> 417 </td>''' % d 418 419 # Controls for removing times. 420 421 html += ''' 422 </tr> 423 <tr> 424 <td class="label"> 425 <input name="hide-times" type="submit" value="%(hide_times_label)s" /> 426 </td> 427 <td></td> 428 <td>''' % d 429 430 # Time zone controls. 431 432 if show_zones: 433 434 # To remove zone information. 435 436 html += ''' 437 <input name="hide-zone" type="submit" value="%(hide_zone_label)s" />''' % d 438 439 # No time zone information shown. 440 441 else: 442 html += ''' 443 <input name="show-regime" type="submit" value="%(show_regime_label)s" /> 444 <input name="show-offsets" type="submit" value="%(show_offsets_label)s" />''' % d 445 446 html += ''' 447 </td> 448 </tr>''' 449 450 # Controls for adding times. 451 452 else: 453 html += ''' 454 <tr> 455 <td class="label"> 456 <input name="show-times" type="submit" value="%(show_times_label)s" /> 457 </td> 458 </tr>''' % d 459 460 461 # Various basic controls. 462 463 html += ''' 464 <tr> 465 <td class="label"><label>%(description_label)s</label></td> 466 <td colspan="2"> 467 <input name="description" type="text" size="40" value="%(description_default)s" /> 468 </td> 469 </tr> 470 <tr> 471 <td class="label"><label>%(link_label)s</label></td> 472 <td colspan="2"> 473 <input name="link" type="text" size="40" value="%(link_default)s" /> 474 </td> 475 </tr>''' % d 476 477 # Topics. 478 479 for i, topic in enumerate(topics): 480 d["topic"] = escattr(topic) 481 d["topic_number"] = i 482 html += ''' 483 <tr> 484 <td class="label"><label>%(topics_label)s</label></td> 485 <td colspan="2"> 486 <input name="topics" type="text" size="20" value="%(topic)s" /> 487 <input name="remove-topic-%(topic_number)s" type="submit" value="%(remove_topic_label)s" /> 488 </td> 489 </tr>''' % d 490 491 html += ''' 492 <tr> 493 <td></td> 494 <td colspan="2"> 495 <input name="add-topic" type="submit" value="%(add_topic_label)s" /> 496 </td> 497 </tr>''' % d 498 499 # Advanced options. 500 501 if show_advanced: 502 html += ''' 503 <tr> 504 <td></td> 505 <td colspan="2"> 506 <input name="basic" type="submit" value="%(basic_label)s" /> 507 <input name="advanced" type="hidden" value="true" /> 508 </td> 509 </tr> 510 <tr> 511 <td class="label"><label>%(category_label)s</label></td> 512 <td colspan="2" class="content"> 513 <select multiple="multiple" name="category"> 514 %(category_list)s 515 </select> 516 </td> 517 </tr> 518 <tr> 519 <td class="label"><label>%(template_label)s</label></td> 520 <td colspan="2"> 521 <input name="template" type="text" size="40" value="%(template_default)s" /> 522 </td> 523 </tr> 524 <tr> 525 <td class="label"><label>%(parent_label)s</label></td> 526 <td colspan="2"> 527 <input name="parent" type="text" size="40" value="%(parent_default)s" /> 528 </td> 529 </tr> 530 <tr> 531 <td></td> 532 <td colspan="2" class="buttons"> 533 %(buttons_html)s 534 </td> 535 </tr> 536 <tr> 537 <td></td> 538 <td colspan="2"> 539 <a href="%(help_page_url)s" target="_blank">%(help_page_label)s</a> 540 </td> 541 </tr> 542 </table>''' % d 543 else: 544 html += ''' 545 <tr> 546 <td></td> 547 <td colspan="2"> 548 <input name="advanced" type="submit" value="%(advanced_label)s" /> 549 %(category_list)s 550 <input name="parent" type="hidden" value="%(parent_default)s" /> 551 <input name="template" type="hidden" value="%(template_default)s" /> 552 </td> 553 </tr> 554 <tr> 555 <td></td> 556 <td colspan="2" class="buttons"> 557 %(buttons_html)s 558 </td> 559 </tr> 560 <tr> 561 <td></td> 562 <td colspan="2"> 563 <a href="%(help_page_url)s" target="_blank">%(help_page_label)s</a> 564 </td> 565 </tr> 566 </table> 567 <script type="text/javascript"> 568 function replaceDialog(url, button) { 569 var form = findForm(); 570 var dialog = findDialog(document); 571 if (form != null && dialog != null) { 572 var xmlhttp = new XMLHttpRequest(); 573 xmlhttp.open("POST", url, false); 574 xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 575 576 var requestBody = encodeURIComponent(button.name) + "=" + encodeURIComponent(button.value); 577 for (var i = 0; i < form.elements.length; i++) { 578 var element = form.elements[i]; 579 if (element.type != "submit") { 580 requestBody += "&" + encodeURIComponent(element.name) + "=" + encodeURIComponent(element.value); 581 } 582 } 583 xmlhttp.send(requestBody); 584 585 var newDialog = xmlhttp.responseText; 586 587 if (newDialog != null) { 588 dialog.parentNode.innerHTML = newDialog; 589 initForm(); 590 return false; 591 } 592 } 593 } 594 595 function findDialog(d) { 596 var elements = d.getElementsByTagName("div"); 597 for (var i = 0; i < elements.length; i++) { 598 var element = elements[i]; 599 var cls = element.getAttribute("class"); 600 if (cls == "dialog") { 601 return element; 602 } 603 } 604 return null; 605 } 606 607 function findForm() { 608 for (var i = 0; i < document.forms.length; i++) { 609 var form = document.forms[i]; 610 if (form["update-form-only"] != null) { 611 return form; 612 } 613 } 614 return null; 615 } 616 617 function initForm() { 618 var form = findForm(); 619 var url = form.getAttribute("action"); 620 form["update-form-only"].value = "true"; 621 for (var i = 0; i < form.length; i++) { 622 var element = form[i]; 623 if (element.type == "submit" && element.name != "%(form_trigger)s" && element.name != "%(form_cancel)s") { 624 element.setAttribute("onclick", "return replaceDialog('" + url + "', this);"); 625 } 626 } 627 } 628 629 initForm(); 630 </script>''' % d 631 632 return html 633 634 def do_action(self): 635 636 "Create the new event." 637 638 _ = self._ 639 form = self.get_form() 640 641 # If no title exists in the request, an error message is returned. 642 643 title = form.get("title", [None])[0] 644 template = form.get("template", [None])[0] 645 646 if not title: 647 return 0, _("No event title specified.") 648 649 if not template: 650 return 0, _("No page template specified.") 651 652 return self.create_event(self.request) 653 654 def render_msg(self, msg, msgtype): 655 656 """ 657 Render 'msg' and 'msgtype'. If 'msgtype' is "dialog" then the form is 658 rendered, and if only part of the form is being requested, the output 659 will be only the form HTML fragment and not the entire page. 660 """ 661 662 # Either render the form as a fragment of a page. 663 664 form = self.get_form() 665 update_form_only = form.get("update-form-only", ["false"])[0] == "true" 666 action_attempted = form.has_key(self.form_trigger) 667 668 if msgtype == "dialog" and update_form_only and not action_attempted: 669 send_headers = get_send_headers(self.request) 670 send_headers(["Content-Type: text/html; charset=%s" % config.charset]) 671 self.request.write(msg.render()) 672 673 # Or render the message/form within an entire page. 674 675 else: 676 ActionBase.render_msg(self, msg, msgtype) 677 678 def render_success(self, msg, msgtype): 679 680 """ 681 Render neither 'msg' nor 'msgtype' since redirection should occur 682 instead. 683 """ 684 685 pass 686 687 def create_event(self, request): 688 689 "Create an event page using the 'request'." 690 691 _ = request.getText 692 form = self.get_form() 693 694 category_pagenames = form.get("category", []) 695 description = form.get("description", [None])[0] 696 location = (form.get("location") or form.get("new-location") or [""])[0] 697 latitude = form.get("latitude", [None])[0] 698 longitude = form.get("longitude", [None])[0] 699 link = form.get("link", [None])[0] 700 topics = form.get("topics", []) 701 702 start_regime = form.get("start-regime", [None])[0] 703 end_regime = form.get("end-regime", form.get("start-regime", [None]))[0] 704 start_offset = form.get("start-offset", [None])[0] 705 end_offset = form.get("end-offset", [None])[0] 706 707 start_zone = start_regime or start_offset 708 end_zone = end_regime or end_offset 709 710 page_name = form.get("page-name", [None])[0] 711 712 # Validate certain fields. 713 714 title = form.get("title", [""])[0].strip() 715 template = form.get("template", [""])[0].strip() 716 parent = form.get("parent", [""])[0].strip() 717 718 if not title: 719 return 0, _("No event title specified.") 720 if not template: 721 return 0, _("No event template specified.") 722 723 try: 724 start_day = self._get_input(form, "start-day") 725 start_month = self._get_input(form, "start-month") 726 start_year = self._get_input(form, "start-year") 727 728 if not start_day or not start_month or not start_year: 729 return 0, _("A start date must be specified.") 730 731 end_day = self._get_input(form, "end-day", start_day) 732 end_month = self._get_input(form, "end-month", start_month) 733 end_year = self._get_input(form, "end-year", start_year) 734 735 except (TypeError, ValueError): 736 return 0, _("Days and years must be numbers yielding a valid date!") 737 738 try: 739 start_hour = self._get_input(form, "start-hour") 740 start_minute = self._get_input(form, "start-minute") 741 start_second = self._get_input(form, "start-second") 742 743 end_hour = self._get_input(form, "end-hour") 744 end_minute = self._get_input(form, "end-minute") 745 end_second = self._get_input(form, "end-second") 746 747 except (TypeError, ValueError): 748 return 0, _("Hours, minutes and seconds must be numbers yielding a valid time!") 749 750 start_date = DateTime( 751 (start_year, start_month, start_day, start_hour, start_minute, start_second, start_zone) 752 ) 753 start_date.constrain() 754 755 end_date = DateTime( 756 (end_year, end_month, end_day, end_hour, end_minute, end_second, end_zone) 757 ) 758 end_date.constrain() 759 760 # An elementary date ordering check. 761 762 if (start_date.as_date() != end_date.as_date() or start_date.has_time() and end_date.has_time()) and start_date > end_date: 763 start_date, end_date = end_date, start_date 764 765 event_details = { 766 "start" : str(start_date), "end" : str(end_date), 767 "title" : title, "summary" : title, 768 "description" : description, "location" : location, "link" : link, 769 "topics" : [topic for topic in topics if topic] 770 } 771 772 if latitude and longitude: 773 event_details["geo"] = latitude, longitude 774 775 # Copy the template. 776 777 template_page = PageEditor(request, template) 778 779 if not template_page.exists(): 780 return 0, _("Event template not available.") 781 782 # Use any parent page information. 783 784 full_title = getFullPageName(parent, title) 785 786 if page_name: 787 788 # Allow parameters in the page name. This permits a degree of 789 # interoperability with MonthCalendar. 790 791 page_name = page_name.replace("@PAGE@", request.page.page_name) 792 page_name = page_name.replace("@DATE@", str(start_date.as_date())) 793 page_name = page_name.replace("@STARTDATE@", str(start_date.as_date())) 794 page_name = page_name.replace("@ENDDATE@", str(end_date.as_date())) 795 page_name = page_name.replace("@PARENT@", parent) 796 page_name = page_name.replace("@TITLE@", title) 797 798 # Normalise any page hierarchy separators. 799 800 page_name = re.sub("/+", "/", page_name) 801 802 else: 803 page_name = full_title 804 805 # Load the new page and replace the event details in the body. 806 807 new_page = PageEditor(request, page_name) 808 809 if new_page.exists(): 810 return 0, _("The specified page already exists. Please choose another name.") 811 812 # Complete the new page and return its body. 813 814 body = fillEventPageFromTemplate(template_page, new_page, event_details, category_pagenames) 815 816 # Open the page editor on the new page. 817 # NOTE: Replacing the revision in the request to prevent Moin from 818 # NOTE: attempting to use the queued changes page's revision. 819 # NOTE: Replacing the action and page in the request to avoid issues 820 # NOTE: with editing tickets. 821 822 request.rev = 0 823 request.action = "edit" 824 request.page = new_page 825 new_page.sendEditor(preview=body, staytop=True) 826 827 # Return success. 828 829 return 1, None 830 831 # Action function. 832 833 def execute(pagename, request): 834 EventAggregatorNewEvent(pagename, request).render() 835 836 # vim: tabstop=4 expandtab shiftwidth=4