[CalendarServer-changes] [1635]
CalendarServer/branches/release/CalendarServer-1.0-dev
source_changes at macosforge.org
source_changes at macosforge.org
Mon Jul 2 13:29:36 PDT 2007
Revision: 1635
http://trac.macosforge.org/projects/calendarserver/changeset/1635
Author: wsanchez at apple.com
Date: 2007-07-02 13:29:35 -0700 (Mon, 02 Jul 2007)
Log Message:
-----------
Pull-up r1629 from trunk
Modified Paths:
--------------
CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts-test.xml
CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts.dtd
CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts.xml
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/customxml.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/apache.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/appleopendirectory.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/calendaruserproxy.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/directory.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/principal.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/sqldb.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/sudo.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/accounts.xml
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_opendirectory.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_opendirectoryschema.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_principal.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_xmlfile.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlaccountsparser.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlfile.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/schedule.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/static.py
Added Paths:
-----------
CalendarServer/branches/release/CalendarServer-1.0-dev/doc/User/
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts-test.xml
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts-test.xml 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts-test.xml 2007-07-02 20:29:35 UTC (rev 1635)
@@ -40,11 +40,16 @@
<uid>location%02d</uid>
<password>location%02d</password>
<name>Room %02d</name>
+ <auto-schedule/>
</location>
<resource repeat="10">
<uid>resource%02d</uid>
<password>resource%02d</password>
<name>Resource %02d</name>
+ <auto-schedule/>
+ <proxies>
+ <member type="users">user01</member>
+ </proxies>
</resource>
<group>
<uid>group01</uid>
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts.dtd
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts.dtd 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts.dtd 2007-07-02 20:29:35 UTC (rev 1635)
@@ -16,31 +16,30 @@
DRI: Cyrus Daboo, cdaboo at apple.com
-->
-<!ELEMENT accounts (user*, group*, resource*) >
+<!ELEMENT accounts (user*, group*, resource*, location*) >
<!ATTLIST accounts realm CDATA "">
- <!ELEMENT user (uid, guid, password, name, cuaddr*, calendar*, quota?, autorespond?)>
+ <!ELEMENT user (uid, guid, password, name, cuaddr*)>
<!ATTLIST user repeat CDATA "1">
- <!ELEMENT group (uid, guid, password, name, members, cuaddr*, calendar*, quota?)>
+ <!ELEMENT group (uid, guid, password, name, members, cuaddr*)>
<!ATTLIST group repeat CDATA "1">
- <!ELEMENT resource (uid, guid, password, name, cuaddr*, calendar*, quota?, autorespond?)>
+ <!ELEMENT resource (uid, guid, password, name, cuaddr*, auto-schedule?, proxies?)>
<!ATTLIST resource repeat CDATA "1">
- <!ELEMENT location (uid, guid, password, name, cuaddr*, calendar*, quota?, autorespond?)>
+ <!ELEMENT location (uid, guid, password, name, cuaddr*, auto-schedule?, proxies?)>
<!ATTLIST location repeat CDATA "1">
<!ELEMENT member (#PCDATA)>
<!ATTLIST member type (users|groups|locations|resources) "users">
- <!ELEMENT uid (#PCDATA)>
- <!ELEMENT guid (#PCDATA)>
- <!ELEMENT password (#PCDATA)>
- <!ELEMENT name (#PCDATA)>
- <!ELEMENT cuaddr (#PCDATA)>
- <!ELEMENT calendar (#PCDATA)>
- <!ELEMENT quota (#PCDATA)>
- <!ELEMENT autorespond EMPTY>
- <!ELEMENT members (member*)>
+ <!ELEMENT uid (#PCDATA)>
+ <!ELEMENT guid (#PCDATA)>
+ <!ELEMENT password (#PCDATA)>
+ <!ELEMENT name (#PCDATA)>
+ <!ELEMENT cuaddr (#PCDATA)>
+ <!ELEMENT members (member*)>
+ <!ELEMENT auto-schedule EMPTY>
+ <!ELEMENT proxies (member*)>
>
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts.xml
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts.xml 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts.xml 2007-07-02 20:29:35 UTC (rev 1635)
@@ -38,10 +38,14 @@
<member type="users">test</member>
</members>
</group>
- <resource>
+ <location>
<uid>mercury</uid>
<password>mercury</password>
<name>Mecury Conference Room, Building 1, 2nd Floor</name>
- </resource>
+ <auto-schedule/>
+ <proxies>
+ <member type="users">test</member>
+ </proxies>
+ </location>
</accounts>
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/customxml.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/customxml.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -91,14 +91,6 @@
allowed_children = { (twisted_dav_namespace, "guid"): (0, None) }
-class TwistedScheduleAutoRespond(davxml.WebDAVEmptyElement):
- """
- When set on an Inbox, scheduling requests are automatically handled.
- """
- namespace = twisted_dav_namespace
- name = "schedule-auto-respond"
- hidden = True
-
class DropBoxHome (davxml.WebDAVEmptyElement):
"""
Denotes a drop box home collection (a collection that will contain drop boxes).
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/apache.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/apache.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/apache.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -132,6 +132,7 @@
shortName = shortName,
fullName = None,
calendarUserAddresses = set(),
+ autoSchedule = False,
)
class AbstractUserRecord(AbstractDirectoryRecord):
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/appleopendirectory.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/appleopendirectory.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -25,6 +25,7 @@
"OpenDirectoryInitError",
]
+import itertools
import sys
import opendirectory
@@ -329,6 +330,21 @@
return result
+ def _parseResourceInfo(self, plist):
+ """
+ Parse OD ResourceInfo attribute and extract information that the server needs.
+
+ @param plist: the plist that is the attribute value.
+ @type plist: str
+ @return: a C{tuple} of C{bool} for auto-accept and C{str} for proxy GUID.
+ """
+ plist = readPlistFromString(plist)
+ wpframework = plist.get("com.apple.WhitePagesFramework", {})
+ autoaccept = wpframework.get("AutoAcceptsInvitation", False)
+ proxy= wpframework.get("CalendaringDelegate")
+
+ return (autoaccept, proxy,)
+
def recordTypes(self):
return (
DirectoryService.recordType_users,
@@ -395,6 +411,7 @@
elif recordType == DirectoryService.recordType_locations:
listRecordType = dsattributes.kDSStdRecordTypeResources
query = dsquery.match(dsattributes.kDSNAttrResourceType, "1", dsattributes.eDSExact)
+ attrs.append(dsattributes.kDSNAttrResourceInfo)
elif recordType == DirectoryService.recordType_resources:
listRecordType = dsattributes.kDSStdRecordTypeResources
@@ -405,6 +422,7 @@
dsquery.match(dsattributes.kDSNAttrResourceType, "4", dsattributes.eDSExact),
dsquery.match(dsattributes.kDSNAttrResourceType, "5", dsattributes.eDSExact),
))
+ attrs.append(dsattributes.kDSNAttrResourceInfo)
else:
raise UnknownRecordTypeError("Unknown Open Directory record type: %s"
@@ -484,6 +502,16 @@
else:
memberGUIDs = ()
+ # Special case for resources and locations
+ autoSchedule = False
+ proxyGUIDs = ()
+ if recordType in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+ resourceInfo = value.get(dsattributes.kDSNAttrResourceInfo)
+ if resourceInfo is not None:
+ autoSchedule, proxy = self._parseResourceInfo(resourceInfo)
+ if proxy:
+ proxyGUIDs = (proxy,)
+
records[recordShortName] = OpenDirectoryRecord(
service = self,
recordType = recordType,
@@ -492,6 +520,8 @@
fullName = realName,
calendarUserAddresses = cuaddrset,
memberGUIDs = memberGUIDs,
+ autoSchedule = autoSchedule,
+ proxyGUIDs = proxyGUIDs,
)
#log.debug("Populated record: %s" % (records[recordShortName],))
@@ -529,7 +559,7 @@
"""
Open Directory implementation of L{IDirectoryRecord}.
"""
- def __init__(self, service, recordType, guid, shortName, fullName, calendarUserAddresses, memberGUIDs):
+ def __init__(self, service, recordType, guid, shortName, fullName, calendarUserAddresses, memberGUIDs, autoSchedule, proxyGUIDs):
super(OpenDirectoryRecord, self).__init__(
service = service,
recordType = recordType,
@@ -537,8 +567,10 @@
shortName = shortName,
fullName = fullName,
calendarUserAddresses = calendarUserAddresses,
+ autoSchedule = autoSchedule,
)
self._memberGUIDs = tuple(memberGUIDs)
+ self._proxyGUIDs = tuple(proxyGUIDs)
def members(self):
if self.recordType != DirectoryService.recordType_groups:
@@ -556,6 +588,25 @@
if self.guid in groupRecord._memberGUIDs:
yield groupRecord
+ def proxies(self):
+ if self.recordType not in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+ return
+
+ for guid in self._proxyGUIDs:
+ proxyRecord = self.service.recordWithGUID(guid)
+ if proxyRecord is None:
+ log.err("No record for proxy in %s with GUID %s" % (self.shortName, guid))
+ else:
+ yield proxyRecord
+
+ def proxyFor(self):
+ for proxyRecord in itertools.chain(
+ self.service.recordsForType(DirectoryService.recordType_resources).itervalues(),
+ self.service.recordsForType(DirectoryService.recordType_locations).itervalues()
+ ):
+ if self.guid in proxyRecord._proxyGUIDs:
+ yield proxyRecord
+
def verifyCredentials(self, credentials):
if isinstance(credentials, UsernamePassword):
try:
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/calendaruserproxy.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/calendaruserproxy.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -33,6 +33,7 @@
from twisted.web2.dav.util import joinURL
from twisted.web2.http import HTTPError, StatusResponse
+from twistedcaldav.config import config
from twistedcaldav.extensions import DAVFile, DAVPrincipalResource
from twistedcaldav.extensions import ReadOnlyWritePropertiesResourceMixIn
from twistedcaldav.sql import AbstractSQLDatabase
@@ -56,6 +57,14 @@
),
)
+ # Add admins
+ aces += tuple([davxml.ACE(
+ davxml.Principal(davxml.HRef(principal)),
+ davxml.Grant(davxml.Privilege(davxml.All())),
+ davxml.Protected(),
+ ) for principal in config.AdminPrincipals
+ ])
+
return davxml.ACL(*aces)
def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
@@ -121,7 +130,15 @@
assert isinstance(property, davxml.WebDAVElement)
if property.qname() == (dav_namespace, "group-member-set"):
- return self.setGroupMemberSet(property, request)
+ if self.hasEditableMembership():
+ return self.setGroupMemberSet(property, request)
+ else:
+ raise HTTPError(
+ StatusResponse(
+ responsecode.FORBIDDEN,
+ "Proxies cannot be changed."
+ )
+ )
return super(CalendarUserProxyPrincipalResource, self).writeProperty(property, request)
@@ -202,7 +219,7 @@
"""Principal UID: %s\n""" % (self.principalUID(),),
"""Principal URL: %s\n""" % (link(self.principalURL()),),
"""\nAlternate URIs:\n""" , format_list(self.alternateURIs()),
- """\nGroup members:\n""" , format_list(link(p.principalURL()) for p in self.groupMembers()),
+ """\nGroup members (%s):\n""" % ({False:"Locked", True:"Editable"}[self.hasEditableMembership()]), format_list(link(p.principalURL()) for p in self.groupMembers()),
"""\nGroup memberships:\n""" , format_list(link(p.principalURL()) for p in self.groupMemberships()),
"""</pre></blockquote></div>""",
output
@@ -237,16 +254,25 @@
return self.parent.principalCollections()
def groupMembers(self):
- # Get member GUIDs and map to principal resources
- members = self._index().getMembers(self.guid)
- return [self.pcollection.principalForGUID(guid) for guid in members]
+ if self.hasEditableMembership():
+ # Get member GUIDs from database and map to principal resources
+ members = self._index().getMembers(self.guid)
+ return [self.pcollection.principalForGUID(guid) for guid in members]
+ else:
+ # Fixed proxies are only for read-write - the read-only list is empty
+ if self.proxyType == "calendar-proxy-write":
+ return self.parent.proxies()
+ else:
+ return ()
def groupMemberships(self):
# Get membership GUIDs and map to principal resources
memberships = self._index().getMemberships(self.guid)
return [self.pcollection.principalForGUID(guid) for guid in memberships]
-
+ def hasEditableMembership(self):
+ return self.parent.hasEditableProxyMembership()
+
class CalendarUserProxyDatabase(AbstractSQLDatabase):
"""
A database to maintain calendar user proxy group memberships.
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/directory.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/directory.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/directory.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -155,7 +155,7 @@
self.fullName
)
- def __init__(self, service, recordType, guid, shortName, fullName, calendarUserAddresses):
+ def __init__(self, service, recordType, guid, shortName, fullName, calendarUserAddresses, autoSchedule):
assert service.realmName is not None
assert recordType
assert shortName
@@ -171,6 +171,7 @@
self.shortName = shortName
self.fullName = fullName
self.calendarUserAddresses = calendarUserAddresses
+ self.autoSchedule = autoSchedule
def __cmp__(self, other):
if not isinstance(other, DirectoryRecord):
@@ -194,6 +195,15 @@
def groups(self):
return ()
+ def proxies(self):
+ return ()
+
+ def proxyFor(self):
+ return ()
+
+ def hasEditableProxyMembership(self):
+ return self.recordType in (DirectoryService.recordType_users, DirectoryService.recordType_groups)
+
def verifyCredentials(self, credentials):
return False
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/principal.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/principal.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -359,7 +359,7 @@
def principalURL(self):
return self._url
- def _getRelatives(self, method, record=None, relatives=None, records=None):
+ def _getRelatives(self, method, record=None, relatives=None, records=None, proxy=False):
if record is None:
record = self.record
if relatives is None:
@@ -373,9 +373,14 @@
for relative in getattr(record, method)():
if relative not in records:
if relative.recordType == myRecordType:
- relatives.add(self.parent.getChild(None, record=relative))
+ found = self.parent.getChild(None, record=relative)
else:
- relatives.add(self.parent.parent.getChild(relative.recordType).getChild(None, record=relative))
+ found = self.parent.parent.getChild(relative.recordType).getChild(None, record=relative)
+
+ if proxy:
+ found = found.getChild("calendar-proxy-write")
+ relatives.add(found)
+
self._getRelatives(method, relative, relatives, records)
return relatives
@@ -426,10 +431,15 @@
def groupMemberships(self):
groups = self._getRelatives("groups")
+
if config.EnableProxyPrincipals:
+ # Get any directory specified proxies
+ groups.update(self._getRelatives("proxyFor", proxy=True))
+
# Get proxy group GUIDs and map to principal resources
proxies = self._map_calendar_user_proxy_guids(self._calendar_user_proxy_index().getMemberships(self.principalUID()))
groups.update(proxies)
+
return groups
def principalCollections(self):
@@ -455,6 +465,15 @@
return addresses
+ def autoSchedule(self):
+ return self.record.autoSchedule
+
+ def proxies(self):
+ return self._getRelatives("proxies")
+
+ def hasEditableProxyMembership(self):
+ return self.record.hasEditableProxyMembership()
+
def scheduleInbox(self, request):
home = self._calendarHome()
if home is None:
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/sqldb.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/sqldb.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/sqldb.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -101,8 +101,11 @@
# Get calendar user addresses
calendarUserAddresses = self.calendarUserAddresses(shortName)
+
+ # TODO: need this for Resources and Locations
+ autoSchedule = False
- yield shortName, guid, password, name, members, groups, calendarUserAddresses
+ yield shortName, guid, password, name, members, groups, calendarUserAddresses, autoSchedule
def getRecord(self, recordType, shortName):
# Get individual account record
@@ -126,8 +129,11 @@
# Get calendar user addresses
calendarUserAddresses = self.calendarUserAddresses(shortName)
+
+ # TODO: need this for Resources and Locations
+ autoSchedule = False
- return shortName, guid, password, name, members, groups, calendarUserAddresses
+ return shortName, guid, password, name, members, groups, calendarUserAddresses, autoSchedule
def members(self, shortName):
members = set()
@@ -313,6 +319,7 @@
members = result[4],
groups = result[5],
calendarUserAddresses = result[6],
+ autoSchedule = result[7],
)
def recordWithShortName(self, recordType, shortName):
@@ -328,6 +335,7 @@
members = result[4],
groups = result[5],
calendarUserAddresses = result[6],
+ autoSchedule = result[7],
)
return None
@@ -336,7 +344,7 @@
"""
XML based implementation implementation of L{IDirectoryRecord}.
"""
- def __init__(self, service, recordType, shortName, guid, password, name, members, groups, calendarUserAddresses):
+ def __init__(self, service, recordType, shortName, guid, password, name, members, groups, calendarUserAddresses, autoSchedule):
super(SQLDirectoryRecord, self).__init__(
service = service,
recordType = recordType,
@@ -344,6 +352,7 @@
shortName = shortName,
fullName = name,
calendarUserAddresses = calendarUserAddresses,
+ autoSchedule = autoSchedule,
)
self.password = password
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/sudo.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/sudo.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/sudo.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -130,7 +130,8 @@
guid=None,
shortName=shortName,
fullName=shortName,
- calendarUserAddresses=set())
+ calendarUserAddresses=set(),
+ autoSchedule=False)
self.password = entry['password']
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/accounts.xml
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/accounts.xml 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/accounts.xml 2007-07-02 20:29:35 UTC (rev 1635)
@@ -122,6 +122,10 @@
<password>gemini</password>
<name>Gemini Twelve</name>
<cuaddr>mailto:gemini at example.com</cuaddr>
+ <auto-schedule/>
+ <proxies>
+ <member>wsanchez</member>
+ </proxies>
</location>
<location>
<uid>apollo</uid>
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_opendirectory.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_opendirectory.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_opendirectory.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -68,7 +68,9 @@
"guidify",
"GUID",
set("mailtoguid at example.com",),
- []
+ [],
+ False,
+ ()
)
digestFields = {}
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_opendirectoryschema.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_opendirectoryschema.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_opendirectoryschema.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -903,7 +903,7 @@
dsattributes.kDSNAttrRecordName : "computer1.apple.com",
dsattributes.kDS1AttrXMLPlist : PlistParse.plist_good,
dsattributes.kDSNAttrMetaNodeLocation : "/LDAPv3/127.0.0.1",
- })
+ })
record_good_other = ("computer2.apple.com", {
dsattributes.kDS1AttrGeneratedUID : "GUID1",
dsattributes.kDSNAttrRecordName : "computer2.apple.com",
@@ -989,3 +989,100 @@
for recordlist, title, guid in records:
_doParseRecords(recordlist, title, guid)
+
+ class ODResourceInfoParse (twisted.trial.unittest.TestCase):
+
+ plist_good_false = """<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.WhitePagesFramework</key>
+ <dict>
+ <key>AutoAcceptsInvitation</key>
+ <false/>
+ <key>Label</key>
+ <string>Location</string>
+ <key>CalendaringDelegate</key>
+ <string>1234-GUID-5678</string>
+ </dict>
+</dict>
+</plist>
+"""
+
+ plist_good_true = """<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.WhitePagesFramework</key>
+ <dict>
+ <key>AutoAcceptsInvitation</key>
+ <true/>
+ <key>Label</key>
+ <string>Location</string>
+ <key>CalendaringDelegate</key>
+ <string></string>
+ </dict>
+</dict>
+</plist>
+"""
+
+ plist_good_missing = """<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.WhitePagesFramework</key>
+ <dict>
+ <key>Label</key>
+ <string>Location</string>
+ </dict>
+</dict>
+</plist>
+"""
+
+ plist_bad = """<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.WhitePagesFramework</key>
+ <string>bogus</string>
+</dict>
+</plist>
+"""
+
+ plist_wrong = """<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.YellowPagesFramework</key>
+ <dict>
+ <key>AutoAcceptsInvitation</key>
+ <true/>
+ <key>Label</key>
+ <string>Location</string>
+ <key>CalendaringDelegate</key>
+ <string>1234-GUID-5678</string>
+ </dict>
+</dict>
+</plist>
+"""
+
+ test_bool = (
+ (plist_good_false, False, "1234-GUID-5678"),
+ (plist_good_true, True, ""),
+ (plist_good_missing, False, None),
+ (plist_wrong, False, None),
+ )
+
+ test_exception = (
+ (plist_bad, AttributeError),
+ )
+
+ def test_plists(self):
+ service = OpenDirectoryService(node="/Search", dosetup=False)
+
+ for item in ODResourceInfoParse.test_bool:
+ self.assertEqual(service._parseResourceInfo(item[0])[0], item[1])
+ self.assertEqual(service._parseResourceInfo(item[0])[1], item[2])
+
+ for item in ODResourceInfoParse.test_exception:
+ self.assertRaises(item[1], service._parseResourceInfo, item[0])
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_principal.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_principal.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_principal.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -191,6 +191,17 @@
self.failIf(principal is None)
self.assertEquals(record, principal.record)
+ def test_autoSchedule(self):
+ """
+ DirectoryPrincipalProvisioningResource.principalForCalendarUserAddress()
+ """
+ for provisioningResource, recordType, recordResource, record in self._allRecords():
+ principal = provisioningResource.principalForRecord(record)
+ self.failIf(principal is None)
+ self.assertEquals(record.autoSchedule, principal.autoSchedule())
+ if record.shortName == "gemini":
+ self.assertTrue(principal.autoSchedule())
+
# FIXME: Run DirectoryPrincipalProvisioningResource tests on DirectoryPrincipalTypeResource also
##
@@ -216,8 +227,16 @@
DirectoryPrincipalResource.groupMemberships()
"""
for provisioningResource, recordType, recordResource, record in self._allRecords():
- self.failUnless(set(record.groups()).issubset(set(r.record for r in recordResource.groupMemberships())))
+ self.failUnless(set(record.groups()).issubset(set(r.record for r in recordResource.groupMemberships() if hasattr(r, "record"))))
+ def test_proxies(self):
+ """
+ DirectoryPrincipalResource.proxies()
+ """
+ for provisioningResource, recordType, recordResource, record in self._allRecords():
+ self.failUnless(set(record.proxies()).issubset(set(r.record for r in recordResource.proxies())))
+ self.assertEqual(record.hasEditableProxyMembership(), recordResource.hasEditableProxyMembership())
+
def test_principalUID(self):
"""
DirectoryPrincipalResource.principalUID()
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_xmlfile.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_xmlfile.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_xmlfile.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -113,3 +113,114 @@
set(r.shortName for r in service.listRecords(recordType)),
set(expectedRecords)
)
+
+ def test_okAutoSchedule(self):
+ service = self.service()
+
+ self.xmlFile().open("w").write(
+"""<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE accounts SYSTEM "accounts.dtd">
+<accounts realm="Test Realm">
+ <location>
+ <uid>my office</uid>
+ <password>nimda</password>
+ <name>Super User</name>
+ <auto-schedule/>
+ </location>
+</accounts>
+"""
+ )
+ for recordType, expectedRecords in (
+ ( DirectoryService.recordType_users , () ),
+ ( DirectoryService.recordType_groups , () ),
+ ( DirectoryService.recordType_locations , ("my office",) ),
+ ( DirectoryService.recordType_resources , () ),
+ ):
+ self.assertEquals(
+ set(r.shortName for r in service.listRecords(recordType)),
+ set(expectedRecords)
+ )
+ self.assertTrue(service.recordWithShortName(DirectoryService.recordType_locations, "my office").autoSchedule)
+
+ def test_badAutoSchedule(self):
+ service = self.service()
+
+ self.xmlFile().open("w").write(
+"""<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE accounts SYSTEM "accounts.dtd">
+<accounts realm="Test Realm">
+ <user>
+ <uid>my office</uid>
+ <password>nimda</password>
+ <name>Super User</name>
+ <auto-schedule/>
+ </user>
+</accounts>
+"""
+ )
+
+ def _findRecords():
+ set(r.shortName for r in service.listRecords(DirectoryService.recordType_users))
+
+ self.assertRaises(ValueError, _findRecords)
+
+ def test_okProxies(self):
+ service = self.service()
+
+ self.xmlFile().open("w").write(
+"""<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE accounts SYSTEM "accounts.dtd">
+<accounts realm="Test Realm">
+ <user>
+ <uid>test</uid>
+ <password>nimda</password>
+ <name>Test</name>
+ </user>
+ <location>
+ <uid>my office</uid>
+ <password>nimda</password>
+ <name>Super User</name>
+ <auto-schedule/>
+ <proxies>
+ <member>test</member>
+ </proxies>
+ </location>
+</accounts>
+"""
+ )
+ for recordType, expectedRecords in (
+ ( DirectoryService.recordType_users , ("test",) ),
+ ( DirectoryService.recordType_groups , () ),
+ ( DirectoryService.recordType_locations , ("my office",) ),
+ ( DirectoryService.recordType_resources , () ),
+ ):
+ self.assertEquals(
+ set(r.shortName for r in service.listRecords(recordType)),
+ set(expectedRecords)
+ )
+ self.assertEqual(set([("users", "test",)],), service.recordWithShortName(DirectoryService.recordType_locations, "my office")._proxies)
+ self.assertEqual(set([("locations", "my office",)],), service.recordWithShortName(DirectoryService.recordType_users, "test")._proxyFor)
+
+ def test_badProxies(self):
+ service = self.service()
+
+ self.xmlFile().open("w").write(
+"""<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE accounts SYSTEM "accounts.dtd">
+<accounts realm="Test Realm">
+ <user>
+ <uid>my office</uid>
+ <password>nimda</password>
+ <name>Super User</name>
+ <proxies>
+ <member>12345-GUID-67890</member>
+ </proxies>
+ </user>
+</accounts>
+"""
+ )
+
+ def _findRecords():
+ set(r.shortName for r in service.listRecords(DirectoryService.recordType_users))
+
+ self.assertRaises(ValueError, _findRecords)
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlaccountsparser.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlaccountsparser.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlaccountsparser.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -44,6 +44,8 @@
ELEMENT_MEMBERS = "members"
ELEMENT_MEMBER = "member"
ELEMENT_CUADDR = "cuaddr"
+ELEMENT_AUTOSCHEDULE = "auto-schedule"
+ELEMENT_PROXIES = "proxies"
ATTRIBUTE_REALM = "realm"
ATTRIBUTE_REPEAT = "repeat"
@@ -101,6 +103,13 @@
if item is not None:
item.groups.add(group.shortName)
+ def updateProxyFor(proxier):
+ # Update proxy membership
+ for recordType, shortName in proxier.proxies:
+ item = self.items[recordType].get(shortName, None)
+ if item is not None:
+ item.proxyFor.add((proxier.recordType, proxier.shortName))
+
for child in node._get_childNodes():
child_name = child._get_localName()
if child_name is None:
@@ -123,9 +132,11 @@
newprincipal = principal.repeat(i)
self.items[recordType][newprincipal.shortName] = newprincipal
updateMembership(newprincipal)
+ updateProxyFor(newprincipal)
else:
self.items[recordType][principal.shortName] = principal
updateMembership(principal)
+ updateProxyFor(principal)
class XMLAccountRecord (object):
"""
@@ -143,6 +154,9 @@
self.members = set()
self.groups = set()
self.calendarUserAddresses = set()
+ self.autoSchedule = False
+ self.proxies = set()
+ self.proxyFor = set()
def repeat(self, ctr):
"""
@@ -175,6 +189,8 @@
result.name = name
result.members = self.members
result.calendarUserAddresses = calendarUserAddresses
+ result.autoSchedule = self.autoSchedule
+ result.proxies = self.proxies
return result
def parseXML(self, node):
@@ -195,14 +211,24 @@
if child.firstChild is not None:
self.name = child.firstChild.data.encode("utf-8")
elif child_name == ELEMENT_MEMBERS:
- self._parseMembers(child)
+ self._parseMembers(child, self.members)
elif child_name == ELEMENT_CUADDR:
if child.firstChild is not None:
self.calendarUserAddresses.add(child.firstChild.data.encode("utf-8"))
+ elif child_name == ELEMENT_AUTOSCHEDULE:
+ # Only Resources & Locations
+ if self.recordType not in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+ raise ValueError("<auto-schedule> element only allowed for Resources and Locations: %s" % (child_name,))
+ self.autoSchedule = True
+ elif child_name == ELEMENT_PROXIES:
+ # Only Resources & Locations
+ if self.recordType not in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+ raise ValueError("<auto-schedule> element only allowed for Resources and Locations: %s" % (child_name,))
+ self._parseMembers(child, self.proxies)
else:
raise RuntimeError("Unknown account attribute: %s" % (child_name,))
- def _parseMembers(self, node):
+ def _parseMembers(self, node, addto):
for child in node._get_childNodes():
if child._get_localName() == ELEMENT_MEMBER:
if child.hasAttribute(ATTRIBUTE_RECORDTYPE):
@@ -210,4 +236,4 @@
else:
recordType = DirectoryService.recordType_users
if child.firstChild is not None:
- self.members.add((recordType, child.firstChild.data.encode("utf-8")))
+ addto.add((recordType, child.firstChild.data.encode("utf-8")))
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlfile.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlfile.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlfile.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -107,12 +107,15 @@
guid = xmlPrincipal.guid,
shortName = shortName,
fullName = xmlPrincipal.name,
- calendarUserAddresses = xmlPrincipal.calendarUserAddresses
+ calendarUserAddresses = xmlPrincipal.calendarUserAddresses,
+ autoSchedule = xmlPrincipal.autoSchedule,
)
- self.password = xmlPrincipal.password
- self._members = xmlPrincipal.members
- self._groups = xmlPrincipal.groups
+ self.password = xmlPrincipal.password
+ self._members = xmlPrincipal.members
+ self._groups = xmlPrincipal.groups
+ self._proxies = xmlPrincipal.proxies
+ self._proxyFor = xmlPrincipal.proxyFor
def members(self):
for recordType, shortName in self._members:
@@ -122,6 +125,14 @@
for shortName in self._groups:
yield self.service.recordWithShortName(DirectoryService.recordType_groups, shortName)
+ def proxies(self):
+ for recordType, shortName in self._proxies:
+ yield self.service.recordWithShortName(recordType, shortName)
+
+ def proxyFor(self):
+ for recordType, shortName in self._proxyFor:
+ yield self.service.recordWithShortName(recordType, shortName)
+
def verifyCredentials(self, credentials):
if isinstance(credentials, UsernamePassword):
return credentials.password == self.password
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/schedule.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/schedule.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/schedule.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -35,10 +35,9 @@
from twisted.web2.dav import davxml
from twisted.web2.dav.http import ErrorResponse, errorForFailure, messageForFailure, statusForFailure
from twisted.web2.dav.resource import AccessDeniedError
-from twisted.web2.dav.util import joinURL, parentForURL
+from twisted.web2.dav.util import joinURL
from twistedcaldav import caldavxml
-from twistedcaldav import customxml
from twistedcaldav import itip
from twistedcaldav.resource import CalDAVResource
from twistedcaldav.caldavxml import caldav_namespace, TimeRange
@@ -481,8 +480,8 @@
# Store CALDAV:schedule-state property
child.writeDeadProperty(caldavxml.ScheduleState(caldavxml.NotProcessed()))
- # Look for auto-respond option
- if inbox.hasDeadProperty(customxml.TwistedScheduleAutoRespond):
+ # Look for auto-schedule option
+ if principal.autoSchedule():
autoresponses.append((principal, inbox, child))
except:
log.err("Could not store data in Inbox : %s" % (inbox,))
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/static.py 2007-06-29 22:01:47 UTC (rev 1634)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/static.py 2007-07-02 20:29:35 UTC (rev 1635)
@@ -575,12 +575,6 @@
def provision(self):
if self.provisionFile():
- # FIXME: This should probably be a directory record option that
- # maps to the property value directly without the need to store one.
- if self.parent.record.recordType in (DirectoryService.recordType_locations, DirectoryService.recordType_resources,):
- # Resources should have autorespond turned on by default,
- # since they typically don't have someone responding for them.
- self.writeDeadProperty(customxml.TwistedScheduleAutoRespond())
# Initialize CTag on the calendar collection
self.updateCTag()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20070702/e51be73f/attachment.html
More information about the calendarserver-changes
mailing list