WikiCalendarMacro: WikiCalendarMacro.py

File WikiCalendarMacro.py, 7.4 kB (added by sukhoy, 1 year ago)

A version of WikiCalendarMacro for 0.11dev-r5987

Line 
1 # Copyright (C) 2005 Matthew Good <trac@matt-good.net>
2 # Copyright (C) 2005 Jan Finell <finell@cenix-bioscience.com>
3 #
4 # "THE BEER-WARE LICENSE" (Revision 42):
5 # <trac@matt-good.net> wrote this file.  As long as you retain this notice you
6 # can do whatever you want with this stuff.  If we meet some day, and you think
7 # this stuff is worth it, you can buy me a beer in return.  Matthew Good
8 # (Beer-ware license written by Poul-Henning Kamp
9 #  http://people.freebsd.org/~phk/)
10 #
11 # Author: Matthew Good <trac@matt-good.net>
12 # Month/Year navigation by: Jan Finell <finell@cenix-bioscience.com>
13 # trac 0.11 compatibility by: Vlad Sukhoy <vladimir.sukhoy@gmail.com>
14
15 import time
16 import calendar
17 from cStringIO import StringIO
18 from trac.wiki.api import WikiSystem
19 from trac.wiki.macros import WikiMacroBase
20 from trac.util import *
21
22 # format:
23 #   WikiCalendar([year,month,[showbuttons,[wiki_page_format]]])
24 #
25 #   displays a calendar, the days link to:
26 #     - milestones (day in bold) if there is one on that day
27 #     - a wiki page that has wiki_page_format (if exist)
28 #     - create that wiki page if it does not exist
29 #
30 # arguments:
31 #   year, month = display calendar for month in year ('*' for current year/month)
32 #   showbuttons = true/false, show prev/next buttons
33 #   wiki_page_format = strftime format for wiki pages to display as link
34 #                      (if there is not a milestone placed on that day)
35 #                      (if exist, otherwise link to create page)
36 #                      default is "%Y-%m-%d"
37 #
38 # examples:
39 #     WikiCalendar(2006,07)
40 #     WikiCalendar(2006,07,false)
41 #     WikiCalendar(*,*,true,Meeting-%Y-%m-%d)
42 #     WikiCalendar(2006,07,false,Meeting-%Y-%m-%d)
43
44 def execute(formatter, txt, env):
45     today = time.localtime()
46     # VS: The hdf is gone in 0.11, using request object instead
47     http_param_year = formatter.req.args.get('year', '')
48     http_param_month = formatter.req.args.get('month', '')
49     if txt == "":
50         args = []
51     else:
52         args = txt.split(',', 3)
53    
54     # find out whether use http param, current or macro param year/month
55    
56     if http_param_year == "":
57         # not clicked on a prev or next button
58         if len(args) >= 1 and args[0] <> "*":
59             # year given in macro parameters
60             year = int(args[0])
61         else:
62             # use current year
63             year = today.tm_year
64     else:
65         # year in http params (clicked by user) overrides everything
66         year = int(http_param_year)
67    
68     if http_param_month == "":
69         # not clicked on a prev or next button
70         if len(args) >= 2 and args[1] <> "*":
71             # month given in macro parameters
72             month = int(args[1])
73         else:
74             # use current month
75             month = today.tm_mon
76     else:
77         # month in http params (clicked by user) overrides everything
78         month = int(http_param_month)
79    
80     showbuttons = 1
81     if len(args) >= 3:
82         showbuttons = bool(args[2]=="True" or args[2]=="true" or args[2]=="no" or args[2]=="0")
83        
84     wiki_page_format = "%Y-%m-%d"
85     if len(args) >= 4:
86         wiki_page_format = args[3]
87    
88     curr_day = None
89     if year == today.tm_year and month == today.tm_mon:
90         curr_day = today.tm_mday
91
92     # Can use this to change the day the week starts on, but this
93     # is a system-wide setting
94     #calendar.setfirstweekday(calendar.SUNDAY)
95     cal = calendar.monthcalendar(year, month)
96
97
98     date = [year, month] + [1] * 7
99
100     # url to the current page (used in the navigation links)
101     # VS: hdf is gone in 0.11, using the new "Context" object instead
102     thispageURL = formatter.context.resource_href() # env.href.wiki(hdf.getValue('wiki.page_name', ''))
103     # for the prev/next navigation links
104     prevMonth = month-1
105     prevYear  = year
106     nextMonth = month+1
107     nextYear  = year
108     # check for year change (KISS version)
109     if prevMonth == 0:
110         prevMonth = 12
111         prevYear -= 1
112     if nextMonth == 13:
113         nextMonth = 1
114         nextYear += 1
115
116     # building the output
117     buff = StringIO()
118     buff.write('<table><caption>')
119
120     if showbuttons:
121         # prev month link
122         prevMonthURL = thispageURL+'?month=%d&year=%d' % (prevMonth, prevYear)
123         buff.write('<a href="%s">&lt; </a>' % prevMonthURL)
124        
125     # the caption
126     buff.write(time.strftime('%B %Y', tuple(date)))
127    
128     if showbuttons:
129         # next month link
130         nextMonthURL = thispageURL+'?month=%d&year=%d' % (nextMonth, nextYear)
131         buff.write('<a href="%s"> &gt;</a>' % nextMonthURL)
132        
133     buff.write('</caption>\n<thead><tr align="center">')
134    
135     for day in calendar.weekheader(2).split():
136         buff.write('<th scope="col"><b>%s</b></th>' % day)
137     buff.write('</tr></thead>\n<tbody>\n')
138
139     for row in cal:
140         buff.write('<tr align="right">')
141         for day in row:
142             if not day:
143                 buff.write('<td>&nbsp;</td>')
144             else:
145                 # first check for milestone on that day
146                 db = env.get_db_cnx()
147                 cursor = db.cursor()
148                 # ugly way but i don't know how to set up a struct_time
149                 # (date as single numbers -> string -> time string parser -> struct_time -> mktime -> seconds
150                 duedateString = str(day) + "." + str(month) + "." + str(year)
151                 duedateStruct = time.strptime(duedateString, "%d.%m.%Y")
152                 duedate = time.mktime(duedateStruct)
153                 cursor.execute("SELECT name,due FROM milestone WHERE due=%s", (duedate,))
154                 row = cursor.fetchone()
155                 if row:
156                     # found a milestone
157                     milestone_name = row[0]
158                     url = env.href.milestone(milestone_name)
159                     buff.write('<td%(style)s><b><a href="%(url)s" alt="%(alt)s">%(day)s</a></b></td>' % {
160                             'url': url,
161                             'alt': milestone_name,
162                             'day': day,
163                             'style': day == curr_day and ' style="border: 1px solid #b00;"' or '',
164                             })
165                 else:
166                     # secondly check for wikipage with name specified in 'wiki_page_format'
167                     date[2] = day
168                     wiki = time.strftime(wiki_page_format, tuple(date))
169                     url = env.href.wiki(wiki)
170                     if WikiSystem(env).has_page(wiki):
171                         buff.write('<td%(style)s><a href="%(url)s">%(day)s</a></td>' % {
172                             'url': url,
173                             'day': day,
174                             'style': day == curr_day and ' style="border: 1px solid #b00;"' or '',
175                             })
176                     # just display the date
177                     else:
178                         url += "?action=edit"
179                         buff.write('<td%(style)s><a href="%(url)s" class="missing">%(day)s</a></td>' % {
180                             'url': url,
181                             'day': day,
182                             'style': day == curr_day and ' style="border: 1px solid #b00;"' or '',
183                             })
184
185         buff.write('</tr>\n')
186
187     buff.write('</tbody>\n</table>')
188            
189     table = buff.getvalue()
190     buff.close()
191     return table
192
193
194 class WikiCalendarMacro(WikiMacroBase):
195     """ Render WikiCalenar macro in trac 0.11 """
196    
197     def expand_macro(self, formatter, name, content):
198         return execute(formatter, content, self.env)