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.
glasnost/shared/web/AppointmentsWeb.py

797 lines
30 KiB
Python

# -*- coding: iso-8859-15 -*-
# Glasnost
# By: Odile Bénassy <obenassy@entrouvert.com>
# Romain Chantereau <rchantereau@entrouvert.com>
# Nicolas Clapiès <nclapies@easter-eggs.org>
# Pierre-Antoine Dejace <padejace@entrouvert.be>
# Thierry Dulieu <tdulieu@easter-eggs.com>
# Florent Monnier <monnier@codelutin.com>
# Cédric Musso <cmusso@easter-eggs.org>
# Frédéric Péters <fpeters@entrouvert.be>
# Benjamin Poussin <poussin@codelutin.com>
# Emmanuel Raviart <eraviart@entrouvert.com>
# Sébastien Régnier <regnier@codelutin.com>
# Emmanuel Saracco <esaracco@easter-eggs.com>
#
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
# Emmanuel Saracco & Théridion
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
# Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
# Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
# Régnier, Emmanuel Saracco, Théridion & Vecam
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
__doc__ = """Glasnost Appointments Web"""
__version__ = '$Revision$'[11:-2]
import calendar
import time
import glasnost.common.tools_new as commonTools
from glasnost.proxy.AppointmentsProxy import *
from ObjectsWeb import register, AdminMixin, ObjectWebMixin, ObjectsWebMixin
import calendaring
from tools import *
class AdminAppointments(AdminMixin, AdminAppointments):
categoriesGroupId_kind_widget_fieldLabel = N_('Categories Group')
categoriesGroupId_kind_widgetName = 'SelectId'
register(AdminAppointments)
_Appointment = Appointment
class Appointment(ObjectWebMixin, Appointment):
body_kind_widget_fieldLabel = N_('Text')
body_kind_widget_cols = 40
body_kind_widget_colSpan = 2
body_kind_widget_rows = 10
body_kind_widgetName = 'TextArea'
categoriesSet = None
class categoriesSet_kindClass:
_kindName = 'Sequence'
importExport = 'private'
isRequiredInEditMode = 1
label = N_('Categories')
requiredCount = 0
stateInEditMode = 'read-write'
class itemKind_valueClass:
_kindName = 'Id'
def getValues(self, slot):
admin = slot.getObject().getWeb().getAdmin()
groupsProxy = getProxyForServerRole('groups')
if not admin.categoriesGroupId:
return []
group = groupsProxy.getObject(admin.categoriesGroupId)
return group.membersSet
end_kind_widget_fieldLabel = N_('End')
participantsSet_kind_itemKind_value_defaultValue = 'user'
participantsSet_kind_balloonHelp = N_(
'Select the people and groups who are assigned to this appointment.')
participantsSet_kind_label = N_('Participants')
start_kind_widget_fieldLabel = N_('Start')
title_kind_widget_fieldLabel = N_('Title')
title_kind_widget_size = 40
title_kind_widgetName = 'InputText'
#def getOrderedLayoutSlotNames(self, parentSlot = None):
# slotNames = _Appointment.getOrderedLayoutSlotNames(
# self, parentSlot = parentSlot)
# #slotNames += [ 'categoriesSet' ]
# return slotNames
def getLabelTranslated(self, destinationLanguages = None, multiCall = None,
withDate = 0, withHour = 0):
label = ObjectWebMixin.getLabelTranslated(self, destinationLanguages,
multiCall)
dateTime = self.getDateTime(withDate, withHour)
if dateTime:
return '%s - %s' % (dateTime, label)
return label
def getSlotNames(self, parentSlot = None):
slotNames = _Appointment.getSlotNames(self, parentSlot = parentSlot)
admin = self.getWeb().getAdmin()
if not admin.categoriesGroupId:
slotNames.remove('categoriesSet')
return slotNames
def toVevent(self):
s = []
s.append("""BEGIN:VEVENT
UID:%s
SUMMARY:%s
URL:%s
SEQUENCE:%s""" % (
self.id,
self.title,
X.idUrl(self.id).getAsAbsoluteUrl(),
self.version))
if self.body:
# TODO: extract text from body
s.append("""DESCRIPTION:%s""" % utf8(self.body.replace('\n', '\\n')))
if not self.getBeginningHourAndMinute():
date = '%d%02d%02d' % tuple(
time.localtime(self.start)[:3])
s.append("""DTSTART
;VALUE=DATE
:%s
DTEND:%sT235900""" % (date, date) )
else:
beginning = '%d%02d%02dT%02d%02d%02d' % tuple(
time.localtime(self.start)[:6])
if not self.end:
self.end = self.start + 3600
end = '%d%02d%02dT%02d%02d%02d' % tuple(
time.localtime(self.end)[:6])
s.append("""DTSTART:%s\nDTEND:%s""" % (beginning, end))
s.append('END:VEVENT\n')
return '\n'.join(s)
register(Appointment)
def weekNumberToDate(year, weekNumber):
jan4thSecs = time.mktime((year, 1, 4, 0, 0, 0, 0, 0, 0))
secondsSinceJan4th = jan4thSecs + (weekNumber-1)*7*24*60*60
weekTuple = time.localtime(secondsSinceJan4th)
daysToAdd = - weekTuple[6]
secondsSinceJan4th += daysToAdd*24*60*60
weekTuple = time.localtime(secondsSinceJan4th)
return weekTuple
def dateToWeekNumber(year, month, day):
janFirstSecs = time.mktime((year, 1, 1, 0, 0, 0, 0, 0, 0))
janFirstTuple = time.localtime(janFirstSecs)
if janFirstTuple[6] < 4:
week0Secs = janFirstSecs - janFirstTuple[6]*24*60*60
else:
week0Secs = janFirstSecs + (7-janFirstTuple[6])*24*60*60
secondsSinceEpoch = time.mktime((year, month, day, 0, 0, 0, 0, 0, 0))
diffSecs = secondsSinceEpoch - week0Secs
weekNumber, mod = divmod(diffSecs, 7*24*60*60)
weekNumber = int(weekNumber) + 1
if weekNumber == 53:
year, weekNumber = year+1, 1
if weekNumber == 0:
year, weekNumber = year-1, 52
return (year, weekNumber)
class AppointmentsWeb(ObjectsWebMixin, AppointmentsProxy):
def agenda(self):
now = time.time()
objects = self.getObjects().values()
pastObjects = [x for x in objects if x.start < now]
pastObjects.sort(lambda x,y: -cmp(x.start, y.start))
futureObjects = [x for x in objects if x.start > now]
futureObjects.sort(lambda x,y: cmp(x.start, y.start))
layout = X.array()
if futureObjects:
table = X.table(_class = 'objects-table')
table += X.tr(
X.th(_('Date')),
X.th(_('Label')))
for object in futureObjects:
table += X.tr(
X.td(object.getDateTime(withDate = 1, withHour = 1)),
X.td(X.objectHypertextLabel(object.id)))
layout += X.h2(_('Future events'))
layout += table
if pastObjects:
table = X.table(_class = 'objects-table')
table += X.tr(
X.th(_('Date')),
X.th(_('Label')))
for object in pastObjects:
table += X.tr(
X.td(object.getDateTime(withDate = 1, withHour = 1)),
X.td(X.objectHypertextLabel(object.id)))
layout += X.h2(_('Past events'))
layout += table
return writePageLayout(layout, _('Agenda'))
agenda.isPublicForWeb = 1
def day(self, year, month, day):
canAdd = self.canAddObject()
thisDay = time.mktime( [int(year), int(month), int(day)] + [0]*5 +
[time.localtime()[-1]] )
appointments = self.getAppointments(thisDay, thisDay+86400).values()
dayAppointments = [x for x in appointments if x.start == thisDay]
layout = X.array()
if len(dayAppointments):
layout += X.h2(_('Day long appointments'))
ul = X.ul()
for d in dayAppointments:
ul += X.li(X.a(href = X.idUrl(d.id))(d.getTitle()))
layout += ul
table = X.table(_class = 'calendar-day-full')
layout += table
caption = X.caption()
yesterday = time.localtime(thisDay-86400)
tomorrow = time.localtime(thisDay+86400)
caption += X.a(href = X.actionUrl('day/%d/%d/%d' % (
yesterday[0], yesterday[1], yesterday[2])),
_class = 'previous-day')('<<')
caption += X.span()(self.formatDate(time.localtime(thisDay)))
caption += X.a(href = X.actionUrl('day/%d/%d/%d' % (
tomorrow[0], tomorrow[1], tomorrow[2])),
_class = 'next-day')('>>')
table += caption
skipTo = 0
for hour in range(8, 21): # TODO: "opening hours" should be an option
tr = X.tr()
table += tr
tr += X.th(scope = 'row')('%02d:00' % hour)
if hour < skipTo:
continue
thisDate = list(time.localtime(thisDay))
thisDate[3] = hour
nextDate = thisDate[:]
nextDate[3] += 1
maxEnd = time.mktime(nextDate)
while 1:
hourAppointments = [x for x in appointments if \
x.start >= time.mktime(thisDate) and \
x.start < time.mktime(nextDate)]
maxEnd = max([maxEnd] + [x.end for x in hourAppointments])
if time.mktime(nextDate) < maxEnd:
nextDate = time.localtime(maxEnd)
else:
break
nbHour = int( math.ceil((
time.mktime(nextDate) - time.mktime(thisDate)) / 3600))
hourContent = X.array()
ul = X.ul()
hourAppointments.sort(lambda x,y: cmp(x.start, y.start))
for d in hourAppointments:
ul += X.li(X.a(href = X.idUrl(d.id))(d.getLabelTranslated()))
hourContent += ul
className = ''
if len(hourAppointments):
className = 'hour-busy'
td = X.td(_class = className)(hourContent)
else:
td = X.td()
if nbHour > 1:
td.setAttribute('rowspan', nbHour)
tr += td
skipTo = hour + nbHour - 1
layout += self.getLinksLayout(year = int(year), month = int(month),
day = int(day), exclude = ['day'])
return writePageLayout(layout, self.formatDate(time.localtime(thisDay)))
day.isPublicForWeb = 1
def formatDate(self, dayTuple):
# TODO: grab user or site preference for date format (euro/us/...)
year, month, day = dayTuple[:3]
monthLabel = calendaring.getMonthLabelNoCapitalization(month)
return '%d %s %d' % (day, monthLabel, year)
def getObject_handleResult(self, lazyObject):
object = AppointmentsProxy.getObject_handleResult(self, lazyObject)
groupsProxy = getProxyForServerRole('groups')
object.categoriesSet = groupsProxy.getObjectIdsWithContent(object.id)
return object
def week(self, year, weekNumber):
webTools.addContextualHeader('calendar.css')
canAdd = self.canAddObject()
today = list(time.localtime(time.time())[:3])
year, weekNumber = int(year), int(weekNumber)
prevYear, prevWeek = year, weekNumber-1
if prevWeek == 0:
prevYear, prevWeek = prevYear-1, 52
nextYear, nextWeek = year, weekNumber+1
if nextWeek > 52:
nextYear, nextWeek = nextYear+1, 1
weekTuple = weekNumberToDate(year, weekNumber)
appointments = self.getAppointments(
time.mktime(weekTuple),
time.mktime(weekTuple)+7*24*60*60 ).values()
table = X.table(_class = 'calendar-week-full')
caption = X.caption()
caption += X.a(href = X.actionUrl('week/%d/%d' % (
prevYear, prevWeek)), _class = 'previous-week')('<<')
caption += X.span()(_('Week %d of %d') % (weekNumber, year))
caption += X.a(href = X.actionUrl('week/%d/%d' % (
nextYear, nextWeek)), _class = 'next-week')('>>')
table += caption
table += X.colgroup()
table += X.colgroup(_class = 'weekdays', span = 5)
table += X.colgroup(_class = 'weekend', span = 2)
weekTime = time.mktime(weekTuple)
tr = X.tr()
tr += X.th()
for i in range(7):
thisDate = time.localtime(weekTime + i*24*60*60)
wd = _(calendaring.dayLabels[i])
dayLabel = '%s %d %s' % (wd, thisDate[2],
calendaring.getMonthLabelNoCapitalization(thisDate[1]))
tr += X.th(scope = 'col')(dayLabel)
table += X.thead(tr)
tbody = X.tbody()
table += tbody
daysFilled = [0] * 7
tr = X.tr()
tr += X.th(scope = 'row')
allDay = 0
for i in range(7):
thisDate = list(time.localtime(weekTime + i*24*60*60))
thisDateTime = time.mktime(thisDate)
dayAppointments = [x for x in appointments \
if x.start == thisDateTime]
if len(dayAppointments) == 0:
if i in (5, 6):
tr += X.td(_class = 'weekend')
else:
tr += X.td()
continue
allDay = 1
content = X.array()
ul = X.ul()
for d in dayAppointments:
ul += X.li(X.a(href = X.idUrl(d.id))(d.getTitle()))
content += ul
className = 'hour-busy'
if i in (5, 6):
className += ' weekend'
tr += X.td(_class = className)(content)
if allDay:
tbody += tr
for hour in range(8, 21):
# TODO: "opening hours" should be an option
# TODO: should also show (where) appointments that are not in the
# opening hours
tr = X.tr()
tbody += tr
tr += X.th(scope = 'row')('%02d:00' % hour)
for i in range(7):
if daysFilled[i]:
daysFilled[i] -= 1
continue
thisDate = list(time.localtime(weekTime + i*24*60*60))
thisDate[3] = hour
nextDate = thisDate[:]
nextDate[3] += 1
maxEnd = time.mktime(nextDate)
previousDuration = 1
while 1:
hourAppointments = [x for x in appointments if \
x.start >= time.mktime(thisDate) and \
x.start < time.mktime(nextDate)]
maxEnd = max([maxEnd] + [x.end for x in hourAppointments])
if time.mktime(nextDate) < maxEnd:
nextDate = time.localtime(maxEnd)
else:
break
if len(hourAppointments) == 0:
if i in (5, 6):
tr += X.td(_class = 'weekend')
else:
tr += X.td()
continue
nbHour = int( math.ceil(
(time.mktime(nextDate) - time.mktime(thisDate)) / 3600))
daysFilled[i] = nbHour-1
hourContent = X.array()
ul = X.ul()
for d in hourAppointments:
ul += X.li(X.a(href = X.idUrl(d.id))(d.getTitle()))
hourContent += ul
className = 'hour-busy'
if i in (5, 6):
className += ' weekend'
td = X.td(_class = className)(hourContent)
if nbHour > 1:
td.setAttribute('rowspan', nbHour)
tr += td
layout = X.array(table)
month = time.localtime(weekTime)[1]
layout += self.getLinksLayout(year = year, month = month,
exclude = ['week'])
dayStart = self.formatDate(weekTuple)
dayEnd = self.formatDate(time.localtime( \
time.mktime(weekTuple)+6*24*60*60))
return writePageLayout(layout, '%s - %s' % (dayStart, dayEnd))
week.isPublicForWeb = 1
def getSmallMonthLayout(self, year = 0, month = 0):
today = list(time.localtime(time.time())[:3])
if not year or not month:
year, month = today[:2]
year, month = int(year), int(month)
table = X.table(_class = 'calendar-month-small')
prevYear, prevMonth = year, month-1
if prevMonth == 0:
prevMonth, prevYear = 12, prevYear - 1
nextYear, nextMonth = year, month+1
if nextMonth == 13:
nextMonth, nextYear = 1, nextYear + 1
appointments = self.getAppointments(
time.mktime((year, month, 1, 0, 0, 0, 0, 0, 0)),
time.mktime((nextYear, nextMonth, 1, 0, 0, 0, 0, 0, 0)) ).values()
caption = X.caption()
caption += X.a(href = X.roleUrl(self.serverRole, 'month/%d/%d' % (
year, month)))(
'%s %s' % (calendaring.getMonthLabel(month), year))
table += caption
tr = X.tr()
for wd in calendaring.dayLabels:
tr += X.th(scope = 'col')(_(wd)[0])
table += X.thead(tr)
cal = calendar.monthcalendar(year, month)
tbody = X.tbody()
table += tbody
for i in range(len(cal)):
tr = X.tr()
tbody += tr
for j in range(len(cal[i])):
d = cal[i][j]
if d == 0:
dayLabel = ''
tr += X.td(_class = 'noday')
continue
else:
dayLabel = str(d)
thisDate = [year, month, d]
nextDate = [year, month, d+1]
timeStart = time.mktime(thisDate + [0]*5 +
[time.localtime()[-1]])
timeEnd = time.mktime(nextDate + [0]*5 +
[time.localtime()[-1]])
dayAppointments = [x for x in appointments if \
x.start >= timeStart and x.start < timeEnd]
className = ''
if thisDate == today:
className += 'today'
elif thisDate < today:
className += 'past'
else:
className += 'future'
if len(dayAppointments) == 0:
dayContent = X.asIs(dayLabel)
elif len(dayAppointments) == 1:
className += ' busy'
app = dayAppointments[0]
dayContent = X.a(href = X.idUrl(app.id),
title = app.getLabelTranslated(withHour = 1))(
dayLabel)
else:
className += ' busy'
title = ', '.join([x.getLabelTranslated() for x in dayAppointments])
dayContent = X.a(
href = '/%s/day/%d/%d/%d' % (
self.serverRole, year, month, d),
title = title)(dayLabel)
className += ' d%d' % (j+1)
if j in (5, 6):
className += ' weekend'
tr += X.td(_class = className)(dayContent)
layout = X.array(table)
return layout
def month(self, year, month):
webTools.addContextualHeader('calendar.css')
canAdd = self.canAddObject()
today = list(time.localtime(time.time())[:3])
year, month = int(year), int(month)
table = X.table(_class = 'calendar-month-full')
prevYear, prevMonth = year, month-1
if prevMonth == 0:
prevMonth, prevYear = 12, prevYear - 1
nextYear, nextMonth = year, month+1
if nextMonth == 13:
nextMonth, nextYear = 1, nextYear + 1
appointments = self.getAppointments(
time.mktime((year, month, 1, 0, 0, 0, 0, 0, 0)),
time.mktime((nextYear, nextMonth, 1, 0, 0, 0, 0, 0, 0)) ).values()
caption = X.caption()
caption += X.a(href = X.actionUrl('month/%d/%d' % (
prevYear, prevMonth)), _class = 'previous-month')('<<')
caption += X.span()('%s %s' % (calendaring.getMonthLabel(month), year))
caption += X.a(href = X.actionUrl('month/%d/%d' % (
nextYear, nextMonth)), _class = 'next-month')('>>')
table += caption
tr = X.tr()
tr += X.th()
for wd in calendaring.dayLabels:
tr += X.th(scope = 'col')(_(wd))
table += X.thead(tr)
cal = calendar.monthcalendar(year, month)
weekNumber = dateToWeekNumber(year, month, 1) [1]
tbody = X.tbody()
table += tbody
for i in range(len(cal)):
tr = X.tr()
tbody += tr
weekLabel = X.a(href = X.actionUrl('week/%d/%d' % (
year, weekNumber)))(weekNumber)
tr += X.th(scope = 'row')(weekLabel)
weekNumber += 1
if weekNumber == 53:
weekNumber = 1
for j in range(len(cal[i])):
d = cal[i][j]
if d == 0:
dayLabel = ''
tr += X.td(_class = 'noday')
continue
else:
dayLabel = str(d)
thisDate = [year, month, d]
nextDate = [year, month, d+1]
if canAdd:
dayLabel = X.array(
X.asIs(dayLabel),
X.a(href = X.actionUrl('edit').add(
'start',
'%d-%02d-%02d' % (year, month, d)).add(
'nextUri', cleanUpUnparsedUri([])))('+'))
dayContent = X.array()
dayContent += X.span(_class = 'day-title')(dayLabel)
thisDateTime = time.mktime(thisDate + [0]*5 +
[time.localtime()[-1]] )
nextDateTime = time.mktime(nextDate + [0]*5 +
[time.localtime()[-1]] )
dayAppointments = [x for x in appointments if \
(x.start >= thisDateTime and
x.start < nextDateTime )
or ( x.end and
x.start < thisDateTime and
x.end >= nextDateTime ) ]
if len(dayAppointments):
ul = X.ul()
for d in dayAppointments:
hasDetails = 0
li = X.li()
disp, role, id = commonTools.splitId(d.id)
idAttribute = 'appointment-%s-%s' % (disp, id)
li += X.a(href = X.idUrl(d.id), id = idAttribute)(
d.getLabelTranslated(withHour = 1))
details = X.ul(_class = 'appointment-details tooltip',
id = 'for-' + idAttribute)
start = d.getBeginningHourAndMinute()
end = d.getEndHourAndMinute()
if start and end:
details += X.li(_('Hour: %s - %s') % (start, end))
hasDetails = 1
if d.body:
details += X.li(d.body)
hasDetails = 1
if hasDetails and \
context.getVar('virtualHost').showTooltips:
webTools.addContextualHeader('tooltips.js')
li += details
ul += li
dayContent += ul
className = ''
if thisDate == today:
className = 'today'
elif thisDate < today:
className = 'past'
else:
className = 'future'
className += ' d%d' % (j+1)
if j in (5, 6):
className += ' weekend'
tr += X.td(_class = className)(dayContent)
layout = X.array(table)
layout += self.getLinksLayout(year = year, month = month,
exclude = ['month'])
return writePageLayout(layout,
'%s %s' % (calendaring.getMonthLabel(month), year))
month.isPublicForWeb = 1
def getLinksLayout(self, year = None, month = None, day = None, exclude = None):
todayYear, todayMonth, todayDay = list(time.localtime(time.time())[:3])
thisYear = year or todayYear
thisMonth = month or todayMonth
thisDay = day or todayDay
thisWeek = dateToWeekNumber(thisYear, thisMonth, thisDay) [1]
dayLink = X.a(href = X.actionUrl('day/%d/%d/%d' % (
thisYear, thisMonth, thisDay))) (_('Day'))
weekLink = X.a(href = X.actionUrl('week/%d/%d' % (
thisYear, thisWeek))) (_('Week'))
monthLink = X.a(href = X.actionUrl('month/%d/%d' % (
thisYear, thisMonth))) (_('Month'))
yearLink = X.a(href = X.actionUrl('year/%d' % thisYear)) (_('Year'))
ul = X.ul(_class = 'calendar-links')
if exclude is None:
exclude = []
if not 'agenda' in exclude:
ul += X.li( X.a(href = X.actionUrl('agenda')) (_('Agenda')))
if not 'day' in exclude:
ul += X.li(dayLink)
if not 'week' in exclude:
ul += X.li(weekLink)
if not 'month' in exclude:
ul += X.li(monthLink)
if not 'year' in exclude:
ul += X.li(yearLink)
return X.array(ul, self.getViewAllButtonsBarLayout())
def submitAddObject(self, object):
result = ObjectsWebMixin.submitAddObject(self, object)
if result:
return result
groupsProxy = getProxyForServerRole('groups')
for groupId in object.categoriesSet or []:
groupsProxy.addObjectMember(groupId, object.id)
# what happens if it fails ?
def submitModifyObject(self, object):
result = ObjectsWebMixin.submitModifyObject(self, object)
if result:
return result
groupsProxy = getProxyForServerRole('groups')
pastGroups = groupsProxy.getObjectIdsWithContent(object.id) or []
nowGroups = object.categoriesSet or []
done = []
for groupId in pastGroups + nowGroups:
if groupId in done:
continue
done.append(groupId)
if groupId not in pastGroups:
# adding
groupsProxy.addObjectMember(groupId, object.id)
continue
if groupId not in nowGroups:
# removing
groupsProxy.deleteObjectMember(groupId, object.id)
continue
def vcal(self, id = ''):
method = context.getVar('httpMethod')
req = context.getVar('req')
if id:
if not self.hasObject(id):
return pageNotFound()
if not self.canGetObject(id):
return accessForbidden()
if method == 'DELETE':
try:
self.deleteObject(id)
except faults.Fault:
return HTTP_FORBIDDEN
return HTTP_NO_CONTENT
elif method == 'PUT':
vCal = req.read()
# TODO: sending vCalendar to
# appointmentsServer.modifyObjectWithvCal(id, vCal)
return HTTP_NOT_IMPLEMENTED
objects = [self.getObject(id)]
else:
if method == 'DELETE':
return HTTP_FORBIDDEN
if method == 'PUT':
vCal = req.read()
self.updateFromVCalendar(vCal)
return HTTP_NO_CONTENT
objects = self.getObjects().values()
req.content_type = 'text/calendar; charset=iso-8859-15'
req.send_http_header()
if req.method == 'HEAD':
return OK
if req.caching:
req.openCachePage()
for object in objects:
req.write("""BEGIN:VCALENDAR
VERSION:2.0
PROPID:-//glasnost.entrouvert.org/NONSGML Glasnost Calendar//EN
METHOD:PUBLISH
""")
req.write(object.toVevent())
req.write("""END:VCALENDAR\n""")
if req.caching:
req.closeCachePage()
return OK
vcal.isPublicForWeb = ('GET', 'DELETE', 'PUT')
def viewAll(self):
year, month = time.localtime(time.time())[:2]
return self.month(year, month)
viewAll.isPublicForWeb = 1
def year(self, year):
try:
year = int(year)
except:
return pageNotFound()
ul = X.ul()
for i in range(12):
ul += X.li( X.a(href = X.actionUrl('month/%d/%d' % (year, i+1))) (
'%s %s' % (calendaring.getMonthLabel(i+1), year)))
layout = X.array()
layout += ul
layout += self.getLinksLayout(year = year, exclude = ['year'])
return writePageLayout(layout, '%s' % year)
year.isPublicForWeb = 1