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