Attachment 'EventCalendar-094-easytime.py'
Download 1 """
2 EventCalendar.py Version 0.94 February 06, 2006
3
4 This macro gives a list of the events recorded in the sub-pages in the form of monthly view and list view.
5
6 @copyright: 2006 by Seungik Lee <seungiklee<at>gmail.com> http://www.silee.net/
7 @license: GPL
8
9 For more information, please visit http://moinmoin.wikiwikiweb.de/MacroMarket/EventCalendar
10
11 <Usage>
12
13 * To list the events in a page, just insert [[EventCalendar]]
14 * To insert an event, insert the event information in any pages of specified category (CategoryEventCalendar by default).
15
16 <Parameters>
17
18 * category: the category of the event data to be used in the calendar. default: 'CategoryEventCalendar'
19 * menubar: shows menubar or not (1: show, 0: no menubar). default: 1
20 * monthlywidth: calendar width in pixel or percent (monthly view). default: '600' (pixel)
21 * simplewidth: calendar width in pixel or percent (simpleview). default: '150' (pixel)
22 * firstview: initial calendar view: monthly, list, simple, upcoming. default: 'monthly'
23 * curdate: initial calendar date (in YYYYMM format). default: current month
24 * upcomingrange: # of days for the range of upcoming event list. default: 7 (days)
25
26 <Event Data Format>
27
28 * Example:
29
30 [default_description:: [default_description_text]]
31 [default_bgcolor:: [default_custom_background_color]]
32
33 == <title> ==
34 start:: <startdate> [starttime]
35 [end:: [enddate] [endtime]]
36 [description:: [description_text]]
37 [bgcolor:: [custom_background_color]]
38 [recur:: <recur_freq> <recur_type> [until <recur_until>]]
39
40 ...
41
42 ----
43 CategoryEventCalendar
44
45
46 * title: event title. required
47 * should be enclosed with heading marker ('='), Title cannot be omitted.
48
49 * startdate: date of start. required
50 * should be in YYYY/MM/DD or YYYY-MM-DD
51
52 * starttime: time of start. optional
53 * should be in HH:MM in 24-hour format
54
55 * enddate: date of end. optional
56 * should be in YYYY/MM/DD or YYYY-MM-DD. If omitted, it will be assigned equal to <startdate>.
57
58 * endtime: time of end. optional
59 * should be in HH:MM in 24-hour format. Both of start|end Time can be omitted but not either of them.
60
61 * description: description of the event. optional
62 * any text with no markup. should be in a line.
63
64 * bgcolor: custom background color of the event in monthly view. optional
65 * e.g., #abcdef
66
67 * recur: recurrence information of the event, optional
68 * recur_freq: how many intervals, digit, required
69 * recur_type: [day|week|weekday|month|year], required
70 * day: every [recur_freq] days
71 * week: every [recur_freq] weeks
72 * weekday: on the same weekday of [recur_freq]-th week of the month
73 * month: on the same day of [recur_freq]-th month
74 * year: on the same day of [recur_freq]-th year
75 * recur_until: recurred until when, YYYY/MM/DD or YYYY-MM-DD, optional
76
77 * e.g., 10 day, 2 week until 2006-06-31, 3 weekday, 6 month until 2007-12-31, 1 year
78
79 * default_bgcolor, default_description: default values of bgcolor and description in the page if unavailable
80
81 * The order of the fields after an event title does not matter.
82
83 <Event Data Examples>
84
85 = Default values =
86 default_bgcolor:: #c0c0c0
87 default_description:: testing...
88
89 === Test event ===
90 start:: 2006-01-10 14:00
91 end:: 2006-01-12 17:00
92 description:: test event
93 bgcolor:: #cfcfcf
94
95 === Jinah's Birthday ===
96 start:: 1977-10-20
97 recur:: 1 year
98
99 === Weekly meeting ===
100 start:: 2006-01-17 19:00
101 end:: 21:00
102 recur:: 1 week until 2006-12-31
103
104 ----
105 CategoryEventCalendar
106
107
108 <Notes>
109
110 * It caches all the page list of the specified category and the event information.
111 * If you added/removed a page into/from a category, you need to do 'Delete cache' in the macro page.
112
113 * 'MonthCalendar.py' developed by Thomas Waldmann <ThomasWaldmann@gmx.de> has inspired this macro.
114 * Much buggy.. : please report bugs and suggest your ideas.
115 * If you missed to add css for EventCalender, monthly view may not be readable.
116 * Insert the EventCalendar css classes into the screen.css of an appropriate theme.
117
118
119
120 """
121
122 from MoinMoin import wikiutil, config, search, caching
123 from MoinMoin.Page import Page
124 from MoinMoin.parser import wiki
125 import re, calendar, time, datetime
126 import codecs, os, urllib, sha
127
128 try:
129 import cPickle as pickle
130 except ImportError:
131 import pickle
132
133 # Set pickle protocol, see http://docs.python.org/lib/node64.html
134 PICKLE_PROTOCOL = pickle.HIGHEST_PROTOCOL
135
136
137 # The following line sets the calendar to have either Sunday or Monday as
138 # the first day of the week. Only SUNDAY or MONDAY (case sensitive) are
139 # valid here. All other values will not make good calendars.
140 # XXX change here ----------------vvvvvv
141 calendar.setfirstweekday(calendar.SUNDAY)
142
143
144 class Globs:
145 month_style_us = 1 # 1: October 2005; 2: 2005 / 10
146 defaultcategory = 'CategoryEventCalendar'
147 upcomingrange = 7 # days
148 pagename = ''
149 baseurl = ''
150 subname = ''
151 wkend = ''
152 months = ''
153 wkdays = ''
154 today = ''
155 request = None
156 formatter = None
157 cal_action = ''
158 debugmsg = ''
159 page_action = ''
160 events = None
161
162
163 class Params:
164 menubar = 0
165 monthlywidth = ''
166 simplewidth = ''
167 firstview = ''
168 curdate = ''
169 bgcolor = ''
170 category = ''
171 upcomingrange = 0
172 debug = 0
173
174
175 def execute(macro, args):
176
177 request = macro.request
178 formatter = macro.formatter
179
180 # INITIALIZATION ----------------------------------------
181 setglobalvalues(macro)
182 getparams(args)
183
184 # allowed actions
185 allowed_action = ['monthly', 'list', 'simple', 'upcoming']
186 default_action = Params.firstview
187
188 # Internal variables
189 cal_action = ''
190 form_vals = {}
191
192 # PROCESSING ARGUEMENTS ----------------------------------------
193 if args:
194 args=request.getText(args)
195
196 for item in macro.form.items():
197 if not form_vals.has_key(item[0]):
198 try:
199 form_vals[item[0]]=item[1][0]
200 except AttributeError:
201 pass
202
203 # PROCESSING ACTIONS ----------------------------------------
204 cal_action = form_vals.get('calaction', default_action)
205 page_action = form_vals.get('action', 'show')
206
207 if not cal_action in allowed_action:
208 cal_action = default_action
209
210 form_vals['calaction'] = cal_action
211
212 # CONTROL FUNCTIONS ----------------------------------------
213
214 html = []
215 html_result = ''
216
217 Globs.cal_action = cal_action
218 Globs.page_action = page_action
219
220
221 # redirect to the appropriate view
222 if cal_action == 'monthly':
223 html_result = showcalendar(form_vals)
224
225 if cal_action == 'list':
226 html_result = showeventlist(form_vals)
227
228 if cal_action == 'simple':
229 html_result = showsimplecalendar(form_vals)
230
231 if cal_action == 'upcoming':
232 html_result = showupcomingeventlist(form_vals)
233
234
235 # format output
236 html.append( html_result )
237 html.append( showmenubar(form_vals) )
238
239 if Params.debug and Globs.debugmsg:
240 html.append(u'<p><b>Debug messages:</b><font color="#aa0000"><ol>%s</ol></font>' % Globs.debugmsg)
241
242 return formatter.rawHTML(u''.join(html))
243
244
245
246 def getparams(args):
247 # process arguments
248
249 params = {}
250 if args:
251 # Arguments are comma delimited key=value pairs
252 sargs = args.split(',')
253
254 for item in sargs:
255 sitem = item.split('=')
256
257 if len(sitem) == 2:
258 key, value = sitem[0], sitem[1]
259 params[key.strip()] = value.strip()
260
261 # category name:
262 # default: 'CategoryEventCalendar'
263 Params.category = params.get('category', Globs.defaultcategory)
264
265 # menu bar: shows menubar or not (1: show, 0: no menubar)
266 # default: 1
267 try:
268 Params.menubar = int(params.get('menubar', 1))
269 except (TypeError, ValueError):
270 Params.menubar = 1
271
272 # calendar width in pixel or percent (monthly)
273 # default: 600px
274 Params.monthlywidth = params.get('monthlywidth', '600')
275 if Params.monthlywidth:
276 # Params.monthlywidth = Params.monthlywidth.replace('%', '%%')
277 Params.monthlywidth = ' width="%s" ' % Params.monthlywidth
278
279 # calendar width in pixel or percent (simply)
280 # default: 150px
281 Params.simplewidth = params.get('simplewidth', '150')
282 if Params.simplewidth:
283 # Params.simplewidth = Params.simplewidth.replace('%', '%%')
284 Params.simplewidth = ' width="%s" ' % Params.simplewidth
285
286 # calendar view: monthly, list, simple
287 # default: 'monthly'
288 Params.firstview = params.get('firstview', 'monthly')
289
290 # calendar date: in YYYYMM format (in monthly, simple view)
291 # default: current month
292 Params.curdate = params.get('curdate', '')
293
294 # upcoming range: # of days for upcoming event list
295 # default: 7
296 try:
297 Params.upcomingrange = int(params.get('upcomingrange', Globs.upcomingrange))
298 except (TypeError, ValueError):
299 Params.upcomingrange = Globs.upcomingrange
300
301 # default bgcolor
302 Params.bgcolor = '#ddffdd'
303
304
305 def setglobalvalues(macro):
306
307 request = macro.request
308 formatter = macro.formatter
309
310 # Useful variables
311 Globs.baseurl = request.getBaseURL() + '/'
312 Globs.pagename = formatter.page.page_name
313 Globs.request = request
314 Globs.formatter = formatter
315
316 # This fixes the subpages bug. subname is now used instead of pagename when creating certain urls
317 Globs.subname = Globs.pagename.split('/')[-1]
318
319 pagepath = formatter.page.getPagePath()
320 Globs.pagepath = formatter.page.getPagePath()
321
322 # european / US differences
323 months = ('January','February','March','April','May','June','July','August','September','October','November','December')
324
325 # Set things up for Monday or Sunday as the first day of the week
326 if calendar.firstweekday() == calendar.MONDAY:
327 wkend = 6
328 wkdays = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')
329 elif calendar.firstweekday() == calendar.SUNDAY:
330 wkend = 0
331 wkdays = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')
332
333 Globs.months = months
334 Globs.wkdays = wkdays
335 Globs.wkend = wkend
336
337 year, month, day, h, m, s, wd, yd, ds = request.user.getTime(time.time())
338 Globs.today = datetime.date(year, month, day)
339
340 Globs.debugmsg = ''
341
342
343 def showReferPageParsed(event, targettext='title', showdesc=0):
344 request = Globs.request
345 pagename = Globs.pagename
346
347 refer = event['refer']
348 targettext = event[targettext]
349 startdate = event['startdate']
350 enddate = event['enddate']
351 description = event['description']
352 starttime = event['starttime']
353 endtime = event['endtime']
354 hid = event['hid']
355
356 if showdesc:
357 if (startdate == enddate) and (starttime and endtime):
358 timedescription = '%s:%s ~ %s:%s' % (starttime[:2], starttime[2:], endtime[:2], endtime[2:])
359 if description:
360 timedescription = '%s | ' % timedescription
361 else:
362 timedescription = ''
363
364 targetlink = '<a href="%s#%s" title="%s%s">%s</a>' % ( refer, hid, timedescription, wikiutil.escape(description), wikiutil.escape(targettext) )
365 else:
366 targetlink = '<a href="%s#%s">%s</a>' % ( refer, hid, wikiutil.escape(targettext))
367
368 return targetlink
369
370
371 def getheadingid(request, referpage, title):
372
373 pntt = (referpage + title).encode(config.charset)
374 hid = "head-" + sha.new(pntt).hexdigest()
375 request._page_headings.setdefault(pntt, 0)
376 request._page_headings[pntt] += 1
377 if request._page_headings[pntt] > 1:
378 hid += '-%d'%(request._page_headings[pntt],)
379
380 return hid
381
382
383 def getquerystring(form_vals, req_fields):
384
385 m_query = []
386 tmp_form_vals = form_vals
387
388 # format querystring
389 # action should be poped out
390 for field in req_fields:
391 if tmp_form_vals.has_key(field):
392 m_query.append(u'%s=%s' % (field, tmp_form_vals[field]) )
393
394 if 'prevcalaction' in req_fields:
395 if not tmp_form_vals.has_key('prevcalaction'):
396 m_query.append(u'%s=%s' % ('prevcalaction', tmp_form_vals['calaction']) )
397
398 m_query = u'&'.join(m_query)
399 return m_query
400
401
402 # bottom menu bar
403 def showmenubar(form_vals):
404
405 cal_action = Globs.cal_action
406 page_name = Globs.pagename
407
408 if not Params.menubar: return ''
409
410 if cal_action == 'simple':
411 menuwidth = Params.simplewidth
412 elif cal_action == 'monthly':
413 menuwidth = Params.monthlywidth
414 else:
415 menuwidth = ''
416
417 left_menu_selected = []
418 right_menu_selected = []
419
420 # Go Today
421 year, month, day = gettodaydate()
422 mnu_curmonthcal = u'<a href="%s?calaction=%s&caldate=%d%02d" title="Go Today">[Today]</a>' % (page_name, cal_action, year, month)
423
424 # List View
425 mnu_listview = u'<a href="%s?calaction=list" title="List of all events">[List]</a>' % page_name
426
427 # Monthly View
428 mnu_monthview = u'<a href="%s?calaction=monthly&%s" title="Monthly view">[Monthly]</a>' % (page_name, getquerystring(form_vals, ['caldate']) )
429
430 # Simple Calendar View
431 mnu_simpleview = u'<a href="%s?calaction=simple&%s" title="Simple calendar view">[Simple]</a>' % (page_name, getquerystring(form_vals, ['caldate']) )
432
433 # Upcoming Event List
434 mnu_upcomingview = u'<a href="%s?calaction=upcoming&%s" title="Upcoming event list">[Upcoming]</a>' % (page_name, getquerystring(form_vals, ['caldate']) )
435
436 html = [
437 u'\r\n',
438 u'<table class="eventcalendar_menubar" %s>',
439 u' <tr>',
440 u' <td class="eventcalendar_menubar" align="left">%s</td>',
441 u' <td class="eventcalendar_menubar" align="right">%s</td>',
442 u' </tr>',
443 u'</table>',
444 ]
445
446 if cal_action == 'list':
447 left_menu_selected.append(mnu_monthview)
448 left_menu_selected.append(mnu_simpleview)
449 right_menu_selected.append(mnu_upcomingview)
450
451 elif cal_action == 'simple':
452 left_menu_selected.append(mnu_monthview)
453 left_menu_selected.append(mnu_listview)
454 right_menu_selected.append(mnu_upcomingview)
455 right_menu_selected.append(mnu_curmonthcal)
456
457 elif cal_action == 'upcoming':
458 left_menu_selected.append(mnu_monthview)
459 left_menu_selected.append(mnu_simpleview)
460 left_menu_selected.append(mnu_listview)
461
462 else:
463 left_menu_selected.append(mnu_listview)
464 left_menu_selected.append(mnu_simpleview)
465 right_menu_selected.append(mnu_upcomingview)
466 right_menu_selected.append(mnu_curmonthcal)
467
468 left_menu_selected = u'\r\n'.join(left_menu_selected)
469 right_menu_selected = u'\r\n'.join(right_menu_selected)
470
471 html = u'\r\n'.join(html)
472 html = html % (menuwidth, left_menu_selected, right_menu_selected)
473
474 return html
475
476
477 def getdatefield(str_date):
478 str_year = ''
479 str_month = ''
480 str_day = ''
481
482 if len(str_date) == 6:
483 # year+month
484 str_year = str_date[:4]
485 str_month = str_date[4:]
486 str_day = '1'
487
488 elif len(str_date) == 8:
489 # year+month+day
490 str_year = str_date[:4]
491 str_month = str_date[4:6]
492 str_day = str_date[6:]
493
494 elif len(str_date) == 10:
495 # year+?+month+?+day
496 str_year = str_date[:4]
497 str_month = str_date[5:7]
498 str_day = str_date[8:]
499
500 else:
501 raise ValueError
502
503 # It raises exception if the input date is incorrect
504 temp = datetime.date(int(str_year), int(str_month), int(str_day))
505
506 return temp.year, temp.month, temp.day
507
508
509 def gettimefield(str_time):
510 str_hour = ''
511 str_min = ''
512
513 regex_time = '(?P<hour>\\d{1,2})[:]?(?P<minute>\\d{0,2})(?P<meridian_p>[pP][mM]?)?'
514 pattern = re.compile(regex_time)
515 match = pattern.search(str_time)
516
517 if match:
518 str_hour = match.group('hour')
519 str_min = match.group('minute')
520 str_meridian_p = match.group('meridian_p')
521
522 else:
523 raise ValueError
524
525 int_hour = int(str_hour)
526
527 # convert to 24 hour format
528 if int_hour == 12:
529 int_hour = 0
530
531 # check for pm
532 if str_meridian_p:
533 int_hour = int_hour + 12
534
535 #handle null minutes
536 try:
537 int_min = int(str_min)
538 except (TypeError, ValueError):
539 int_min = 0
540
541 # It raises exception if the input date is incorrect
542 temp = datetime.time(int_hour, int_min)
543
544 return temp.hour, temp.minute
545
546
547 def gettodaydate():
548 today = Globs.today
549 return today.year, today.month, today.day
550
551
552 def cal_listhead():
553
554 html = [
555 u' <tr>',
556 u' <td class="list_head">Title</td>',
557 u' <td class="list_head">Start Date</td>',
558 u' <td class="list_head">End Date</td>',
559 u' <td class="list_head">Recurrence</td>',
560 u' <td class="list_head">Description</td>',
561 u' <td class="list_head">Reference</td>',
562 u' </tr>',
563 ]
564
565 return u'\r\n'.join(html)
566
567
568 def showeventlist(form_vals):
569
570 debug('Show Calendar: List view')
571
572 request = Globs.request
573 formatter = Globs.formatter
574
575 html_event_rows = []
576 html_list_header = cal_listhead()
577
578 # read all the events
579 events, cal_events = loadEvents()
580
581 # sort events
582 sorted_eventids = events.keys()
583 sorted_eventids.sort(cmp=lambda x,y: cmp(events[x]['startdate'], events[y]['startdate']))
584
585 for eid in sorted_eventids:
586 if not events[eid]['clone']:
587 html_event_rows.append( listshow_event(events[eid], form_vals) )
588
589 html_event_rows = u'\r\n'.join(html_event_rows)
590
591 html_list_table = [
592 u'\r\n<div id="eventlist">',
593 u'<table class="eventlist">',
594 u'%s' % html_list_header,
595 u'%s' % html_event_rows,
596 u'</table>',
597 u'</div>',
598 ]
599 html_list_table = u'\r\n'.join(html_list_table)
600
601 return html_list_table
602
603
604 def listshow_event(event, form_vals):
605
606 if event['recur_freq']:
607 recur_desc = 'every %d %s' % (event['recur_freq'], event['recur_type'])
608 if event['recur_until']:
609 recur_desc = '%s until %s' % (recur_desc, formatcfgdatetime(event['recur_until']))
610 else:
611 recur_desc = ''
612
613 html = [
614 u' <tr>',
615 u' <td class="list_entry">%s</td>' % converttext(event['title']),
616 u' <td class="list_entry">%s</td>' % formatcfgdatetime(event['startdate'], event['starttime']),
617 u' <td class="list_entry">%s</td>' % formatcfgdatetime(event['enddate'], event['endtime']),
618 u' <td class="list_entry">%s</td>' % recur_desc,
619 u' <td class="list_entry">%s</td>' % converttext(event['description']),
620 u' <td class="list_entry">%s</td>' % showReferPageParsed(event, 'refer'),
621 u' </tr>',
622 ]
623
624 return u'\r\n'.join(html)
625
626
627 def showupcomingeventlist(form_vals):
628
629 debug('Show Calendar: Upcoming Event View')
630
631 request = Globs.request
632 formatter = Globs.formatter
633
634 html_event_rows = []
635 html_list_header = cal_listhead()
636
637 year, month, day = gettodaydate()
638 day_delta = datetime.timedelta(days=Params.upcomingrange)
639 cur_date = datetime.date(year, month, day)
640 next_range = cur_date + day_delta
641
642 # set ranges of events
643 datefrom = u'%04d%02d%02d' % (year, month, day)
644 dateto = u'%04d%02d%02d' % (next_range.year, next_range.month, next_range.day)
645
646 # read all the events (no cache)
647 events, cal_events = loadEvents(datefrom, dateto, 1)
648
649 datefrom = u'%04d-%02d-%02d' % (year, month, day)
650 dateto = u'%04d-%02d-%02d' % (next_range.year, next_range.month, next_range.day)
651
652 # sort events
653 sorted_eventids = events.keys()
654 sorted_eventids.sort(cmp=lambda x,y: cmp(events[x]['startdate'], events[y]['startdate']))
655
656 for eid in sorted_eventids:
657 html_event_rows.append( listshow_event(events[eid], form_vals) )
658
659 html_event_rows = u'\r\n'.join(html_event_rows)
660
661 html_list_table = [
662 u'\r\n<div id="eventlist">',
663 u'<table class="eventlist">',
664 u'<tr><td colspan="7" class="list_entry" style="border-width: 0px;"><b>Upcoming Event List: %s ~ %s</b><p><br><p></td></tr>' % (datefrom, dateto),
665 u'%s' % html_list_header,
666 u'%s' % html_event_rows,
667 u'</table>',
668 u'</div>',
669 ]
670 html_list_table = u'\r\n'.join(html_list_table)
671
672 return html_list_table
673
674
675
676
677 def showcalendar(form_vals):
678
679 request = Globs.request
680 formatter = Globs.formatter
681
682 if form_vals.has_key('caldate'):
683 try:
684 year, month, str_temp = getdatefield(form_vals['caldate'])
685 except (TypeError, ValueError):
686 debug('Invalid target date: e.g., "200510"')
687 year, month, dy = gettodaydate()
688 elif Params.curdate:
689 try:
690 year, month, str_temp = getdatefield(Params.curdate)
691 except (TypeError, ValueError):
692 debug('Invalid target date: e.g., "200510"')
693 year, month, dy = gettodaydate()
694
695 else:
696 year, month, dy = gettodaydate()
697
698 html = showeventcalendar(year, month)
699
700 return u''.join(html)
701
702
703
704
705 def showsimplecalendar(form_vals):
706
707 request = Globs.request
708 formatter = Globs.formatter
709
710 if form_vals.has_key('caldate'):
711 try:
712 year, month, str_temp = getdatefield(form_vals['caldate'])
713 except (TypeError, ValueError):
714 debug('Invalid target date: e.g., "200510"')
715 year, month, dy = gettodaydate()
716 elif Params.curdate:
717 try:
718 year, month, str_temp = getdatefield(Params.curdate)
719 except (TypeError, ValueError):
720 debug('Invalid target date: e.g., "200510"')
721 year, month, dy = gettodaydate()
722 else:
723 year, month, dy = gettodaydate()
724
725 html = showsimpleeventcalendar(year, month)
726
727 return u''.join(html)
728
729
730
731 # sort events in cal_events by length of days of the event
732 def comp_cal_events(xid, yid):
733 events = Globs.events
734
735 if events[xid]['date_len'] > events[yid]['date_len']:
736 return -1
737 elif events[xid]['date_len'] == events[yid]['date_len']:
738 if events[xid]['date_len'] == 1:
739 return cmp(events[xid]['starttime'], events[yid]['starttime'])
740 else:
741 return 0
742 else:
743 return 1
744
745
746 # load events from wiki pages
747 def loadEvents(datefrom='', dateto='', nocache=0):
748
749 request = Globs.request
750
751 debug('Loading event information.')
752
753 events = {}
754 cal_events = {}
755 raw_events = loadEventsFromWikiPages()
756
757 # handling cal_events
758 if datefrom or dateto:
759
760 # cache configurations
761 arena = Page(request, Globs.pagename)
762 eventkey = 'events'
763 filteredeventkey = 'events_%s-%s' % (datefrom, dateto)
764 caleventkey = 'calevents_%s-%s' % (datefrom, dateto)
765
766 cache_events = caching.CacheEntry(request, arena, eventkey)
767 cache_filteredevents = caching.CacheEntry(request, arena, filteredeventkey)
768 cache_calevents = caching.CacheEntry(request, arena, caleventkey)
769
770 dirty = 1
771
772 debug('Checking cal_events cache')
773
774 if not (cache_calevents.needsUpdate(cache_events._filename()) or cache_filteredevents.needsUpdate(cache_events._filename())):
775
776 try:
777 events = pickle.loads(cache_filteredevents.content())
778 cal_events = pickle.loads(cache_calevents.content())
779 debug('Cached event (filtered) information is used: total %d events' % len(events))
780 dirty = 0
781 except (pickle.UnpicklingError, IOError, EOFError, ValueError):
782 debug('Picke error at fetching cached events (filtered)')
783 events = {}
784 cal_events = {}
785
786
787 # if cache is dirty, update the cache
788 if dirty:
789
790 debug('Checking event cache: it\'s dirty or requested to refresh')
791 debug('Building new cal_event information')
792
793 try:
794 datefrom, dateto = int(datefrom), int(dateto)
795 except (TypeError, ValueError):
796 datefrom, dateto = 0, 0
797
798 clone_num = 0
799
800 for e_id in raw_events.keys():
801
802 cur_event = raw_events[e_id]
803
804 # handling event recurrence
805 recur_freq = cur_event['recur_freq']
806
807 if recur_freq:
808
809 if not (cur_event['recur_until'] and int(cur_event['recur_until']) < datefrom) or int(cur_event['startdate']) > dateto:
810
811 if not (int(cur_event['enddate']) < datefrom or int(cur_event['startdate']) > dateto):
812 # generating cal_events for iteself
813 events[e_id] = cur_event.copy()
814 insertcalevents(cal_events, datefrom, dateto, e_id, cur_event['startdate'], cur_event['enddate'])
815
816 delta_date_len = datetime.timedelta(days = int(cur_event['date_len']) - 1 )
817
818 if cur_event['recur_type'] == 'day':
819
820 day_delta = int(recur_freq)
821 startdate = getdatetimefromstring(cur_event['startdate'])
822 datefrom_date = getdatetimefromstring(datefrom)
823
824 if int(datefrom) > int(cur_event['startdate']):
825 diffs = datefrom_date - startdate
826 q_delta = diffs.days / day_delta
827 if diffs.days % day_delta > 0:
828 q_delta += 1
829 else:
830 q_delta = 1
831
832 while 1:
833
834 if q_delta == 0:
835 q_delta += 1
836 continue
837
838 recurred_startdate = startdate + datetime.timedelta(days = q_delta * day_delta )
839 recurred_enddate = recurred_startdate + delta_date_len
840
841 new_startdate = formatdateobject(recurred_startdate)
842 new_enddate = formatdateobject(recurred_enddate)
843
844 if int(new_startdate) > dateto or (cur_event['recur_until'] and int(cur_event['recur_until']) < int(new_startdate)):
845 break
846
847 clone_num += 1
848 clone_id = 'c%d' % clone_num
849
850 events[clone_id] = cur_event.copy()
851 events[clone_id]['id'] = clone_id
852 events[clone_id]['startdate'] = new_startdate
853 events[clone_id]['enddate'] = new_enddate
854 events[clone_id]['clone'] = 1
855
856 insertcalevents(cal_events, datefrom, dateto, clone_id, new_startdate, new_enddate)
857
858 q_delta += 1
859
860 elif cur_event['recur_type'] == 'week':
861
862 day_delta = int(recur_freq) * 7
863
864 startdate = getdatetimefromstring(cur_event['startdate'])
865 datefrom_date = getdatetimefromstring(datefrom)
866
867 if int(datefrom) > int(cur_event['startdate']):
868 diffs = datefrom_date - startdate
869 q_delta = diffs.days / day_delta
870 if diffs.days % day_delta > 0:
871 q_delta += 1
872 else:
873 q_delta = 1
874
875 while 1:
876
877 if q_delta == 0:
878 q_delta += 1
879 continue
880
881 recurred_startdate = startdate + datetime.timedelta(days = q_delta * day_delta )
882 recurred_enddate = recurred_startdate + delta_date_len
883
884 new_startdate = formatdateobject(recurred_startdate)
885 new_enddate = formatdateobject(recurred_enddate)
886
887 if int(new_startdate) > dateto or (cur_event['recur_until'] and int(cur_event['recur_until']) < int(new_startdate)):
888 break
889
890 clone_num += 1
891 clone_id = 'c%d' % clone_num
892
893 events[clone_id] = cur_event.copy()
894 events[clone_id]['id'] = clone_id
895 events[clone_id]['startdate'] = new_startdate
896 events[clone_id]['enddate'] = new_enddate
897 events[clone_id]['clone'] = 1
898
899 insertcalevents(cal_events, datefrom, dateto, clone_id, new_startdate, new_enddate)
900
901 q_delta += 1
902
903
904 elif cur_event['recur_type'] == 'weekday':
905
906 syear, smonth, sday = getdatefield(cur_event['startdate'])
907 cyear, cmonth, cday = getdatefield(str(datefrom))
908
909 recur_weekday = calendar.weekday(syear, smonth, sday)
910
911
912 while 1:
913
914 firstweekday, daysinmonth = calendar.monthrange(cyear, cmonth)
915 firstmatch = (recur_weekday - firstweekday) % 7 + 1
916
917 #XXX should handle error
918 try:
919 therecur_day = xrange(firstmatch, daysinmonth + 1, 7)[recur_freq-1]
920 except IndexError:
921 therecur_day = xrange(firstmatch, daysinmonth + 1, 7)[-1]
922
923 recurred_startdate = datetime.date(cyear, cmonth, therecur_day)
924 recurred_enddate = recurred_startdate + delta_date_len
925
926 new_startdate = formatdateobject(recurred_startdate)
927 new_enddate = formatdateobject(recurred_enddate)
928
929 if int(new_startdate) < int(datefrom):
930 cyear, cmonth = yearmonthplusoffset(cyear, cmonth, 1)
931 continue
932
933 if int(new_startdate) > dateto or (cur_event['recur_until'] and int(cur_event['recur_until']) < int(new_startdate)):
934 break
935
936 clone_num += 1
937 clone_id = 'c%d' % clone_num
938
939 events[clone_id] = cur_event.copy()
940 events[clone_id]['id'] = clone_id
941 events[clone_id]['startdate'] = new_startdate
942 events[clone_id]['enddate'] = new_enddate
943 events[clone_id]['clone'] = 1
944
945 insertcalevents(cal_events, datefrom, dateto, clone_id, new_startdate, new_enddate)
946
947 cyear, cmonth = yearmonthplusoffset(cyear, cmonth, 1)
948
949
950 elif cur_event['recur_type'] == 'month':
951
952 cyear, cmonth, therecurday = getdatefield(cur_event['startdate'])
953
954 while 1:
955
956 cyear, cmonth = yearmonthplusoffset(cyear, cmonth, recur_freq)
957 firstweekday, daysinmonth = calendar.monthrange(cyear, cmonth)
958 recur_day = therecurday
959 if daysinmonth < recur_day:
960 recur_day = daysinmonth
961 new_startdate = formatDate(cyear, cmonth, recur_day)
962
963 if int(new_startdate) < int(datefrom):
964 continue
965
966 recurred_startdate = datetime.date(cyear, cmonth, recur_day)
967 recurred_enddate = recurred_startdate + delta_date_len
968
969 new_startdate = formatdateobject(recurred_startdate)
970 new_enddate = formatdateobject(recurred_enddate)
971
972 if int(new_startdate) > dateto or (cur_event['recur_until'] and int(cur_event['recur_until']) < int(new_startdate)):
973 break
974
975 clone_num += 1
976 clone_id = 'c%d' % clone_num
977
978 events[clone_id] = cur_event.copy()
979 events[clone_id]['id'] = clone_id
980 events[clone_id]['startdate'] = new_startdate
981 events[clone_id]['enddate'] = new_enddate
982 events[clone_id]['clone'] = 1
983
984 insertcalevents(cal_events, datefrom, dateto, clone_id, new_startdate, new_enddate)
985
986 elif cur_event['recur_type'] == 'year':
987
988 ryear, rmonth, rday = getdatefield(cur_event['startdate'])
989 cyear, cmonth, cday = getdatefield(str(datefrom))
990
991 while 1:
992
993 ryear += recur_freq
994 new_startdate = formatDate(ryear, rmonth, rday)
995
996 if int(new_startdate) < int(datefrom):
997 continue
998
999 if int(new_startdate) > dateto or (cur_event['recur_until'] and int(cur_event['recur_until']) < int(new_startdate)):
1000 break
1001
1002 recurred_startdate = datetime.date(ryear, rmonth, rday)
1003 recurred_enddate = recurred_startdate + delta_date_len
1004
1005 new_startdate = formatdateobject(recurred_startdate)
1006 new_enddate = formatdateobject(recurred_enddate)
1007
1008 clone_num += 1
1009 clone_id = 'c%d' % clone_num
1010
1011 events[clone_id] = cur_event.copy()
1012 events[clone_id]['id'] = clone_id
1013 events[clone_id]['startdate'] = new_startdate
1014 events[clone_id]['enddate'] = new_enddate
1015 events[clone_id]['clone'] = 1
1016
1017 insertcalevents(cal_events, datefrom, dateto, clone_id, new_startdate, new_enddate)
1018
1019 else:
1020
1021 if not (int(cur_event['enddate']) < datefrom or int(cur_event['startdate']) > dateto):
1022 events[e_id] = cur_event.copy()
1023 insertcalevents(cal_events, datefrom, dateto, e_id, cur_event['startdate'], cur_event['enddate'])
1024
1025 # sort cal_events
1026 # store event list into global variables in order to sort them
1027 Globs.events = events
1028
1029 for eachdate in cal_events.keys():
1030 cal_events[eachdate].sort(comp_cal_events)
1031
1032 # cache update
1033 if not nocache:
1034 cache_filteredevents.update(pickle.dumps(events, PICKLE_PROTOCOL))
1035 cache_calevents.update(pickle.dumps(cal_events, PICKLE_PROTOCOL))
1036
1037 else:
1038 events = raw_events
1039
1040 debug(u'Total %d of events are loaded finally.' % len(events))
1041
1042 #debug('Events:')
1043 #for key in events.keys():
1044 # debug('__ %s' % events[key])
1045
1046 return events, cal_events
1047
1048
1049
1050 def loadEventsFromWikiPages():
1051
1052 events = {}
1053
1054 eventrecord_list = []
1055 eventpages = []
1056
1057 request = Globs.request
1058 category = Params.category
1059
1060 # cache configurations
1061 arena = Page(request, Globs.pagename)
1062 eventkey = 'events'
1063 pagelistkey = 'eventpages'
1064
1065 cache_events = caching.CacheEntry(request, arena, eventkey)
1066 cache_pages = caching.CacheEntry(request, arena, pagelistkey)
1067
1068
1069 # page list cache
1070
1071 debug('Checking page list cache')
1072
1073 # check the time at which page list cache has been created
1074
1075 cp_mtime = cache_pages.mtime()
1076 timedelta_days = 9999
1077
1078 if cp_mtime:
1079 cp_date = datetime.datetime.fromtimestamp(cp_mtime)
1080 today = datetime.datetime.fromtimestamp(time.time())
1081 datediff = today - cp_date
1082 timedelta_days = datediff.days
1083 debug('Time from page list cache built = %s' % datediff)
1084
1085
1086 if Globs.page_action == 'refresh' or cache_pages.needsUpdate(arena._text_filename()) or timedelta_days >= 1:
1087 categorypages = searchPages(request, category)
1088 for page in categorypages:
1089 eventpages.append(page.page_name)
1090 cache_pages.update('\n'.join(eventpages), True)
1091 debug('New page list is built: %d pages' % len(eventpages))
1092 else:
1093 eventpages = cache_pages.content(True).split('\n')
1094 debug('Cached page list is used: %d pages' % len(eventpages))
1095
1096
1097 # generating events
1098
1099 e_num = 0
1100 dirty = 0
1101 debug_records = {}
1102
1103 # fetch event records from each page in the category
1104 for page_name in eventpages:
1105
1106 p = Page(request, page_name)
1107 e_ref = page_name
1108
1109 eventrecordkey = 'eventrecords'
1110 cache_eventrecords = caching.CacheEntry(request, p, eventrecordkey)
1111
1112 if cache_eventrecords.needsUpdate(p._text_filename()) or Globs.page_action == 'refresh':
1113 dirty = 1
1114 page_content = p.get_raw_body()
1115 eventrecords, e_num = getEventRecordFromPage(page_content, e_ref, e_num)
1116 debug_records[e_ref] = '%d eventrecords are fetched from %s' % (len(eventrecords), e_ref)
1117 cache_eventrecords.update(pickle.dumps(eventrecords, PICKLE_PROTOCOL))
1118 else:
1119 try:
1120 eventrecords = pickle.loads(cache_eventrecords.content())
1121 debug_records[e_ref] = '%d cached eventrecords are used from %s' % (len(eventrecords), e_ref)
1122 except (pickle.UnpicklingError, IOError, EOFError, ValueError):
1123 dirty = 1
1124 page_content = p.get_raw_body()
1125 eventrecords, e_num = getEventRecordFromPage(page_content, e_ref, e_num)
1126 debug_records[e_ref] = '%d eventrecords are fetched from %s due to pickle error' % (len(eventrecords), e_ref)
1127 cache_eventrecords.update(pickle.dumps(eventrecords, PICKLE_PROTOCOL))
1128
1129 eventrecord_list.append(eventrecords)
1130
1131 # if no dirty, just fetch the cache
1132 if not (dirty or Globs.page_action == 'refresh'):
1133
1134 debug('Checking event cache: still valid')
1135
1136 try:
1137 events = pickle.loads(cache_events.content())
1138 debug('Cached event information is used: total %d events' % len(events))
1139 except (pickle.UnpicklingError, IOError, EOFError, ValueError):
1140 debug('Picke error at fetching cached events')
1141 events = {}
1142
1143 else:
1144
1145 debug('Checking event cache: it\'s dirty or requested to refresh')
1146
1147 # if there is no events (if it needs refreshed), generate events dictionary
1148 if not len(events.keys()):
1149
1150 # XXX: just debugging
1151 debug('Bulding new event information')
1152 for page_name in eventpages:
1153 debug(debug_records[page_name])
1154
1155
1156 day_delta = datetime.timedelta(days=1)
1157
1158 for eventrecords in eventrecord_list:
1159
1160 for evtrecord in eventrecords:
1161
1162 e_id = evtrecord['id']
1163
1164 # generating events
1165 events[e_id] = evtrecord
1166 #debug('event %s: %s' % (evtrecord['id'], evtrecord))
1167
1168 # after generating updated events, update the cache
1169 cache_events.update(pickle.dumps(events, PICKLE_PROTOCOL))
1170
1171 debug('Event information is newly built: total %d events' % len(events))
1172
1173 # end of updating events block
1174
1175
1176 return events
1177
1178
1179
1180 def getEventRecordFromPage(pagecontent, referpage, e_num):
1181
1182 request = Globs.request
1183
1184 eventrecords = []
1185 page_bgcolor = ''
1186 page_description = ''
1187
1188 # fetch the page default bgcolor
1189 regex_page_bgcolor = r"""
1190 ^\s+default_bgcolor::\s*
1191 (?P<pagebgcolor>\#[0-9a-fA-F]{6})
1192 \s*
1193 $
1194 """
1195
1196 pattern = re.compile(regex_page_bgcolor, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1197 match = pattern.search(pagecontent)
1198
1199 if match:
1200 page_bgcolor = match.group('pagebgcolor')
1201
1202 # fetch the page default description
1203 regex_page_description = r"""
1204 ^\s+default_description::\s*
1205 (?P<pagedescription>.*?)
1206 $
1207 """
1208
1209 pattern = re.compile(regex_page_description, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1210 match = pattern.search(pagecontent)
1211
1212 if match:
1213 page_description = match.group('pagedescription')
1214
1215
1216 # fetch event item
1217 regex_eventitem = r"""
1218 (?P<eventitem>
1219 (?P<heading>^\s*(?P<hmarker>=+)\s(?P<eventtitle>.*?)\s(?P=hmarker) $)
1220 (?P<eventdetail>.*?
1221 (?=
1222 ^\s*(?P<nexthmarker>=+)\s(?P<nexteventtitle>.*?)\s(?P=nexthmarker) $
1223 | \Z
1224 )
1225 )
1226 )
1227 """
1228
1229 pattern = re.compile(regex_eventitem, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1230 match = pattern.findall(pagecontent)
1231
1232 if match:
1233
1234 for matchitem in match:
1235
1236 eventitem = {}
1237
1238 eventtitle = matchitem[3]
1239 eventdetail = matchitem[4]
1240
1241 try:
1242 e_start_date, e_start_time, e_end_date, e_end_time, e_bgcolor, e_description, e_recur_freq, e_recur_type, e_recur_until = geteventfield(eventdetail)
1243 except (TypeError, ValueError):
1244 #debug('An event data is corrupted: invalid event format')
1245 continue
1246
1247 # set default values
1248 if not e_bgcolor:
1249 e_bgcolor = page_bgcolor
1250
1251 if not e_description:
1252 e_description = page_description
1253
1254 e_num += 1
1255 e_id = 'e%d' % e_num
1256
1257 eventitem['id'] = e_id
1258 eventitem['title'] = eventtitle
1259 eventitem['startdate'] = e_start_date
1260 eventitem['starttime'] = e_start_time
1261 eventitem['enddate'] = e_end_date
1262 eventitem['endtime'] = e_end_time
1263 eventitem['title'] = eventtitle
1264 eventitem['refer'] = referpage
1265 eventitem['bgcolor'] = e_bgcolor
1266 eventitem['description'] = e_description
1267 eventitem['recur_freq'] = e_recur_freq
1268 eventitem['recur_type'] = e_recur_type
1269 eventitem['recur_until'] = e_recur_until
1270
1271 eventitem['date_len'] = diffday(e_start_date, e_end_date) + 1
1272 eventitem['clone'] = 0
1273 eventitem['hid'] = getheadingid(request, referpage, eventtitle)
1274
1275 eventrecords.append(eventitem)
1276
1277 #debug('matched records: %d' % len(match))
1278
1279 return eventrecords, e_num
1280
1281
1282
1283 def geteventfield(detail):
1284
1285 regex_startdate = r"""
1286 ^\s+start::\s*
1287 (?P<startdate>\d{4}[/-]\d{2}[/-]\d{2})
1288 \s*
1289 (?P<starttime>\d{1,2}[:]?\d{0,2}([AP][M]?)?)*
1290 \s*
1291 $
1292 """
1293
1294 regex_enddate = r"""
1295 ^\s+end::\s*
1296 (?P<enddate>\d{4}[/-]\d{2}[/-]\d{2})*
1297 \s*
1298 (?P<endtime>\d{1,2}[:]?\d{0,2}([AP][M]?)?)*
1299 \s*
1300 $
1301 """
1302
1303 regex_bgcolor = r"""
1304 ^\s+bgcolor::\s*
1305 (?P<bgcolor>\#[0-9a-fA-F]{6})
1306 \s*
1307 $
1308 """
1309
1310 regex_description = r"""
1311 ^\s+description::\s*
1312 (?P<description>.*?)
1313 $
1314 """
1315
1316 regex_recur = r"""
1317 ^\s+recur::\s*
1318 (?P<recur_freq>\d+)
1319 \s*
1320 (?P<recur_type>day|week|weekday|month|year)
1321 \s*
1322 (
1323 until
1324 \s*
1325 (?P<recur_until>\d{4}[/-]\d{2}[/-]\d{2})
1326 )*
1327 $
1328 """
1329
1330 # need help on regular expressions for more efficient/flexible form
1331
1332 # compile regular expression objects
1333
1334 pattern_startdate = re.compile(regex_startdate, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1335 pattern_enddate = re.compile(regex_enddate, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1336 pattern_bgcolor = re.compile(regex_bgcolor, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1337 pattern_description = re.compile(regex_description, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1338 pattern_recur = re.compile(regex_recur, re.UNICODE + re.MULTILINE + re.IGNORECASE + re.DOTALL + re.VERBOSE)
1339
1340 ##################### retrieve startdate
1341 match = pattern_startdate.search(detail)
1342
1343 if match:
1344 startdate = match.group('startdate')
1345 starttime = match.group('starttime')
1346 else:
1347 startdate = ''
1348 starttime = ''
1349
1350 ##################### retrieve enddate
1351 match = pattern_enddate.search(detail)
1352
1353 if match:
1354 enddate = match.group('enddate')
1355 endtime = match.group('endtime')
1356 else:
1357 enddate = ''
1358 endtime = ''
1359
1360 ##################### retrieve bgcolor
1361 match = pattern_bgcolor.search(detail)
1362
1363 if match:
1364 bgcolor = match.group('bgcolor')
1365 else:
1366 bgcolor = ''
1367
1368 ##################### retrieve description
1369 match = pattern_description.search(detail)
1370
1371 if match:
1372 description = match.group('description')
1373 else:
1374 description = ''
1375
1376 ##################### retrieve recurrence
1377 match = pattern_recur.search(detail)
1378
1379 if match:
1380 recur_freq = int(match.group('recur_freq'))
1381 recur_type = match.group('recur_type')
1382 recur_until = match.group('recur_until')
1383
1384 else:
1385 recur_freq = 0
1386 recur_type = ''
1387 recur_until = ''
1388
1389
1390 # check validity of each fields
1391
1392 if not startdate:
1393 #debug('start date is not specified')
1394 # self.printoutput('Parse Error', msg, '')
1395 # ERROR
1396 return '','','','','','','','','',''
1397
1398 if (endtime) and not (starttime):
1399 #debug('endtime without starttime')
1400 # ERROR
1401 return '','','','','','','','','',''
1402
1403 # if no time, it's 1-day event
1404 if not enddate:
1405 enddate = startdate
1406
1407 try:
1408 syear, smonth, sday = getdatefield(startdate)
1409 eyear, emonth, eday = getdatefield(enddate)
1410 except (TypeError, ValueError):
1411 #debug('invalid date format: %s, %s' % (startdate, enddate))
1412 return '','','','','','','','','',''
1413
1414 if datetime.date(syear, smonth, sday) > datetime.date(eyear, emonth, eday):
1415 #debug('startdate should precede enddate')
1416 return '','','','','','','','','',''
1417
1418 # format date
1419 startdate = formatDate(syear, smonth, sday)
1420 enddate = formatDate(eyear, emonth, eday)
1421
1422 if (starttime and endtime):
1423 try:
1424 shour, smin = gettimefield(starttime)
1425 ehour, emin = gettimefield(endtime)
1426 except (TypeError, ValueError):
1427 #debug('invalid time format: %s, %s' % (startdate, enddate))
1428 return '','','','','','','','','',''
1429
1430 if startdate == enddate:
1431 if datetime.time(shour, smin) > datetime.time(ehour, emin):
1432 #debug('starttime should precede endtime')
1433 return '','','','','','','','','',''
1434
1435 # format time
1436 starttime = u'%02d%02d' %(shour, smin)
1437 endtime = u'%02d%02d' %(ehour, emin)
1438 elif (starttime):
1439 try:
1440 shour, smin = gettimefield(starttime)
1441 except (TypeError, ValueError):
1442 #debug('invalid time format: %s, %s' % (startdate, enddate))
1443 return '','','','','','','','','',''
1444
1445 starttime = u'%02d%02d' %(shour, smin)
1446 endtime = u''
1447
1448 # check recurrent data
1449 event_len = diffday(startdate, enddate)
1450 if recur_freq:
1451
1452 if recur_type == 'day':
1453 if event_len > int(recur_freq):
1454 debug('event length should be smaller than recurrence interval')
1455 return '','','','','','','','','',''
1456
1457 elif recur_type == 'week':
1458 if event_len > int(recur_freq) * 7:
1459 debug('event length should be smaller than recurrence interval')
1460 return '','','','','','','','','',''
1461
1462 elif recur_type == 'weekday':
1463 if event_len > 25:
1464 debug('event length should be smaller than recurrence interval')
1465 return '','','','','','','','','',''
1466
1467 elif recur_type == 'month':
1468 if event_len > int(recur_freq) * 25:
1469 debug('event length should be smaller than recurrence interval')
1470 return '','','','','','','','','',''
1471
1472 elif recur_type == 'year':
1473 if event_len > int(recur_freq) * 365:
1474 debug('event length should be smaller than recurrence interval')
1475 return '','','','','','','','','',''
1476
1477 if recur_until:
1478 try:
1479 ryear, rmonth, rday = getdatefield(recur_until)
1480 except (TypeError, ValueError):
1481 debug('invalid date format: %s' % recur_until)
1482 return '','','','','','','','','',''
1483
1484 recur_until = formatDate(ryear, rmonth, rday)
1485
1486 if int(recur_until) < int(enddate):
1487 debug('recur_until should precede enddate')
1488 return '','','','','','','','','',''
1489
1490
1491 return startdate, starttime, enddate, endtime, bgcolor, description, recur_freq, recur_type, recur_until
1492
1493
1494
1495 def converttext(targettext):
1496 # Converts some special characters of html to plain-text style
1497 # What else to handle?
1498
1499 targettext = targettext.replace(u'&', '&')
1500 targettext = targettext.replace(u'>', '>')
1501 targettext = targettext.replace(u'<', '<')
1502 targettext = targettext.replace(u'\n', '<br>')
1503 targettext = targettext.replace(u'"', '"')
1504 targettext = targettext.replace(u'\t', '  ')
1505 targettext = targettext.replace(u' ', ' ')
1506
1507 return targettext
1508
1509
1510 # monthly view
1511 def showeventcalendar(year, month):
1512
1513 debug('Show Calendar: Monthly View')
1514
1515 request = Globs.request
1516 formatter = Globs.formatter
1517 _ = request.getText
1518
1519 wkend = Globs.wkend
1520 months= Globs.months
1521 wkdays = Globs.wkdays
1522
1523 # get the calendar
1524 monthcal = calendar.monthcalendar(year, month)
1525
1526 # shows current year & month
1527 html_header_curyearmonth = calhead_yearmonth(year, month, 'head_yearmonth')
1528
1529 r7 = range(7)
1530
1531 # shows header of week days
1532 html_header_weekdays = []
1533
1534 for wkday in r7:
1535 wday = _(wkdays[wkday])
1536 html_header_weekdays.append( calhead_weekday(wday, 'head_weekday') )
1537 html_header_weekdays = ' <tr>\r\n%s\r\n</tr>\r\n' % u'\r\n'.join(html_header_weekdays)
1538
1539 # pending events for next row
1540 next_pending = []
1541
1542 # gets previous, next month
1543 day_delta = datetime.timedelta(days=-1)
1544 cur_month = datetime.date(year, month, 1)
1545 prev_month = cur_month + day_delta
1546
1547 day_delta = datetime.timedelta(days=15)
1548 cur_month_end = datetime.date(year, month, 25)
1549 next_month = cur_month_end + day_delta
1550
1551 prev_monthcal = calendar.monthcalendar(prev_month.year, prev_month.month)
1552 next_monthcal = calendar.monthcalendar(next_month.year, next_month.month)
1553
1554 # shows days
1555 html_week_rows = []
1556
1557 # set ranges of events
1558 datefrom = u'%04d%02d21' % (prev_month.year, prev_month.month)
1559 dateto = u'%04d%02d06' % (next_month.year, next_month.month)
1560
1561 # read all the events
1562 events, cal_events = loadEvents(datefrom, dateto)
1563
1564 #debug(u' events: %s' % events)
1565 #debug(u' cal_events: %s' % cal_events)
1566
1567 for week in monthcal:
1568
1569 # day head rows
1570 html_headday_cols = []
1571 html_events_rows = []
1572
1573 for wkday in r7:
1574
1575 day = week[wkday]
1576
1577 if not day:
1578 if week == monthcal[0]:
1579 nb_day = prev_monthcal[-1][wkday]
1580 else:
1581 nb_day = next_monthcal[0][wkday]
1582
1583 html_headday_cols.append( calhead_day_nbmonth(nb_day) )
1584 else:
1585 html_headday_cols.append( calhead_day(year, month, day, wkday) )
1586
1587 html_headday_row = ' <tr>\r\n%s\r\n</tr>\r\n' % u'\r\n'.join(html_headday_cols)
1588 html_week_rows.append(html_headday_row)
1589
1590 # dummy rows
1591 html_headdummy_cols = []
1592
1593 for wkday in r7:
1594 day = week[wkday]
1595 if not day:
1596 html_headdummy_cols.append( calshow_blankbox('head_dummy_nbmonth') )
1597 else:
1598 html_headdummy_cols.append( calshow_blankbox('head_dummy') )
1599
1600 html_headdummy_cols = u'\r\n'.join(html_headdummy_cols)
1601 html_week_rows.append(' <tr>\r\n%s </tr>\r\n' % html_headdummy_cols)
1602
1603 # pending events for next row
1604 pending = next_pending
1605 next_pending = []
1606
1607 # show events
1608 while 1:
1609 event_left = 7
1610 colspan = -1
1611 html_events_cols = []
1612
1613 for wkday in r7:
1614
1615 day = week[wkday]
1616
1617 if not day:
1618 if week == monthcal[0]:
1619 cur_date = formatDate(prev_month.year, prev_month.month, prev_monthcal[-1][wkday])
1620 else:
1621 cur_date = formatDate(next_month.year, next_month.month, next_monthcal[0][wkday])
1622 else:
1623 cur_date = formatDate(year, month, day)
1624
1625 # if an event is already displayed with colspan
1626 if colspan > 0:
1627 colspan -= 1
1628 if cal_events.has_key(cur_date) and lastevent in cal_events[cur_date]:
1629 cal_events[cur_date].remove(lastevent)
1630
1631 continue
1632
1633 # if there is any event for this date
1634 if cal_events.has_key(cur_date):
1635 if len(cal_events[cur_date]) > 0:
1636
1637 # if there is any pending event in the previous week
1638 if wkday == 0 and len(pending) > 0:
1639 todo_event_id = pending.pop(0)
1640 if todo_event_id in cal_events[cur_date]:
1641 cur_event = events[todo_event_id]
1642 temp_len = diffday(cur_date, cur_event['enddate']) + 1
1643
1644 # calculate colspan value
1645 if (7-wkday) < temp_len:
1646 colspan = 7 - wkday
1647 next_pending.append(cur_event['id'])
1648 html_events_cols.append( calshow_eventbox(cur_event, colspan, 'append_pending', cur_date) )
1649
1650 else:
1651 colspan = temp_len
1652 html_events_cols.append( calshow_eventbox(cur_event, colspan, 'append', cur_date) )
1653
1654
1655 cal_events[cur_date].remove(todo_event_id)
1656
1657 colspan -= 1
1658 lastevent = todo_event_id
1659 else:
1660 debug('Warning: no such event in cal_events')
1661
1662 continue
1663
1664 # if there is no pending event in the previous week, start a new event
1665 event_found = 0
1666 for e_id in cal_events[cur_date]:
1667
1668 # if the start date of the event is current date
1669 if events[e_id]['startdate'] == cur_date:
1670
1671 cur_event = events[cal_events[cur_date].pop(cal_events[cur_date].index(e_id))]
1672
1673 # calculate colspan value
1674 if (7-wkday) < cur_event['date_len']:
1675 colspan = 7 - wkday
1676 next_pending.append(cur_event['id'])
1677 html_events_cols.append( calshow_eventbox(cur_event, colspan, 'pending', cur_date) )
1678
1679 else:
1680 colspan = cur_event['date_len']
1681 html_events_cols.append( calshow_eventbox(cur_event, colspan, '', cur_date) )
1682
1683 colspan -= 1
1684 lastevent = cur_event['id']
1685 event_found = 1
1686 break
1687
1688 # if the start date of the event is NOT current date
1689 else:
1690
1691 # pending event from previous month
1692 if wkday == 0 and week == monthcal[0]:
1693
1694 cur_event = events[cal_events[cur_date].pop(0)]
1695 temp_len = diffday(cur_date, cur_event['enddate']) + 1
1696
1697 # calculate colspan value
1698 if (7-wkday) < temp_len:
1699 colspan = 7 - wkday
1700 next_pending.append(cur_event['id'])
1701 html_events_cols.append( calshow_eventbox(cur_event, colspan, 'append_pending', cur_date) )
1702 else:
1703 colspan = temp_len
1704 html_events_cols.append( calshow_eventbox(cur_event, colspan, 'append', cur_date) )
1705
1706 colspan -= 1
1707 lastevent = cur_event['id']
1708 event_found = 1
1709 break
1710
1711 # if there is no event to start
1712 if not event_found:
1713 if not day:
1714 html_events_cols.append( calshow_blankbox('cal_nbmonth') )
1715 else:
1716 html_events_cols.append( calshow_blankbox('cal_noevent') )
1717 event_left -= 1
1718
1719 else:
1720 if not day:
1721 html_events_cols.append( calshow_blankbox('cal_nbmonth') )
1722 else:
1723 html_events_cols.append( calshow_blankbox('cal_noevent') )
1724
1725 event_left -= 1
1726
1727 # if there is NO event for this date
1728 else:
1729 if not day:
1730 html_events_cols.append( calshow_blankbox('cal_nbmonth') )
1731 else:
1732 html_events_cols.append( calshow_blankbox('cal_noevent') )
1733
1734 event_left -= 1
1735
1736 # if no event for this entry
1737 if not event_left:
1738 # ignore the previous entry
1739 break
1740 else:
1741 html_events_rows.append(' <tr>\r\n%s </tr>\r\n' % u'\r\n'.join(html_events_cols))
1742
1743 # show dummy blank slots for week height
1744 left_blank_rows = 2 - len(html_events_rows)
1745
1746 # remove the followings
1747 if left_blank_rows > 0 and 0:
1748 for i in range(left_blank_rows):
1749 html_events_cols = []
1750 for wkday in r7:
1751 day = week[wkday]
1752 if not day:
1753 html_events_cols.append( calshow_blankbox('cal_nbmonth') )
1754 else:
1755 html_events_cols.append( calshow_blankbox('cal_noevent') )
1756
1757 html_events_rows.append(' <tr>\r\n%s </tr>\r\n' % u'\r\n'.join(html_events_cols))
1758
1759
1760 # close the week slots
1761 html_events_cols = []
1762 for wkday in r7:
1763 day = week[wkday]
1764 if not day:
1765 html_events_cols.append( calshow_blankbox('cal_last_nbmonth') )
1766 else:
1767 html_events_cols.append( calshow_blankbox('cal_last_noevent') )
1768
1769 html_events_rows.append(' <tr>\r\n%s </tr>\r\n' % u'\r\n'.join(html_events_cols))
1770
1771 html_events_rows = u'\r\n'.join(html_events_rows)
1772 html_week_rows.append(html_events_rows)
1773
1774 html_calendar_rows = u'\r\n'.join(html_week_rows)
1775
1776 html_cal_table = [
1777 u'\r\n<div id="eventcalendar">',
1778 u'<table class="eventcalendar" %s>' % Params.monthlywidth,
1779 u'%s' % html_header_curyearmonth,
1780 u'%s' % html_header_weekdays,
1781 u'%s' % html_calendar_rows,
1782 u'</table>',
1783 u'</div>',
1784 ]
1785 html_cal_table = u'\r\n'.join(html_cal_table)
1786
1787 return html_cal_table
1788
1789 # simple view
1790 def showsimpleeventcalendar(year, month):
1791
1792 debug('Show Calendar: Simple View')
1793
1794 request = Globs.request
1795 formatter = Globs.formatter
1796 _ = request.getText
1797
1798 wkend = Globs.wkend
1799 months= Globs.months
1800 wkdays = Globs.wkdays
1801
1802 # get the calendar
1803 monthcal = calendar.monthcalendar(year, month)
1804
1805 # shows current year & month
1806 html_header_curyearmonth = calhead_yearmonth(year, month, 'simple_yearmonth')
1807
1808 r7 = range(7)
1809
1810 # shows header of week days
1811 html_header_weekdays = []
1812
1813 for wkday in r7:
1814 wday = wkdays[wkday]
1815 html_header_weekdays.append( calhead_weekday(wday, 'simple_weekday') )
1816 html_header_weekdays = ' <tr>\r\n%s\r\n</tr>\r\n' % u'\r\n'.join(html_header_weekdays)
1817
1818 # gets previous, next month
1819 day_delta = datetime.timedelta(days=-1)
1820 cur_month = datetime.date(year, month, 1)
1821 prev_month = cur_month + day_delta
1822
1823 day_delta = datetime.timedelta(days=15)
1824 cur_month_end = datetime.date(year, month, 25)
1825 next_month = cur_month_end + day_delta
1826
1827 prev_monthcal = calendar.monthcalendar(prev_month.year, prev_month.month)
1828 next_monthcal = calendar.monthcalendar(next_month.year, next_month.month)
1829
1830 # shows days
1831 html_week_rows = []
1832
1833 # set ranges of events
1834 datefrom = u'%04d%02d21' % (prev_month.year, prev_month.month)
1835 dateto = u'%04d%02d06' % (next_month.year, next_month.month)
1836
1837 # read all the events
1838 events, cal_events = loadEvents(datefrom, dateto)
1839
1840 for week in monthcal:
1841
1842 # day head rows
1843 html_headday_cols = []
1844 html_events_rows = []
1845
1846 for wkday in r7:
1847
1848 day = week[wkday]
1849
1850 if not day:
1851 if week == monthcal[0]:
1852 nb_day = prev_monthcal[-1][wkday]
1853 else:
1854 nb_day = next_monthcal[0][wkday]
1855
1856 html_headday_cols.append( simple_eventbox(year, month, day, nb_day, 'simple_nb') )
1857 else:
1858 cur_date = formatDate(year, month, day)
1859 if cal_events.has_key(cur_date):
1860 html_headday_cols.append( simple_eventbox(year, month, day, wkday, 'simple_event') )
1861 else:
1862 html_headday_cols.append( simple_eventbox(year, month, day, wkday, 'simple_noevent') )
1863
1864 html_headday_row = ' <tr>\r\n%s\r\n</tr>\r\n' % u'\r\n'.join(html_headday_cols)
1865 html_week_rows.append(html_headday_row)
1866
1867 html_calendar_rows = u'\r\n'.join(html_week_rows)
1868
1869 html_cal_table = [
1870 u'\r\n<div id="eventcalendar">',
1871 u'<table class="simplecalendar" %s>' % Params.simplewidth,
1872 u'%s' % html_header_curyearmonth,
1873 u'%s' % html_header_weekdays,
1874 u'%s' % html_calendar_rows,
1875 u'</table>',
1876 u'</div>',
1877 ]
1878 html_cal_table = u'\r\n'.join(html_cal_table)
1879
1880 return html_cal_table
1881
1882
1883 # show weekday
1884 def calhead_yearmonth(year, month, headclass):
1885
1886 months = Globs.months
1887 monthstyle_us = Globs.month_style_us
1888 cal_action = Globs.cal_action
1889 page_name = Globs.pagename
1890
1891 nextyear, nextmonth = yearmonthplusoffset(year, month, 1)
1892 prevyear, prevmonth = yearmonthplusoffset(year, month, -1)
1893
1894 prevlink = u'%s?calaction=%s&caldate=%d%02d' % (page_name, cal_action, prevyear, prevmonth)
1895 nextlink = u'%s?calaction=%s&caldate=%d%02d' % (page_name, cal_action, nextyear, nextmonth)
1896 curlink = u'%s?calaction=%s&caldate=%d%02d' % (page_name, cal_action, year, month)
1897
1898 if monthstyle_us:
1899 stryearmonth = u'%s %d' % (months[month-1], year)
1900 strnextmonth = u'%s %d' % (months[nextmonth-1], nextyear)
1901 strprevmonth = u'%s %d' % (months[prevmonth-1], prevyear)
1902 else:
1903 stryearmonth = u'%d / %02d' % (year, month)
1904 strnextmonth = u'%d / %02d' % (nextyear, nextmonth)
1905 strprevmonth = u'%d / %02d' % (prevyear, prevmonth)
1906
1907 html = [
1908 u' <tr>',
1909 u' <td class="%s"><a href="%s" title="%s"><</a></td>' % (headclass, prevlink, strprevmonth),
1910 u' <td colspan="5" class="%s"><a href="%s" title="Refresh">%s</a></td>' % (headclass, curlink, stryearmonth),
1911 u' <td class="%s"><a href="%s" title="%s">></a></td>' % (headclass, nextlink, strnextmonth),
1912 u' </tr>',
1913 ]
1914
1915 return u'\r\n'.join(html)
1916
1917 # show days in simple
1918 def simple_eventbox(year, month, day, wkday, boxclass):
1919 wkend = Globs.wkend
1920 if wkday == wkend:
1921 html_text = u'<font color="#aa7744">%s</font>' % day
1922 else:
1923 html_text = u'%s' % day
1924
1925 cyear, cmonth, cday = gettodaydate()
1926
1927 if boxclass == 'simple_nb':
1928 html = u' <td class="%s"> </td>\r\n' % boxclass
1929 else:
1930 if cyear == year and cmonth == month and cday == day:
1931 html = u' <td class="%s_today">%s</td>\r\n' % (boxclass, html_text)
1932 else:
1933 html = u' <td class="%s">%s</td>\r\n' % (boxclass, html_text)
1934
1935 return html
1936
1937
1938 # show weekday
1939 def calhead_weekday(wday, headclass):
1940 if headclass == 'simple_weekday':
1941 html = u' <td class="%s">%s</td>\r\n' % (headclass, wday[0])
1942 else:
1943 html = u' <td class="%s">%s</td>\r\n' % (headclass, wday)
1944
1945 return html
1946
1947
1948 # show days of current month
1949 def calhead_day(year, month, day, wkday):
1950 wkend = Globs.wkend
1951 if wkday == wkend:
1952 html_text = u'<font color="#FF3300">%s</font>' % day
1953 else:
1954 html_text = u'%s' % day
1955
1956 cyear, cmonth, cday = gettodaydate()
1957
1958 if cyear == year and cmonth == month and cday == day:
1959 html = u' <td class="head_day_today"> %s</td>\r\n' % html_text
1960 else:
1961 html = u' <td class="head_day"> %s</td>\r\n' % html_text
1962
1963 return html
1964
1965
1966 # show days of previous or next month
1967 def calhead_day_nbmonth(day):
1968 html = u' <td class="head_day_nbmonth"> %s</td>\r\n' % day
1969 return html
1970
1971
1972 # show blank calendar box
1973 def calshow_blankbox(classname):
1974 html = u' <td class="%s"> </td>' % classname
1975 return html
1976
1977 # show eventbox
1978 def calshow_eventbox(event, colspan, status, cur_date):
1979 if status:
1980 status = u'_%s' % status
1981
1982 title = event['title']
1983 eid = event['id']
1984 startdate = event['startdate']
1985 enddate = event['enddate']
1986 starttime = event['starttime']
1987 endtime = event['endtime']
1988 description = event['description']
1989 bgcolor = event['bgcolor']
1990
1991 year, month, day = getdatefield(cur_date)
1992
1993 if bgcolor:
1994 bgcolor = 'background-color: %s;' % bgcolor
1995 else:
1996 bgcolor = 'background-color: %s;' % Params.bgcolor
1997
1998 if (startdate == enddate) and starttime:
1999 shour, smin = gettimefield(starttime)
2000
2001 link = [
2002 u'<table width="100%%" style="border-width: 0px; padding: 0px; margin: 0px;"><tr>\r\n',
2003 u'<td width="10" nowrap style="border-width: 0px; padding: 0px; margin: 0px; text-align: left; vertical-align: top; font-size: 7pt; color: #000000;">%02d:%02d </td>\r\n' % (shour, smin),
2004 u'<td style="border-width: 0px; padding: 0px; margin: 0px; text-align: left; vertical-align: top;font-size: 8pt;">',
2005 u'%s' % showReferPageParsed(event, 'title', 1),
2006 u'</td>\r\n</tr></table>',
2007 ]
2008 link = u''.join(link)
2009 else:
2010 link = u'%s' % showReferPageParsed(event, 'title', 1)
2011
2012
2013 html = [
2014 u' <td class="cal_eventbox" colspan="%d"><table class="cal_event">' % colspan,
2015 u' <tr><td id="cal_event_%s" class="cal_event%s" style="%s">%s</td></tr>' % (eid, status, bgcolor, link),
2016 u' </table></td>',
2017 ]
2018
2019 return u'\r\n'.join(html)
2020
2021
2022 def insertcalevents(cal_events, datefrom, dateto, e_id, e_start_date, e_end_date):
2023
2024
2025 if not (int(e_start_date) > dateto or int(e_end_date) < datefrom):
2026
2027 e_start_date = str(max(int(e_start_date), datefrom))
2028 e_end_date = str(min(int(e_end_date), dateto))
2029
2030 day_delta = datetime.timedelta(days=1)
2031 e_start_year, e_start_month, e_start_day = getdatefield(e_start_date)
2032 cur_datetime = datetime.date(e_start_year, e_start_month, e_start_day)
2033
2034 while 1:
2035 tmp_record_date = formatdateobject(cur_datetime)
2036
2037 if not cal_events.has_key(tmp_record_date):
2038 cal_events[tmp_record_date] = []
2039 cal_events[tmp_record_date].append(e_id)
2040
2041 if tmp_record_date == e_end_date:
2042 break
2043
2044 cur_datetime = cur_datetime + day_delta
2045
2046
2047 # date format should be like '20051004' for 2005, Oct., 04
2048 def diffday(date1, date2):
2049
2050 try:
2051 year1, month1, day1 = getdatefield(date1)
2052 year2, month2, day2 = getdatefield(date2)
2053 tmp_diff = datetime.date(year2, month2, day2) - datetime.date(year1, month1, day1)
2054 except (TypeError, ValueError):
2055 debug('An event data is corrupted: invalid date format')
2056 return 0
2057
2058 return tmp_diff.days
2059
2060
2061 def formatDate(year, month, day):
2062 # returns like: '20051004'
2063 return u'%4d%02d%02d' % (year, month, day)
2064
2065 def formatdateobject(obj_date):
2066
2067 return formatDate(obj_date.year, obj_date.month, obj_date.day)
2068
2069
2070 def cliprgb(r,g,b): # don't use 255!
2071 if r < 0: r=0
2072 if r > 254: r=254
2073 if b < 0: b=0
2074 if b > 254: b=254
2075 if g < 0: g=0
2076 if g > 254: g=254
2077 return r, g, b
2078
2079
2080 def debug(astring):
2081 Globs.debugmsg += u'<li>%s\n' % astring
2082
2083
2084 def yearmonthplusoffset(year, month, offset):
2085 month = month+offset
2086 # handle offset and under/overflows - quick and dirty, yes!
2087 while month < 1:
2088 month = month + 12
2089 year = year - 1
2090 while month > 12:
2091 month = month - 12
2092 year = year + 1
2093 return year, month
2094
2095
2096 def formatcfgdatetime(strdate, strtime=''):
2097
2098 if not strdate:
2099 return ''
2100
2101 request = Globs.request
2102
2103 if request.user.date_fmt:
2104 date_fmt = request.user.date_fmt
2105 else:
2106 date_fmt = request.cfg.date_fmt
2107
2108 if request.user.datetime_fmt:
2109 datetime_fmt = request.user.datetime_fmt
2110 else:
2111 datetime_fmt = request.cfg.datetime_fmt
2112
2113 ## XXX HACK
2114 datetime_fmt = datetime_fmt.replace(':%S', '')
2115
2116 date_fmt = str(date_fmt)
2117 datetime_fmt = str(datetime_fmt)
2118
2119 year, month, day = getdatefield(str(strdate))
2120 if strtime:
2121 hour, min = gettimefield(str(strtime))
2122 objdatetime = datetime.datetime(year, month, day, hour, min)
2123 return objdatetime.strftime(datetime_fmt)
2124 else:
2125 objdate = getdatetimefromstring(strdate)
2126 return objdate.strftime(date_fmt)
2127
2128
2129 def getdatetimefromstring(strdate):
2130 year, month, day = getdatefield(str(strdate))
2131 return datetime.date( year, month, day )
2132
2133
2134 def searchPages(request, needle):
2135 # Search the pages and return the results
2136 query = search.QueryParser().parse_query(needle)
2137 results = search.searchPages(request, query)
2138 #results.sortByPagename()
2139
2140 return results.hits
2141
2142 html = []
2143 for page in results.hits:
2144 html.append(page.page_name)
2145
2146 html = u',<br>'.join(html)
2147 return u'%s<p>%s' % (Params.category, html)
2148
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.