vendor/CMF/1.6-r40908/CMFCalendar

view CalendarTool.py @ 0:e47fc5876d9a

Vendor import of CMF 1.6 branch r40908
author fguillaume
date Tue, 20 Dec 2005 15:51:52 +0000
parents
children
line source
1 ##############################################################################
2 #
3 # Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
4 #
5 # This software is subject to the provisions of the Zope Public License,
6 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
10 # FOR A PARTICULAR PURPOSE.
11 #
12 ##############################################################################
13 """ CMFCalendar portal_calendar tool.
15 $Id: CalendarTool.py 38330 2005-09-06 23:56:51Z jens $
16 """
18 import calendar
19 calendar.setfirstweekday(6) #start day Mon(0)-Sun(6)
21 from AccessControl import ClassSecurityInfo
22 from DateTime import DateTime
23 from Globals import InitializeClass
24 from OFS.SimpleItem import SimpleItem
25 from Products.PageTemplates.PageTemplateFile import PageTemplateFile
27 from Products.CMFCore.utils import UniqueObject
29 from permissions import ManagePortal
31 class CalendarTool (UniqueObject, SimpleItem):
32 """ a calendar tool for encapsualting how calendars work and are displayed """
33 id = 'portal_calendar'
34 meta_type= 'CMF Calendar Tool'
35 security = ClassSecurityInfo()
37 calendar_types = ('Event',)
38 calendar_states = ('published',)
39 use_session = ''
41 manage_options = ( ({ 'label' : 'Overview', 'action' : 'manage_overview' }
42 , { 'label' : 'Configure', 'action' : 'manage_configure' }
43 ,
44 ) + SimpleItem.manage_options
45 )
47 #
48 # ZMI methods
49 #
50 security.declareProtected( ManagePortal, 'manage_overview' )
51 manage_overview = PageTemplateFile('www/explainCalendarTool', globals(),
52 __name__='manage_overview')
54 security.declareProtected( ManagePortal, 'manage_configure' )
55 manage_configure = PageTemplateFile('www/configureCalendarTool', globals(),
56 __name__='manage_configure')
58 security.declareProtected( ManagePortal, 'edit_configuration' )
59 def edit_configuration(self, show_types, use_session, show_states=None):
60 """ Change the configuration of the calendar tool """
61 self.calendar_types = tuple(show_types)
62 self.use_session = use_session
63 if show_states is not None:
64 self.calendar_states = tuple(show_states)
65 if hasattr(self.REQUEST, 'RESPONSE'):
66 self.REQUEST.RESPONSE.redirect('manage_configure')
68 security.declarePublic('getCalendarTypes')
69 def getCalendarTypes(self):
70 """ Returns a list of type that will show in the calendar """
71 return self.calendar_types
73 security.declarePublic('getCalendarStates')
74 def getCalendarStates(self):
75 """ Returns a list of workflow states that will show in the calendar """
76 return self.calendar_states
78 security.declarePublic('getUseSession')
79 def getUseSession(self):
80 """ Returns the Use_Session option """
81 return self.use_session
83 security.declarePublic('getDays')
84 def getDays(self):
85 """ Returns a list of days with the correct start day first """
86 return calendar.weekheader(2).split()
88 security.declarePublic('getWeeksList')
89 def getWeeksList(self, month='1', year='2002'):
90 """Creates a series of weeks, each of which contains an integer day number.
91 A day number of 0 means that day is in the previous or next month.
92 """
93 year=int(year)
94 month=int(month)
95 # daysByWeek is a list of days inside a list of weeks, like so:
96 # [[0, 1, 2, 3, 4, 5, 6],
97 # [7, 8, 9, 10, 11, 12, 13],
98 # [14, 15, 16, 17, 18, 19, 20],
99 # [21, 22, 23, 24, 25, 26, 27],
100 # [28, 29, 30, 31, 0, 0, 0]]
101 daysByWeek=calendar.monthcalendar(year, month)
103 return daysByWeek
105 security.declarePublic('getEventsForCalendar')
106 def getEventsForCalendar(self, month='1', year='2002'):
107 """ recreates a sequence of weeks, by days each day is a mapping.
108 {'day': #, 'url': None}
109 """
110 year=int(year)
111 month=int(month)
112 # daysByWeek is a list of days inside a list of weeks, like so:
113 # [[0, 1, 2, 3, 4, 5, 6],
114 # [7, 8, 9, 10, 11, 12, 13],
115 # [14, 15, 16, 17, 18, 19, 20],
116 # [21, 22, 23, 24, 25, 26, 27],
117 # [28, 29, 30, 31, 0, 0, 0]]
118 daysByWeek=calendar.monthcalendar(year, month)
119 weeks=[]
121 events=self.catalog_getevents(year, month)
123 for week in daysByWeek:
124 days=[]
125 for day in week:
126 if events.has_key(day):
127 days.append(events[day])
128 else:
129 days.append({'day': day, 'event': 0, 'eventslist':[]})
131 weeks.append(days)
133 return weeks
135 security.declarePublic('catalog_getevents')
136 def catalog_getevents(self, year, month):
137 """ given a year and month return a list of days that have events """
138 year=int(year)
139 month=int(month)
140 last_day=calendar.monthrange(year, month)[1]
141 first_date=self.getBeginAndEndTimes(1, month, year)[0]
142 last_date=self.getBeginAndEndTimes(last_day, month, year)[1]
144 query = self.portal_catalog(
145 portal_type=self.getCalendarTypes(),
146 review_state=self.getCalendarStates(),
147 start={'query': last_date, 'range': 'max'},
148 end={'query': first_date, 'range': 'min'},
149 sort_on='start' )
151 # compile a list of the days that have events
152 eventDays={}
153 for daynumber in range(1, 32): # 1 to 31
154 eventDays[daynumber] = {'eventslist':[], 'event':0, 'day':daynumber}
155 includedevents = []
156 for result in query:
157 if result.getRID() in includedevents:
158 break
159 else:
160 includedevents.append(result.getRID())
161 event={}
162 # we need to deal with events that end next month
163 if result.end.month() != month:
164 # doesn't work for events that last ~12 months
165 # fix it if it's a problem, otherwise ignore
166 eventEndDay = last_day
167 event['end'] = None
168 else:
169 eventEndDay = result.end.day()
170 event['end'] = result.end.Time()
171 # and events that started last month
172 if result.start.month() != month: # same as above re: 12 month thing
173 eventStartDay = 1
174 event['start'] = None
175 else:
176 eventStartDay = result.start.day()
177 event['start'] = result.start.Time()
179 event['title'] = result.Title or result.getId
181 if eventStartDay != eventEndDay:
182 allEventDays = range(eventStartDay, eventEndDay+1)
183 eventDays[eventStartDay]['eventslist'].append( {'end': None,
184 'start': result.start.Time(), 'title': event['title']} )
185 eventDays[eventStartDay]['event'] = 1
187 for eventday in allEventDays[1:-1]:
188 eventDays[eventday]['eventslist'].append( {'end': None,
189 'start': None, 'title': event['title']} )
190 eventDays[eventday]['event'] = 1
192 if result.end == result.end.earliestTime():
193 last_day = eventDays[allEventDays[-2]]
194 last_days_event = last_day['eventslist'][-1]
195 last_days_event['end'] = (result.end-1).latestTime().Time()
196 else:
197 eventDays[eventEndDay]['eventslist'].append( {'end':
198 result.end.Time(), 'start': None, 'title': event['title']} )
199 eventDays[eventEndDay]['event'] = 1
200 else:
201 eventDays[eventStartDay]['eventslist'].append(event)
202 eventDays[eventStartDay]['event'] = 1
203 # This list is not uniqued and isn't sorted
204 # uniquing and sorting only wastes time
205 # and in this example we don't need to because
206 # later we are going to do an 'if 2 in eventDays'
207 # so the order is not important.
208 # example: [23, 28, 29, 30, 31, 23]
209 return eventDays
211 security.declarePublic('getEventsForThisDay')
212 def getEventsForThisDay(self, thisDay):
213 """ given an exact day return ALL events that:
214 A) Start on this day OR
215 B) End on this day OR
216 C) Start before this day AND end after this day"""
218 catalog = self.portal_catalog
219 day, month, year = ( int(thisDay.day())
220 , int(thisDay.month())
221 , int(thisDay.year())
222 )
224 first_date, last_date = self.getBeginAndEndTimes(day, month, year)
225 zone = first_date.localZone()
226 after_midnight_str = '%d-%02d-%02d 00:01:00 %s' % (year,month,day,zone)
227 after_midnight = DateTime(after_midnight_str)
229 # Get all events that Start on this day
230 query = self.portal_catalog(
231 portal_type=self.getCalendarTypes(),
232 review_state=self.getCalendarStates(),
233 start={'query': (first_date, last_date),
234 'range': 'minmax'} )
236 # Get all events that End on this day
237 query += self.portal_catalog(
238 portal_type=self.getCalendarTypes(),
239 review_state=self.getCalendarStates(),
240 end={'query': (after_midnight, last_date),
241 'range': 'minmax'} )
243 # Get all events that Start before this day AND End after this day
244 query += self.portal_catalog(
245 portal_type=self.getCalendarTypes(),
246 review_state=self.getCalendarStates(),
247 start={'query': first_date, 'range': 'max'},
248 end={'query': last_date, 'range': 'min'} )
250 # Unique the results
251 results = []
252 rids = []
253 for item in query:
254 rid = item.getRID()
255 if not rid in rids:
256 results.append(item)
257 rids.append(rid)
259 def sort_function(x,y):
260 z = cmp(x.start,y.start)
261 if not z:
262 return cmp(x.end,y.end)
263 return z
265 # Sort by start date
266 results.sort(sort_function)
268 return results
270 security.declarePublic('getPreviousMonth')
271 def getPreviousMonth(self, month, year):
272 # given any particular year and month, this method will return a
273 # datetime object for one month prior
275 try: month=int(month)
276 except: raise "Calendar Type Error", month
277 try: year=int(year)
278 except: raise "Calendar Type Error", year
280 if month==0 or month==1:
281 month, year = 12, year - 1
282 else:
283 month-=1
285 return DateTime(year, month, 1)
287 security.declarePublic('getNextMonth')
288 def getNextMonth(self, month, year):
289 # given any particular year and month, this method will return a datetime object
290 # for one month after
292 try: month=int(month)
293 except: raise "Calendar Type Error", month
294 try: year=int(year)
295 except: raise "Calendar Type Error", year
297 if month==12:
298 month, year = 1, year + 1
299 else:
300 month+=1
302 return DateTime(year, month, 1)
304 security.declarePublic('getBeginAndEndTimes')
305 def getBeginAndEndTimes(self, day, month, year):
306 # Given any day, month and year this method returns 2 DateTime objects
307 # That represent the exact start and the exact end of that particular day.
309 day=int(day)
310 month=int(month)
311 year=int(year)
313 begin=DateTime('%d-%02d-%02d 00:00:00' % (year, month, day))
314 end=DateTime('%d-%02d-%02d 23:59:59' % (year, month, day))
316 return (begin, end)
318 InitializeClass(CalendarTool)