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