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/servers/AppointmentsServer/AppointmentsServer.py

285 lines
10 KiB
Python
Executable File

#!/usr/bin/env 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 Server"""
__version__ = '$Revision$'[11:-2]
import sys
import time
glasnostPythonDir = '/usr/local/lib/glasnost-devel' # changed on make install
sys.path.insert(0, glasnostPythonDir)
import glasnost
from glasnost.common.AppointmentsCommon import *
import glasnost.common.faults as faults
from glasnost.common.tools import sendMail
import glasnost.common.tools_new as commonTools
from glasnost.server.ObjectsServer import ObjectServerMixin, \
AdminServerMixin, ObjectsServer
from glasnost.server.things import register
from glasnost.server.tools import *
from glasnost.proxy.CacheProxy import invalidateValue
from glasnost.proxy.GroupsProxy import setContains, getSetContainedIds
try:
import vcalsax
except ImportError:
pass
applicationName = 'AppointmentsServer'
applicationRole = 'appointments'
dispatcher = None
class AdminAppointments(AdminServerMixin, AdminAppointmentsCommon):
pass
register(AdminAppointments)
class Appointment(ObjectServerMixin, AppointmentCommon):
pass
register(Appointment)
def vCalDateToTime(s):
if len(s) == 8:
return time.mktime(time.strptime(s, '%Y%m%d'))
if len(s) == 15:
return time.mktime(time.strptime(s, '%Y%m%dT%H%M%S'))
return None
def domToObject(domDocument):
# FIXME: the document could have several VEVENT
nodes = domDocument._get_childNodes()[1]._get_childNodes()[-1]._get_childNodes()
attrs = [(x._get_nodeName(),
x._get_childNodes()[0]._get_nodeValue()) for x in nodes]
# yep, I hope it will work. Incredible.
# TODO: something smarter
# attrs now is a list of pairs (key, value)
# ex: [('UID', 'glasnost://projects.entrouvert.be.lan/appointments/1'),
# ('SUMMARY', 'rdv avec Olivier Lattignies et Etienne Saliez'),
# ('URL', 'http://projects.entrouvert.be.lan/appointments/1'),
# ('REVISION', '0'),
# ('DTSTART', '20030210'),
# ('DTEND', '20030210T235900')]
d = {}
for k,v in attrs:
d[k] = unicode(v.encode('latin-1'), 'utf-8').encode('latin-1')
appointment = Appointment()
if d['UID'].startswith('glasnost://'):
appointment.id = d['UID']
appointment.title = d['SUMMARY']
if d.has_key('SEQUENCE'):
appointment.version = d['SEQUENCE']
if d.has_key('DTSTART'):
t = vCalDateToTime(d['DTSTART'])
if t:
appointment.start = t
if d.has_key('DTEND'):
t = vCalDateToTime(d['DTEND'])
if t:
appointment.end = t
if d.has_key('DESCRIPTION'):
s = d['DESCRIPTION']
s = s.replace('\\n', '\n')
appointment.body = s
return appointment
class AppointmentsServer(AppointmentsCommonMixin, ObjectsServer):
useAdminWritersSet = 1
def isAskedParticipant(self, appointment, resourceIds):
people = getSetContainedIds(participantIds)
for personId in people:
if setContains(appointment.participantsSet, personId):
return 1
return 0
def getAppointmentIds(self, start = None, end = None,
participantIds = None):
isAdmin = self.isAdmin()
## if not isAdmin:
## raise faults.UserAccessDenied()
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
if not participantIds or participantIds == ['']:
participantIds = []
authenticationProxy = getProxyForServerRole('authentication')
result = []
for objectId, object in virtualServer.objects.items():
if not (isAdmin
or authenticationProxy.setContainsUser(object.readersSet)
or (object.participantsSet
and getProxyForServerRole('authentication'
).setContainsUser(object.participantsSet))):
continue
if participantIds and not self.isAskedParticipant(
object, participantIds):
continue
if (object.end or object.start) < start or object.start > end:
continue
result.append(object.id)
return result
def addObjectXmlRpc(self, objectImport):
objectId = ObjectsServer.addObjectXmlRpc(self, objectImport)
# TODO: send notification mail
return objectId
def modifyObjectXmlRpc(self, objectImport):
version = ObjectsServer.modifyObjectXmlRpc(self, objectImport)
# TODO: send notification mail
return version
def updateFromVCalendar(self, vCalendar):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
vCals = ['BEGIN:VCALENDAR' +x
for x in vCalendar.split('BEGIN:VCALENDAR')[1:]]
apps = []
for v in vCals:
parser = vcalsax.VcfParser()
reader = vcalsax.Sax2.Reader(0, 0, None,
vcalsax.Sax2.XmlDomGenerator,
parser)
doc = reader.fromString(v)
apps.append( domToObject(doc) )
for a in apps:
invalidate = 0
object = virtualServer.loadObjectCore(a.id)
if a.version and object.version != a.version:
continue
if object.title != a.title:
object.title = a.title
invalidate = 1
if object.start != a.start and a.start:
object.start = a.start
invalidate = 1
if object.end != a.end and a.end:
object.end = a.end
invalidate = 1
if object.body != a.body:
object.body = a.body
invalidate = 1
if invalidate:
object.version += 1
invalidateValue(object.id)
def sendNotification(self, virtualServerId, appointment, subject, body):
virtualServer = self.getVirtualServer(virtualServerId)
mailFrom = virtualServer.adminEmailAddress
people = getSetContainedIds(appointment.participantsSet)
for personId in people:
person = getProxyForServerRole('people').getObject(personId)
if person.email:
mailTo = person.email
try:
sendMail(mailFrom, mailTo, mailSubject = subject,
mailMessage = body, mailPerson = person)
except faults.SmtpError:
pass
def registerPublicMethods(self):
ObjectsServer.registerPublicMethods(self)
self.registerPublicMethod('getAppointmentIds')
self.registerPublicMethod('updateFromVCalendar')
def repairVirtualServer(self, virtualServer, version):
changed = 0
if version <= 1029000:
for object in virtualServer.objects.values():
if not hasattr(object, 'rememberTime'):
continue
object.reminderTime = object.rememberTime
del(object.rememberTime)
changed = 1
if version <= 1032000:
for object in virtualServer.objects.values():
if not hasattr(object, 'resourcesSet'):
continue
object.participantsSet = object.resourcesSet
del(object.resourcesSet)
changed = 1
# several fields where also removed in this version:
# authorsSet, category, endingDate, lastEditorId,
# modificationTime, reminderTime, repetition and
# repetitionDay
# they are not removed from objects because they might
# be replaced by alternatives later and it would be bad
# to lose data.
if version <= 1039000:
# beginningDate renamed to start, duration removed,
# endingDate is back but renamed to end.
for object in virtualServer.objects.values():
if hasattr(object, 'beginningDate'):
object.start = object.beginningDate
changed = 1
if hasattr(object, 'endingDate'):
object.end = object.endingDate
changed = 1
if hasattr(object, 'duration') and not object.end:
object.end = object.start + object.duration
changed = 1
if changed:
virtualServer.markAllAsDirtyFIXME()
appointmentsServer = AppointmentsServer()
if __name__ == "__main__":
appointmentsServer.launch(applicationName, applicationRole)