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