This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
tabellio.agenda/tabellio/agenda/utils.py

273 lines
11 KiB
Python

from time import localtime
from Acquisition import aq_inner
from DateTime import DateTime
from zope.component import getMultiAdapter
from zope.i18nmessageid import MessageFactory
from Products.CMFPlone.utils import safe_unicode
from Products.CMFCore.utils import getToolByName
PLMF = MessageFactory('plonelocales')
class MonthlyView:
updated = False
def __init__(self, context, init_calendar=False):
self.context = context
self.updated = False
if init_calendar:
self.calendar = getToolByName(context, 'portal_calendar')
def update(self):
if self.updated:
return
self.updated = True
context = aq_inner(self.context)
self.calendar = getToolByName(context, 'portal_calendar')
self._ts = getToolByName(context, 'translation_service')
self.now = localtime()
self.yearmonth = yearmonth = self.getYearAndMonthToDisplay()
self.year = year = yearmonth[0]
self.month = month = yearmonth[1]
self.showPrevMonth = yearmonth > (self.now[0]-1, self.now[1])
self.showNextMonth = yearmonth < (self.now[0]+1, self.now[1])
self.prevMonthYear, self.prevMonthMonth = self.getPreviousMonth(year, month)
self.nextMonthYear, self.nextMonthMonth = self.getNextMonth(year, month)
self.monthName = PLMF(self._ts.month_msgid(month),
default=self._ts.month_english(month))
def get_events_from_catalog(self, start, end, portal_type=None, **keywords):
if portal_type is None:
portal_type = ('tabellio.agenda.event',
'tabellio.agenda.parlevent',
'tabellio.agenda.burevent',
'tabellio.agenda.comevent')
catalog = getToolByName(self.context, 'portal_catalog')
def cmp_event(x, y):
if x.start == y.start:
return cmp(x.id, y.id)
return cmp(x.start, y.start)
rs = []
rsid = []
for brain in catalog(portal_type=portal_type,
review_state=self.calendar.getCalendarStates(),
start={'query': start, 'range': 'max'},
end={'query': end, 'range': 'min'},
**keywords) + \
catalog(portal_type=portal_type,
review_state=self.calendar.getCalendarStates(),
start={'query': (start, end), 'range': 'min:max'},
**keywords):
if type(brain.getId) is str:
if not brain.getId in rsid:
rs.append(brain)
rsid.append(brain.getId)
else:
if not brain.getId() in rsid:
rs.append(brain)
rsid.append(brain.getId())
return sorted(rs, cmp_event)
def catalog_getevents(self, year, month):
last_day = self.calendar._getCalendar().monthrange(year, month)[1]
first_date = self.calendar.getBeginAndEndTimes(1, month, year)[0]
last_date = self.calendar.getBeginAndEndTimes(last_day, month, year)[1]
query = self.get_events_from_catalog(last_date, first_date, sort_on='start')
# compile a list of the days that have events
eventDays={}
for daynumber in range(1, 32): # 1 to 31
eventDays[daynumber] = {'eventslist': [],
'event': 0,
'day': daynumber}
includedevents = []
for result in query:
if result.end is None:
result.end = DateTime(result.start)
else:
result.end = DateTime(result.end)
result.start = DateTime(result.start)
if result.getRID() in includedevents:
break
else:
includedevents.append(result.getRID())
event={}
# we need to deal with events that end next month
if result.end is None or result.end.greaterThan(last_date):
eventEndDay = last_day
event['end'] = None
else:
eventEndDay = result.end.day()
if result.end == result.end.earliestTime():
event['end'] = (result.end - 1).latestTime().Time()
else:
event['end'] = result.end.Time()
# and events that started last month
if result.start.lessThan(first_date):
eventStartDay = 1
event['start'] = None
else:
eventStartDay = result.start.day()
event['start'] = result.start.Time()
event['title'] = result.Title or result.getId
event['type'] = result.portal_type.split('.')[-1]
event['id'] = result.getId
if eventStartDay != eventEndDay:
allEventDays = range(eventStartDay, eventEndDay+1)
eventDays[eventStartDay]['eventslist'].append(
{'end': None,
'start': result.start.Time(),
'title': event['title'],
'type': event['type'],
'id': event['id']} )
eventDays[eventStartDay]['event'] = 1
for eventday in allEventDays[1:-1]:
eventDays[eventday]['eventslist'].append(
{'end': None,
'start': None,
'title': event['title'],
'type': event['type'],
'id': event['id']} )
eventDays[eventday]['event'] = 1
if (event['end'] is not None and result.end == result.end.earliestTime()):
# ends some day this month at midnight
last_day_data = eventDays[allEventDays[-2]]
last_days_event = last_day_data['eventslist'][-1]
last_days_event['end'] = (result.end-1).latestTime().Time()
else:
eventDays[eventEndDay]['eventslist'].append(
{ 'end': event['end'],
'start': None,
'title': event['title'],
'type': event['type'],
'id': event['id']} )
eventDays[eventEndDay]['event'] = 1
else:
eventDays[eventStartDay]['eventslist'].append(event)
eventDays[eventStartDay]['event'] = 1
# This list is not uniqued and isn't sorted
# uniquing and sorting only wastes time
# and in this example we don't need to because
# later we are going to do an 'if 2 in eventDays'
# so the order is not important.
# example: [23, 28, 29, 30, 31, 23]
return eventDays
def getDailyEventsForMonth(self, month, year):
year = int(year)
month = int(month)
daysByWeek = self.calendar._getCalendar().monthcalendar(year, month)
weeks = []
events = self.catalog_getevents(year, month)
for week in daysByWeek:
days = []
for day in week:
if events.has_key(day):
days.append(events[day])
else:
days.append({'day': day, 'event': 0, 'eventslist':[]})
weeks.append(days)
return weeks
def getEventsForCalendar(self):
context = aq_inner(self.context)
year = self.year
month = self.month
weeks = self.getDailyEventsForMonth(month, year)
for week in weeks:
for day in week:
daynumber = day['day']
if daynumber == 0:
continue
day['is_today'] = self.isToday(daynumber)
if day['event']:
cur_date = DateTime(year, month, daynumber)
localized_date = [self._ts.ulocalized_time(cur_date, context=context, request=self.request)]
day['eventstring'] = '\n'.join(localized_date+[' %s' %
self.getEventString(e) for e in day['eventslist']])
day['date_string'] = '%s-%s-%s' % (year, month, daynumber)
evtype = None
evid = None
for event in day['eventslist']:
if evtype is None:
evtype = event['type']
evid = event['id']
elif evtype != event['type']:
evtype = 'misc'
evid = None
break
day['eventclass'] = evtype or 'none'
day['eventid'] = evid
return weeks
def getEventString(self, event):
start = event.get('start') and ':'.join(event.get('start').split(':')[:2]) or ''
end = event.get('end') and ':'.join(event.get('end').split(':')[:2]) or ''
title = safe_unicode(event.get('title')) or u'event'
if start == end:
end = None
if start == '00:00':
start = None
end = None
if start and end:
eventstring = "%s-%s %s" % (start, end, title)
elif start: # can assume not event['end']
eventstring = "%s - %s" % (start, title)
elif event['end']: # can assume not event['start']
eventstring = "%s - %s" % (title, end)
else: # can assume not event['start'] and not event['end']
eventstring = title
return eventstring
def getPreviousMonth(self, year, month):
if month==0 or month==1:
month, year = 12, year - 1
else:
month-=1
return (year, month)
def getNextMonth(self, year, month):
if month==12:
month, year = 1, year + 1
else:
month+=1
return (year, month)
def getWeekdays(self):
"""Returns a list of Messages for the weekday names."""
weekdays = []
# list of ordered weekdays as numbers
for day in self.calendar.getDayNumbers():
weekdays.append(PLMF(self._ts.day_msgid(day, format='s'),
default=self._ts.weekday_english(day, format='a')))
return weekdays
def isToday(self, day):
"""Returns True if the given day and the current month and year equals
today, otherwise False.
"""
return self.now[2]==day and self.now[1]==self.month and \
self.now[0]==self.year