[CalendarServer-changes] [4049] CalendarServer/branches/users/sagen/resource-delegates-4038
source_changes at macosforge.org
source_changes at macosforge.org
Tue Apr 21 06:23:56 PDT 2009
Revision: 4049
http://trac.macosforge.org/projects/calendarserver/changeset/4049
Author: sagen at apple.com
Date: 2009-04-21 06:23:56 -0700 (Tue, 21 Apr 2009)
Log Message:
-----------
Auto-Schedule property added; source of truth moved from directory to DB; caldav_utility can now manipulate auto-schedule.
Modified Paths:
--------------
CalendarServer/branches/users/sagen/resource-delegates-4038/bin/caldav_utility.py
CalendarServer/branches/users/sagen/resource-delegates-4038/calendarserver/tools/util.py
CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/customxml.py
CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/cachingappleopendirectory.py
CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/cachingdirectory.py
CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/calendaruserproxy.py
CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/directory.py
CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/idirectory.py
CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/principal.py
CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/resource.py
CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/scheduling/processing.py
Modified: CalendarServer/branches/users/sagen/resource-delegates-4038/bin/caldav_utility.py
===================================================================
--- CalendarServer/branches/users/sagen/resource-delegates-4038/bin/caldav_utility.py 2009-04-21 00:44:45 UTC (rev 4048)
+++ CalendarServer/branches/users/sagen/resource-delegates-4038/bin/caldav_utility.py 2009-04-21 13:23:56 UTC (rev 4049)
@@ -101,6 +101,8 @@
"add-read-delegate=",
"add-write-delegate=",
"remove-delegate=",
+ "set-auto-schedule=",
+ "get-auto-schedule",
],
)
except GetoptError, e:
@@ -188,9 +190,20 @@
result = (yield resource.removeDelegate(delegate, "read"))
result = (yield resource.removeDelegate(delegate, "write"))
+ elif opt == "--set-auto-schedule":
+ if resource is None: abort("No current resource.")
+ result = (yield resource.setAutoSchedule(arg.lower() in ("true", "1")))
+
+ elif opt == "--get-auto-schedule":
+ if resource is None: abort("No current resource.")
+
+ result = (yield resource.getAutoSchedule())
+ print "Auto-Schedule: %s" % ("True" if result else "False",)
+
+
print "Stopping reactor"
- reactor.stop()
+ reactor.callLater(0, reactor.stop)
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -200,14 +213,10 @@
self.resource = resource
def readProperty(self, prop):
- # fake a request
- request = FakeRequest()
- return self.resource.readProperty(prop, request)
+ return self.resource.readProperty(prop, FakeRequest())
def writeProperty(self, prop):
- # fake a request
- request = FakeRequest()
- return self.resource.writeProperty(prop, request)
+ return self.resource.writeProperty(prop, FakeRequest())
def getChild(self, path):
resource = self.resource
@@ -280,7 +289,11 @@
result.append(str(child))
returnValue(result)
+ def setAutoSchedule(self, autoSchedule):
+ return self.resource.setAutoSchedule(autoSchedule)
+ def getAutoSchedule(self):
+ return self.resource.getAutoSchedule()
def url(self):
return self.resource.url()
@@ -395,7 +408,7 @@
shortNames = ("dummy",),
fullName = "Dummy McDummerson",
calendarUserAddresses = set(),
- autoSchedule = False,
+ # autoSchedule = False,
)
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Modified: CalendarServer/branches/users/sagen/resource-delegates-4038/calendarserver/tools/util.py
===================================================================
--- CalendarServer/branches/users/sagen/resource-delegates-4038/calendarserver/tools/util.py 2009-04-21 00:44:45 UTC (rev 4048)
+++ CalendarServer/branches/users/sagen/resource-delegates-4038/calendarserver/tools/util.py 2009-04-21 13:23:56 UTC (rev 4049)
@@ -105,5 +105,5 @@
lastName = "McDummerson",
emailAddresses = (),
calendarUserAddresses = (),
- autoSchedule = False,
+ # autoSchedule = False,
)
Modified: CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/customxml.py 2009-04-21 00:44:45 UTC (rev 4048)
+++ CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/customxml.py 2009-04-21 13:23:56 UTC (rev 4049)
@@ -575,9 +575,17 @@
"""
Exposes the type of a record
"""
+ namespace = calendarserver_namespace
name = "record-type"
protected = True
+class AutoSchedule (davxml.WebDAVTextElement):
+ """
+ Whether the principal automatically accepts invitations
+ """
+ namespace = calendarserver_namespace
+ name = "auto-schedule"
+
##
# Extensions to davxml.ResourceType
##
Modified: CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/cachingappleopendirectory.py
===================================================================
--- CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/cachingappleopendirectory.py 2009-04-21 00:44:45 UTC (rev 4048)
+++ CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/cachingappleopendirectory.py 2009-04-21 13:23:56 UTC (rev 4049)
@@ -659,7 +659,9 @@
else:
memberGUIDs = ()
- autoSchedule = False
+ # MOR:
+ # autoSchedule = False
+
proxyGUIDs = ()
readOnlyProxyGUIDs = ()
@@ -691,7 +693,8 @@
lastName = recordLastName,
emailAddresses = recordEmailAddresses,
calendarUserAddresses = calendarUserAddresses,
- autoSchedule = autoSchedule,
+ # MOR:
+ # autoSchedule = autoSchedule,
enabledForCalendaring = enabledForCalendaring,
memberGUIDs = memberGUIDs,
proxyGUIDs = proxyGUIDs,
@@ -707,7 +710,10 @@
def __init__(
self, service, recordType, guid, nodeName, shortNames, authIDs,
fullName, firstName, lastName, emailAddresses,
- calendarUserAddresses, autoSchedule, enabledForCalendaring,
+ calendarUserAddresses,
+ # MOR:
+ # autoSchedule,
+ enabledForCalendaring,
memberGUIDs, proxyGUIDs, readOnlyProxyGUIDs,
):
super(OpenDirectoryRecord, self).__init__(
@@ -721,7 +727,8 @@
lastName = lastName,
emailAddresses = emailAddresses,
calendarUserAddresses = calendarUserAddresses,
- autoSchedule = autoSchedule,
+ # MOR:
+ # autoSchedule = autoSchedule,
enabledForCalendaring = enabledForCalendaring,
)
self.nodeName = nodeName
Modified: CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/cachingdirectory.py
===================================================================
--- CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/cachingdirectory.py 2009-04-21 00:44:45 UTC (rev 4048)
+++ CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/cachingdirectory.py 2009-04-21 13:23:56 UTC (rev 4049)
@@ -319,7 +319,9 @@
def __init__(
self, service, recordType, guid, shortNames=(), authIDs=set(),
fullName=None, firstName=None, lastName=None, emailAddresses=set(),
- calendarUserAddresses=set(), autoSchedule=False,
+ calendarUserAddresses=set(),
+ # MOR:
+ # autoSchedule=False,
enabledForCalendaring=None, uid=None,
):
super(CachingDirectoryRecord, self).__init__(
@@ -333,7 +335,8 @@
lastName = lastName,
emailAddresses = emailAddresses,
calendarUserAddresses = calendarUserAddresses,
- autoSchedule = autoSchedule,
+ # MOR:
+ # autoSchedule = autoSchedule,
enabledForCalendaring = enabledForCalendaring,
uid = uid,
)
Modified: CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/calendaruserproxy.py 2009-04-21 00:44:45 UTC (rev 4048)
+++ CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/calendaruserproxy.py 2009-04-21 13:23:56 UTC (rev 4049)
@@ -695,6 +695,8 @@
"""
)
+
+
##
# Utilities
##
Modified: CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/directory.py
===================================================================
--- CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/directory.py 2009-04-21 00:44:45 UTC (rev 4048)
+++ CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/directory.py 2009-04-21 13:23:56 UTC (rev 4049)
@@ -269,7 +269,10 @@
def __init__(
self, service, recordType, guid, shortNames=(), authIDs=set(), fullName=None,
firstName=None, lastName=None, emailAddresses=set(),
- calendarUserAddresses=set(), autoSchedule=False, enabledForCalendaring=None,
+ calendarUserAddresses=set(),
+ # MOR:
+ # autoSchedule=False,
+ enabledForCalendaring=None,
uid=None,
):
assert service.realmName is not None
@@ -309,7 +312,8 @@
self.emailAddresses = emailAddresses
self.enabledForCalendaring = enabledForCalendaring
self.calendarUserAddresses = calendarUserAddresses
- self.autoSchedule = autoSchedule
+ # MOR:
+ # self.autoSchedule = autoSchedule
def __cmp__(self, other):
if not isinstance(other, DirectoryRecord):
Modified: CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/idirectory.py
===================================================================
--- CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/idirectory.py 2009-04-21 00:44:45 UTC (rev 4048)
+++ CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/idirectory.py 2009-04-21 13:23:56 UTC (rev 4049)
@@ -101,7 +101,8 @@
lastName = Attribute("The last name of this record.")
emailAddress = Attribute("The email address of this record.")
calendarUserAddresses = Attribute("A set of calendar user addresses for this record.")
- autoSchedule = Attribute("Principal identified by this record should automatically accept/deny meetings.")
+ # MOR:
+ # autoSchedule = Attribute("Principal identified by this record should automatically accept/deny meetings.")
enabledForCalendaring = Attribute("Determines whether this record should be provisioned with a calendar home.")
def members():
Modified: CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/principal.py 2009-04-21 00:44:45 UTC (rev 4048)
+++ CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/directory/principal.py 2009-04-21 13:23:56 UTC (rev 4049)
@@ -837,8 +837,9 @@
return addresses
- def autoSchedule(self):
- return self.record.autoSchedule
+ # MOR:
+ # def autoSchedule(self):
+ # return self.record.autoSchedule
def enabledAsOrganizer(self):
if self.record.recordType == DirectoryService.recordType_users:
Modified: CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/resource.py 2009-04-21 00:44:45 UTC (rev 4048)
+++ CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/resource.py 2009-04-21 13:23:56 UTC (rev 4049)
@@ -27,6 +27,7 @@
"isPseudoCalendarCollectionResource",
]
+import os
import urllib
from zope.interface import implements
@@ -36,13 +37,12 @@
from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.web2 import responsecode
from twisted.web2.dav import davxml
+from twisted.web2.dav.davxml import dav_namespace
+from twisted.web2.dav.http import ErrorResponse
from twisted.web2.dav.idav import IDAVPrincipalCollectionResource
from twisted.web2.dav.resource import AccessDeniedError, DAVPrincipalCollectionResource
-from twisted.web2.dav.davxml import dav_namespace
-from twisted.web2.dav.http import ErrorResponse
from twisted.web2.dav.resource import TwistedACLInheritable
-from twisted.web2.dav.util import joinURL, parentForURL, unimplemented,\
- normalizeURL
+from twisted.web2.dav.util import joinURL, parentForURL, unimplemented, normalizeURL
from twisted.web2.http import HTTPError, RedirectResponse, StatusResponse, Response
from twisted.web2.http_headers import MimeType
from twisted.web2.iweb import IResponse
@@ -51,16 +51,18 @@
import twistedcaldav
from twistedcaldav import caldavxml, customxml
+from twistedcaldav.caldavxml import caldav_namespace
from twistedcaldav.config import config
from twistedcaldav.customxml import TwistedCalendarAccessProperty
+from twistedcaldav.customxml import calendarserver_namespace
from twistedcaldav.extensions import DAVResource, DAVPrincipalResource
from twistedcaldav.ical import Component
+from twistedcaldav.ical import Component as iComponent
+from twistedcaldav.ical import allowedComponents
from twistedcaldav.icaldav import ICalDAVResource, ICalendarPrincipalResource
-from twistedcaldav.caldavxml import caldav_namespace
-from twistedcaldav.customxml import calendarserver_namespace
-from twistedcaldav.ical import allowedComponents
-from twistedcaldav.ical import Component as iComponent
from twistedcaldav.log import LoggingMixIn
+from twistedcaldav.memcacher import Memcacher
+from twistedcaldav.sql import AbstractSQLDatabase, db_prefix
from urlparse import urlsplit
@@ -828,6 +830,7 @@
(caldav_namespace, "calendar-user-type" ),
(calendarserver_namespace, "calendar-proxy-read-for" ),
(calendarserver_namespace, "calendar-proxy-write-for" ),
+ (calendarserver_namespace, "auto-schedule" ),
)
@classmethod
@@ -898,9 +901,23 @@
*[davxml.HRef(principal.principalURL()) for principal in results]
))
+ elif name == "auto-schedule":
+ autoSchedule = (yield self.getAutoSchedule())
+ returnValue(customxml.AutoSchedule("true" if autoSchedule else "false"))
+
result = (yield super(CalendarPrincipalResource, self).readProperty(property, request))
returnValue(result)
+ def writeProperty(self, property, request):
+ assert isinstance(property, davxml.WebDAVElement), (
+ "%r is not a WebDAVElement instance" % (property,)
+ )
+
+ if property.qname() == (caldav_namespace, "auto-schedule"):
+ self.setAutoSchedule(autoSchedule) # MOR: parse the value
+
+ return super(CalendarPrincipalResource, self).writeProperty(property, request)
+
def calendarHomeURLs(self):
if self.hasDeadProperty((caldav_namespace, "calendar-home-set")):
home_set = self.readDeadProperty((caldav_namespace, "calendar-home-set"))
@@ -989,6 +1006,25 @@
"""
return None
+ def setAutoSchedule(self, autoSchedule):
+ self._index().setAutoSchedule(self.record.guid, autoSchedule)
+
+ def getAutoSchedule(self):
+ return self._index().getAutoSchedule(self.record.guid)
+
+ def _index(self):
+ """
+ Return the SQL database for this calendar principal.
+
+ @return: the L{ResourceInfoDatabase} for the calendar principal.
+ """
+
+ # The db is located in the data root
+ self.pcollection = self.parent.parent # MOR: doesn't feel right
+ if not hasattr(self.pcollection, "resource_info_db"):
+ setattr(self.pcollection, "resource_info_db", ResourceInfoDatabase(config.DataRoot))
+ return self.pcollection.resource_info_db
+
##
# Utilities
##
@@ -1008,3 +1044,140 @@
return False
else:
return resource.isPseudoCalendarCollection()
+
+
+class ResourceInfoDatabase(AbstractSQLDatabase, LoggingMixIn):
+ """
+ A database to maintain resource (and location) information
+
+ SCHEMA:
+
+ Group Database:
+
+ ROW: GUID, AUTOSCHEDULE
+
+ """
+
+ dbType = "RESOURCEINFO"
+ dbFilename = "resourceinfo.sqlite"
+ dbOldFilename = db_prefix + "resourceinfo"
+ dbFormatVersion = "1"
+
+ class ResourceInfoDBMemcacher(Memcacher):
+
+ def setAutoSchedule(self, guid, autoSchedule):
+ print "Sending to memcache", "1" if autoSchedule else "0"
+ return self.set("resourceinfo:%s" % (str(guid),), "1" if autoSchedule else "0")
+
+ @inlineCallbacks
+ def getAutoSchedule(self, guid):
+ result = (yield self.get("resourceinfo:%s" % (str(guid),)))
+ print "Result from memcache is:", result
+ if result is not None:
+ autoSchedule = result == "1"
+ else:
+ autoSchedule = None
+ print "Therefore, getting back from memcache:", autoSchedule
+ returnValue(autoSchedule)
+
+ def __init__(self, path):
+ path = os.path.join(path, ResourceInfoDatabase.dbFilename)
+ super(ResourceInfoDatabase, self).__init__(path, True)
+
+ self._memcacher = ResourceInfoDatabase.ResourceInfoDBMemcacher("resourceInfoDB")
+
+ @inlineCallbacks
+ def setAutoSchedule(self, guid, autoSchedule):
+ """
+ Set a resource/location's auto-Schedule boolean.
+
+ @param guid: the UID of the group principal to add.
+ @param autoSchedule: boolean
+ """
+
+ # Remove what is there, then add it back.
+ self._delete_from_db(guid)
+ self._add_to_db(guid, autoSchedule)
+ self._db_commit()
+
+ # Update cache
+ _ignore = (yield self._memcacher.setAutoSchedule(guid, autoSchedule))
+
+ @inlineCallbacks
+ def getAutoSchedule(self, guid):
+ """
+ Return the auto-Schedule state for the resource/location specified by guid
+ """
+
+ # Pull from cache
+ autoSchedule = (yield self._memcacher.getAutoSchedule(guid))
+ if autoSchedule is None:
+ # Not in memcache, check local db
+ autoSchedule = self._db_value_for_sql("select AUTOSCHEDULE from RESOURCEINFO where GUID = :1", guid)
+ if autoSchedule is not None:
+ autoSchedule = autoSchedule == 1
+ result = (yield self._memcacher.setAutoSchedule(guid, autoSchedule))
+ else:
+ # Not in local db
+ # MOR: no value -- what to do, default to False?
+ autoSchedule = False
+
+ returnValue(autoSchedule)
+
+ def _add_to_db(self, guid, autoSchedule):
+ """
+ Insert the specified entry into the database.
+
+ @param guid: the guid of the resource/location
+ @param autoSchedule: a boolean
+ """
+ self._db_execute(
+ """
+ insert into RESOURCEINFO (GUID, AUTOSCHEDULE)
+ values (:1, :2)
+ """, guid, 1 if autoSchedule else 0
+ )
+
+ def _delete_from_db(self, guid):
+ """
+ Deletes the specified entry from the database.
+
+ @param guid: the guid of the resource/location to delete
+ """
+ self._db_execute("delete from RESOURCEINFO where GUID = :1", guid)
+
+ def _db_version(self):
+ """
+ @return: the schema version assigned to this index.
+ """
+ return ResourceInfoDatabase.dbFormatVersion
+
+ def _db_type(self):
+ """
+ @return: the collection type assigned to this index.
+ """
+ return ResourceInfoDatabase.dbType
+
+ def _db_init_data_tables(self, q):
+ """
+ Initialise the underlying database tables.
+ @param q: a database cursor to use.
+ """
+
+ #
+ # RESOURCEINFO table
+ #
+ q.execute(
+ """
+ create table RESOURCEINFO (
+ GUID text,
+ AUTOSCHEDULE integer
+ )
+ """
+ )
+ q.execute(
+ """
+ create index RESOURCEGUIDS on RESOURCEINFO (GUID)
+ """
+ )
+
Modified: CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/scheduling/processing.py
===================================================================
--- CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/scheduling/processing.py 2009-04-21 00:44:45 UTC (rev 4048)
+++ CalendarServer/branches/users/sagen/resource-delegates-4038/twistedcaldav/scheduling/processing.py 2009-04-21 13:23:56 UTC (rev 4049)
@@ -268,7 +268,7 @@
raise ImplicitProcessorException(iTIPRequestStatus.NO_USER_SUPPORT)
log.debug("ImplicitProcessing - originator '%s' to recipient '%s' ignoring METHOD:REQUEST, UID: '%s' - new processed" % (self.originator.cuaddr, self.recipient.cuaddr, self.uid))
- autoprocessed = self.recipient.principal.autoSchedule()
+ autoprocessed = self.recipient.principal.getAutoSchedule()
new_calendar = iTipProcessing.processNewRequest(self.message, self.recipient.cuaddr, autoprocessing=autoprocessed)
name = md5(str(new_calendar) + str(time.time()) + default.fp.path).hexdigest() + ".ics"
@@ -291,7 +291,7 @@
result = (True, autoprocessed, changes,)
else:
# Processing update to existing event
- autoprocessed = self.recipient.principal.autoSchedule()
+ autoprocessed = self.recipient.principal.getAutoSchedule()
new_calendar, props_changed, rids = iTipProcessing.processRequest(self.message, self.recipient_calendar, self.recipient.cuaddr, autoprocessing=autoprocessed)
if new_calendar:
@@ -350,7 +350,7 @@
else:
# Need to check for auto-respond attendees. These need to suppress the inbox message
# if the cancel is processed.
- autoprocessed = self.recipient.principal.autoSchedule()
+ autoprocessed = self.recipient.principal.getAutoSchedule()
# Check to see if this is a cancel of the entire event
processed_message, delete_original, rids = iTipProcessing.processCancel(self.message, self.recipient_calendar, autoprocessing=autoprocessed)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090421/6f8cd5f8/attachment-0001.html>
More information about the calendarserver-changes
mailing list