[CalendarServer-changes] [2995] CalendarServer/branches/users/sagen/principal-property-search-2970
source_changes at macosforge.org
source_changes at macosforge.org
Mon Sep 15 12:12:50 PDT 2008
Revision: 2995
http://trac.macosforge.org/projects/calendarserver/changeset/2995
Author: sagen at apple.com
Date: 2008-09-15 12:12:49 -0700 (Mon, 15 Sep 2008)
Log Message:
-----------
Checkpoint of progress towards fast REPORT-based search. This iteration directly queries OD rather than searching through every resource.
Modified Paths:
--------------
CalendarServer/branches/users/sagen/principal-property-search-2970/conf/accounts-test.xml
CalendarServer/branches/users/sagen/principal-property-search-2970/lib-patches/Twisted/twisted.web2.dav.element.rfc3744.patch
CalendarServer/branches/users/sagen/principal-property-search-2970/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch
CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/customxml.py
CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/aggregate.py
CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/apache.py
CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/appleopendirectory.py
CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/directory.py
CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/idirectory.py
CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/principal.py
CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/sudo.py
CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/xmlaccountsparser.py
CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/xmlfile.py
CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/resource.py
Modified: CalendarServer/branches/users/sagen/principal-property-search-2970/conf/accounts-test.xml
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-2970/conf/accounts-test.xml 2008-09-13 17:34:06 UTC (rev 2994)
+++ CalendarServer/branches/users/sagen/principal-property-search-2970/conf/accounts-test.xml 2008-09-15 19:12:49 UTC (rev 2995)
@@ -24,12 +24,16 @@
<guid>admin</guid>
<password>admin</password>
<name>Super User</name>
+ <first-name>Super</first-name>
+ <last-name>User</last-name>
</user>
<user>
<uid>apprentice</uid>
<guid>apprentice</guid>
<password>apprentice</password>
<name>Apprentice Super User</name>
+ <first-name>Apprentice</first-name>
+ <last-name>Super User</last-name>
</user>
<user repeat="99">
<uid>user%02d</uid>
@@ -37,6 +41,8 @@
<password>user%02d</password>
<name>User %02d</name>
<cuaddr>mailto:user%02d at example.com</cuaddr>
+ <first-name>User</first-name>
+ <last-name>%02d</last-name>
</user>
<user repeat="10">
<uid>public%02d</uid>
@@ -44,6 +50,8 @@
<password>public%02d</password>
<name>Public %02d</name>
<cuaddr>mailto:public%02d at example.com</cuaddr>
+ <first-name>Public</first-name>
+ <last-name>%02d</last-name>
</user>
<location repeat="10">
<uid>location%02d</uid>
Modified: CalendarServer/branches/users/sagen/principal-property-search-2970/lib-patches/Twisted/twisted.web2.dav.element.rfc3744.patch
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-2970/lib-patches/Twisted/twisted.web2.dav.element.rfc3744.patch 2008-09-13 17:34:06 UTC (rev 2994)
+++ CalendarServer/branches/users/sagen/principal-property-search-2970/lib-patches/Twisted/twisted.web2.dav.element.rfc3744.patch 2008-09-15 19:12:49 UTC (rev 2995)
@@ -81,3 +81,11 @@
# This element can be empty when uses in supported-report-set
if not len(self.children):
+@@ -705,6 +714,7 @@
+ (dav_namespace, "prop" ): (0, 1),
+ (dav_namespace, "apply-to-principal-collection-set"): (0, 1),
+ }
++ allowed_attributes = { "test": False }
+
+ class PropertySearch (WebDAVElement):
+ """
Modified: CalendarServer/branches/users/sagen/principal-property-search-2970/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-2970/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch 2008-09-13 17:34:06 UTC (rev 2994)
+++ CalendarServer/branches/users/sagen/principal-property-search-2970/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch 2008-09-15 19:12:49 UTC (rev 2995)
@@ -2,7 +2,101 @@
===================================================================
--- twisted/web2/dav/method/report_principal_property_search.py (revision 19773)
+++ twisted/web2/dav/method/report_principal_property_search.py (working copy)
-@@ -127,13 +127,8 @@
+@@ -46,17 +46,23 @@
+ Generate a principal-property-search REPORT. (RFC 3744, section 9.4)
+ """
+
++
+ # Verify root element
+ if not isinstance(principal_property_search, davxml.PrincipalPropertySearch):
+ raise ValueError("%s expected as root element, not %s."
+ % (davxml.PrincipalPropertySearch.sname(), principal_property_search.sname()))
+
++ # Should we AND (the default) or OR (if test="anyof")?
++ testMode = principal_property_search.attributes.get("test", "allof")
++ if testMode not in ("allof", "anyof"):
++ raise ValueError("Unknown value for test attribute: %s" % (testMode,))
++
+ # Only handle Depth: 0
+ depth = request.headers.getHeader("depth", "0")
+ if depth != "0":
+ log.err("Error in prinicpal-property-search REPORT, Depth set to %s" % (depth,))
+ raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, "Depth %s not allowed" % (depth,)))
+-
++
+ # Get a single DAV:prop element from the REPORT request body
+ propertiesForResource = None
+ propElement = None
+@@ -93,31 +99,53 @@
+ else:
+ return False
+
+- def propertySearch(resource, request):
++ def propertySearch(resource, request, testMode):
+ """
+ Test the resource to see if it contains properties matching the
+ property-search specification in this report.
+ @param resource: the L{DAVFile} for the resource to test.
+ @param request: the current request.
++ @param testMode: "allof" (AND operation) or "anyof" (OR operation)
+ @return: True if the resource has matching properties, False otherwise.
+ """
+- for props, match in propertySearches:
+- # Test each property
+- for prop in props:
+- try:
+- propvalue = waitForDeferred(resource.readProperty(prop.qname(), request))
+- yield propvalue
+- propvalue = propvalue.getResult()
+- if propvalue and not nodeMatch(propvalue, match):
++
++ if testMode == "allof": # "AND"
++ for props, match in propertySearches:
++ # Test each property
++ for prop in props:
++ try:
++ propvalue = waitForDeferred(resource.readProperty(prop.qname(), request))
++ yield propvalue
++ propvalue = propvalue.getResult()
++ if propvalue:
++ if not nodeMatch(propvalue, match):
++ yield False
++ return
++ except HTTPError:
++ # No property => no match
+ yield False
+ return
+- except HTTPError:
+- # No property => no match
+- yield False
+- return
+-
+- yield True
++ # we hit on every property
++ yield True
+
++ else: # "OR"
++ for props, match in propertySearches:
++ # Test each property
++ for prop in props:
++ try:
++ propvalue = waitForDeferred(resource.readProperty(prop.qname(), request))
++ yield propvalue
++ propvalue = propvalue.getResult()
++ if propvalue:
++ if nodeMatch(propvalue, match):
++ yield True
++ return
++ except HTTPError:
++ # No property
++ pass
++ # we didn't hit any
++ yield False
++
+ propertySearch = deferredGenerator(propertySearch)
+
+ # Run report
+@@ -127,13 +155,8 @@
matchcount = 0
if applyTo:
@@ -18,3 +112,103 @@
resource = waitForDeferred(request.locateResource(uri))
yield resource
resource = resource.getResult()
+@@ -142,42 +165,67 @@
+ else:
+ resources.append((self, request.uri))
+
+- # Loop over all collections and principal resources within
+- for resource, ruri in resources:
++ if True:
+
+- # Do some optimisation of access control calculation by determining any inherited ACLs outside of
+- # the child resource loop and supply those to the checkPrivileges on each child.
+- filteredaces = waitForDeferred(resource.inheritedACEsforChildren(request))
+- yield filteredaces
+- filteredaces = filteredaces.getResult()
++ for record in self.directory.recordsStartingWith("mor"):
++ resource = self.principalForRecord(record)
++ url = resource.url()
+
+- children = []
+- d = waitForDeferred(resource.findChildren("infinity", request, lambda x, y: children.append((x,y)),
+- privileges=(davxml.Read(),), inherited_aces=filteredaces))
+- yield d
+- d.getResult()
++ # Check size of results is within limit
++ matchcount += 1
++ if matchcount > max_number_of_matches:
++ raise NumberOfMatchesWithinLimits
+
+- for child, uri in children:
+- if isPrincipalResource(child):
+- d = waitForDeferred(propertySearch(child, request))
+- yield d
+- d = d.getResult()
+- if d:
+- # Check size of results is within limit
+- matchcount += 1
+- if matchcount > max_number_of_matches:
+- raise NumberOfMatchesWithinLimits
+-
+- d = waitForDeferred(prop_common.responseForHref(
+- request,
+- responses,
+- davxml.HRef.fromString(uri),
+- child,
+- propertiesForResource,
+- propElement
+- ))
++ d = waitForDeferred(prop_common.responseForHref(
++ request,
++ responses,
++ davxml.HRef.fromString(url),
++ resource,
++ propertiesForResource,
++ propElement
++ ))
++ yield d
++ d.getResult()
++
++ else:
++
++ # Loop over all collections and principal resources within
++ for resource, ruri in resources:
++
++ # Do some optimisation of access control calculation by determining any inherited ACLs outside of
++ # the child resource loop and supply those to the checkPrivileges on each child.
++ filteredaces = waitForDeferred(resource.inheritedACEsforChildren(request))
++ yield filteredaces
++ filteredaces = filteredaces.getResult()
++
++ children = []
++ # d = waitForDeferred(resource.findChildren("infinity", request, lambda x, y: children.append((x,y)),
++ d = waitForDeferred(resource.findChildren("1", request, lambda x, y: children.append((x,y)),
++ privileges=(davxml.Read(),), inherited_aces=filteredaces))
++ yield d
++ d.getResult()
++
++ for child, uri in children:
++ if isPrincipalResource(child):
++ d = waitForDeferred(propertySearch(child, request, testMode))
+ yield d
+- d.getResult()
++ d = d.getResult()
++ if d:
++ # Check size of results is within limit
++ matchcount += 1
++ if matchcount > max_number_of_matches:
++ raise NumberOfMatchesWithinLimits
++
++ d = waitForDeferred(prop_common.responseForHref(
++ request,
++ responses,
++ davxml.HRef.fromString(uri),
++ child,
++ propertiesForResource,
++ propElement
++ ))
++ yield d
++ d.getResult()
+
+ except NumberOfMatchesWithinLimits:
+ log.err("Too many matching components in prinicpal-property-search report")
Modified: CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/customxml.py 2008-09-13 17:34:06 UTC (rev 2994)
+++ CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/customxml.py 2008-09-15 19:12:49 UTC (rev 2995)
@@ -290,6 +290,22 @@
protected = True
hidden = True
+class FirstNameProperty (davxml.WebDAVTextElement):
+ """
+ A property representing first name of a principal
+ """
+ namespace = calendarserver_namespace
+ name = "first-name"
+ protected = True
+
+class LastNameProperty (davxml.WebDAVTextElement):
+ """
+ A property representing last name of a principal
+ """
+ namespace = calendarserver_namespace
+ name = "last-name"
+ protected = True
+
class IScheduleInbox (davxml.WebDAVEmptyElement):
"""
Denotes the resourcetype of a iSchedule Inbox.
Modified: CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/aggregate.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/aggregate.py 2008-09-13 17:34:06 UTC (rev 2994)
+++ CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/aggregate.py 2008-09-15 19:12:49 UTC (rev 2995)
@@ -103,6 +103,9 @@
def recordWithCalendarUserAddress(self, address):
return self._queryAll("recordWithCalendarUserAddress", address)
+ def recordsStartingWith(self, str):
+ return self._queryAll("recordsStartingWith", str)
+
def serviceForRecordType(self, recordType):
try:
return self._recordTypes[recordType]
Modified: CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/apache.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/apache.py 2008-09-13 17:34:06 UTC (rev 2994)
+++ CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/apache.py 2008-09-15 19:12:49 UTC (rev 2995)
@@ -129,6 +129,8 @@
guid = None,
shortName = shortName,
fullName = None,
+ firstName = None,
+ lastName = None,
calendarUserAddresses = set(),
autoSchedule = False,
)
Modified: CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/appleopendirectory.py 2008-09-13 17:34:06 UTC (rev 2994)
+++ CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/appleopendirectory.py 2008-09-15 19:12:49 UTC (rev 2995)
@@ -460,6 +460,62 @@
return record
+ def recordsStartingWith(self, string):
+ results = opendirectory.queryRecordsWithAttributes(
+ self.directory,
+ dsquery.expression(dsquery.expression.OR,
+ (
+ dsquery.match(dsattributes.kDS1AttrFirstName, string,
+ dsattributes.eDSStartsWith),
+ dsquery.match(dsattributes.kDS1AttrLastName, string,
+ dsattributes.eDSStartsWith),
+ dsquery.match(dsattributes.kDSNAttrEMailAddress, string,
+ dsattributes.eDSStartsWith)
+ )
+ ).generate(),
+ True,
+ dsattributes.kDSStdRecordTypeUsers,
+ [
+ dsattributes.kDS1AttrGeneratedUID,
+ dsattributes.kDS1AttrFirstName,
+ dsattributes.kDS1AttrLastName,
+ dsattributes.kDSNAttrEMailAddress,
+ dsattributes.kDS1AttrDistinguishedName,
+ dsattributes.kDSNAttrMetaNodeLocation,
+ ]
+ )
+ returning = []
+ for key, val in results.iteritems():
+ try:
+ calendarUserAddresses = set()
+ enabledForCalendaring = False
+ if val.has_key(dsattributes.kDSNAttrEMailAddress):
+ enabledForCalendaring = True
+ calendarUserAddresses.add(val[dsattributes.kDSNAttrEMailAddress])
+ rec = OpenDirectoryRecord(
+ service = self,
+ recordType = DirectoryService.recordType_users,
+ guid = val[dsattributes.kDS1AttrGeneratedUID],
+ nodeName = val[dsattributes.kDSNAttrMetaNodeLocation],
+ shortName = key,
+ fullName = val[dsattributes.kDS1AttrDistinguishedName],
+ firstName = val[dsattributes.kDS1AttrFirstName],
+ lastName = val[dsattributes.kDS1AttrLastName],
+ calendarUserAddresses = calendarUserAddresses,
+ autoSchedule = False,
+ enabledForCalendaring = enabledForCalendaring,
+ memberGUIDs = (),
+ proxyGUIDs = (),
+ readOnlyProxyGUIDs = (),
+ )
+ returning.append(rec)
+ except Exception, e:
+ print e
+ import pdb; pdb.set_trace()
+
+ return returning
+
+
def reloadCache(self, recordType, shortName=None, guid=None):
if shortName:
self.log_info("Faulting record %s into %s record cache" % (shortName, recordType))
@@ -533,6 +589,8 @@
# Now get useful record info.
recordGUID = value.get(dsattributes.kDS1AttrGeneratedUID)
recordFullName = value.get(dsattributes.kDS1AttrDistinguishedName)
+ recordFirstName = value.get(dsattributes.kDS1AttrFirstName)
+ recordLastName = value.get(dsattributes.kDS1AttrLastName)
recordNodeName = value.get(dsattributes.kDSNAttrMetaNodeLocation)
if not recordGUID:
@@ -581,6 +639,8 @@
nodeName = recordNodeName,
shortName = recordShortName,
fullName = recordFullName,
+ firstName = recordFirstName,
+ lastName = recordLastName,
calendarUserAddresses = calendarUserAddresses,
autoSchedule = autoSchedule,
enabledForCalendaring = enabledForCalendaring,
@@ -665,6 +725,8 @@
attrs = [
dsattributes.kDS1AttrGeneratedUID,
dsattributes.kDS1AttrDistinguishedName,
+ dsattributes.kDS1AttrFirstName,
+ dsattributes.kDS1AttrLastName,
dsattributes.kDSNAttrEMailAddress,
dsattributes.kDSNAttrServicesLocator,
dsattributes.kDSNAttrMetaNodeLocation,
@@ -827,6 +889,7 @@
"""
def __init__(
self, service, recordType, guid, nodeName, shortName, fullName,
+ firstName, lastName,
calendarUserAddresses, autoSchedule, enabledForCalendaring,
memberGUIDs, proxyGUIDs, readOnlyProxyGUIDs,
):
@@ -836,6 +899,8 @@
guid = guid,
shortName = shortName,
fullName = fullName,
+ firstName = firstName,
+ lastName = lastName,
calendarUserAddresses = calendarUserAddresses,
autoSchedule = autoSchedule,
enabledForCalendaring = enabledForCalendaring,
Modified: CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/directory.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/directory.py 2008-09-13 17:34:06 UTC (rev 2994)
+++ CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/directory.py 2008-09-15 19:12:49 UTC (rev 2995)
@@ -155,6 +155,7 @@
def __init__(
self, service, recordType, guid, shortName, fullName,
+ firstName, lastName,
calendarUserAddresses, autoSchedule, enabledForCalendaring=True,
):
assert service.realmName is not None
@@ -174,6 +175,8 @@
self.guid = guid
self.shortName = shortName
self.fullName = fullName
+ self.firstName = firstName
+ self.lastName = lastName
self.enabledForCalendaring = enabledForCalendaring
self.calendarUserAddresses = calendarUserAddresses
self.autoSchedule = autoSchedule
Modified: CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/idirectory.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/idirectory.py 2008-09-13 17:34:06 UTC (rev 2994)
+++ CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/idirectory.py 2008-09-15 19:12:49 UTC (rev 2995)
@@ -72,6 +72,14 @@
addresses.
"""
+ def recordsStartingWith(string):
+ """
+ @return: a sequence of L{IDirectoryRecord}s whose first name, last
+ name, or email address start with the given string (case
+ insensitive)
+ """
+
+
class IDirectoryRecord(Interface):
"""
Directory Record
@@ -81,6 +89,8 @@
guid = Attribute("The GUID of this record.")
shortName = Attribute("The name of this record.")
fullName = Attribute("The full name of this record.")
+ firstName = Attribute("The first name of this record.")
+ lastName = Attribute("The last name 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.")
enabledForCalendaring = Attribute("Determines whether this record should be provisioned with a calendar home.")
Modified: CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/principal.py 2008-09-13 17:34:06 UTC (rev 2994)
+++ CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/principal.py 2008-09-15 19:12:49 UTC (rev 2995)
@@ -437,6 +437,8 @@
"""Record type: %s\n""" % (self.record.recordType,),
"""Short name: %s\n""" % (self.record.shortName,),
"""Full name: %s\n""" % (self.record.fullName,),
+ """First name: %s\n""" % (self.record.firstName,),
+ """Last name: %s\n""" % (self.record.lastName,),
"""Principal UID: %s\n""" % (self.principalUID(),),
"""Principal URL: %s\n""" % (format_link(self.principalURL()),),
"""\nAlternate URIs:\n""" , format_list(format_link(u) for u in self.alternateURIs()),
@@ -597,6 +599,8 @@
"""Record type: %s\n""" % (self.record.recordType,),
"""Short name: %s\n""" % (self.record.shortName,),
"""Full name: %s\n""" % (self.record.fullName,),
+ """First name: %s\n""" % (self.record.firstName,),
+ """Last name: %s\n""" % (self.record.lastName,),
"""Principal UID: %s\n""" % (self.principalUID(),),
"""Principal URL: %s\n""" % (format_link(self.principalURL()),),
"""\nAlternate URIs:\n""" , format_list(format_link(u) for u in self.alternateURIs()),
Modified: CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/sudo.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/sudo.py 2008-09-13 17:34:06 UTC (rev 2994)
+++ CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/sudo.py 2008-09-15 19:12:49 UTC (rev 2995)
@@ -98,6 +98,9 @@
if entry['username'] == shortName:
return self._recordForEntry(entry)
+ def recordsStartingWith(self, string):
+ return None
+
def requestAvatarId(self, credentials):
# FIXME: ?
# We were checking if principal is enabled; seems unnecessary in current
@@ -132,6 +135,8 @@
guid=None,
shortName=shortName,
fullName=shortName,
+ firstName="",
+ lastName="",
calendarUserAddresses=set(),
autoSchedule=False,
enabledForCalendaring=False)
Modified: CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/xmlaccountsparser.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/xmlaccountsparser.py 2008-09-13 17:34:06 UTC (rev 2994)
+++ CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/xmlaccountsparser.py 2008-09-15 19:12:49 UTC (rev 2995)
@@ -43,6 +43,8 @@
ELEMENT_GUID = "guid"
ELEMENT_PASSWORD = "password"
ELEMENT_NAME = "name"
+ELEMENT_FIRST_NAME = "first-name"
+ELEMENT_LAST_NAME = "last-name"
ELEMENT_MEMBERS = "members"
ELEMENT_MEMBER = "member"
ELEMENT_CUADDR = "cuaddr"
@@ -163,6 +165,8 @@
self.guid = None
self.password = None
self.name = None
+ self.firstName = None
+ self.lastName = None
self.members = set()
self.groups = set()
self.calendarUserAddresses = set()
@@ -195,6 +199,14 @@
name = self.name % ctr
else:
name = self.name
+ if self.firstName and self.firstName.find("%") != -1:
+ firstName = self.firstName % ctr
+ else:
+ firstName = self.firstName
+ if self.lastName and self.lastName.find("%") != -1:
+ lastName = self.lastName % ctr
+ else:
+ lastName = self.lastName
calendarUserAddresses = set()
for cuaddr in self.calendarUserAddresses:
if cuaddr.find("%") != -1:
@@ -207,6 +219,8 @@
result.guid = guid
result.password = password
result.name = name
+ result.firstName = firstName
+ result.lastName = lastName
result.members = self.members
result.calendarUserAddresses = calendarUserAddresses
result.autoSchedule = self.autoSchedule
@@ -237,6 +251,12 @@
elif child_name == ELEMENT_NAME:
if child.firstChild is not None:
self.name = child.firstChild.data.encode("utf-8")
+ elif child_name == ELEMENT_FIRST_NAME:
+ if child.firstChild is not None:
+ self.firstName = child.firstChild.data.encode("utf-8")
+ elif child_name == ELEMENT_LAST_NAME:
+ if child.firstChild is not None:
+ self.lastName = child.firstChild.data.encode("utf-8")
elif child_name == ELEMENT_MEMBERS:
self._parseMembers(child, self.members)
elif child_name == ELEMENT_CUADDR:
Modified: CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/xmlfile.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/xmlfile.py 2008-09-13 17:34:06 UTC (rev 2994)
+++ CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/directory/xmlfile.py 2008-09-15 19:12:49 UTC (rev 2995)
@@ -108,6 +108,8 @@
guid = xmlPrincipal.guid,
shortName = shortName,
fullName = xmlPrincipal.name,
+ firstName = xmlPrincipal.firstName,
+ lastName = xmlPrincipal.lastName,
calendarUserAddresses = xmlPrincipal.calendarUserAddresses,
autoSchedule = xmlPrincipal.autoSchedule,
enabledForCalendaring = xmlPrincipal.enabledForCalendaring,
Modified: CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/resource.py 2008-09-13 17:34:06 UTC (rev 2994)
+++ CalendarServer/branches/users/sagen/principal-property-search-2970/twistedcaldav/resource.py 2008-09-15 19:12:49 UTC (rev 2995)
@@ -705,6 +705,8 @@
(caldav_namespace, "calendar-user-address-set"),
(caldav_namespace, "schedule-inbox-URL" ),
(caldav_namespace, "schedule-outbox-URL" ),
+ (calendarserver_namespace, "first-name" ),
+ (calendarserver_namespace, "last-name" ),
)
@classmethod
@@ -760,6 +762,21 @@
else:
return customxml.DropBoxHomeURL(davxml.HRef(url))
+ if name == "first-name":
+ firstName = self.record.firstName
+ if firstName:
+ return customxml.FirstNameProperty(firstName)
+ else:
+ return None
+
+ if name == "last-name":
+ lastName = self.record.lastName
+ if lastName:
+ return customxml.LastNameProperty(lastName)
+ else:
+ return None
+
+
return super(CalendarPrincipalResource, self).readProperty(property, request)
return maybeDeferred(defer)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20080915/73b227ab/attachment-0001.html
More information about the calendarserver-changes
mailing list