[CalendarServer-changes] [5292] CalendarServer/branches/users/cdaboo/shared-calendars-5187/ twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Fri Mar 12 11:42:29 PST 2010
Revision: 5292
http://trac.macosforge.org/projects/calendarserver/changeset/5292
Author: cdaboo at apple.com
Date: 2010-03-12 11:42:28 -0800 (Fri, 12 Mar 2010)
Log Message:
-----------
XML schema clean-up and reply notifications to sharer.
Modified Paths:
--------------
CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/customxml.py
CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/notifications.py
CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/sharing.py
CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/static.py
CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/test_sharing.py
Modified: CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/customxml.py 2010-03-12 19:39:52 UTC (rev 5291)
+++ CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/customxml.py 2010-03-12 19:42:28 UTC (rev 5292)
@@ -590,13 +590,20 @@
namespace = calendarserver_namespace
name = "read-write"
+class ReadWriteScheduleAccess (davxml.WebDAVEmptyElement):
+ """
+ Denotes read and write and schedule access on a shared calendar.
+ """
+ namespace = calendarserver_namespace
+ name = "read-write-schedule"
+
class UID (davxml.WebDAVTextElement):
namespace = calendarserver_namespace
name = "uid"
-class Sequence (davxml.WebDAVTextElement):
+class InReplyTo (davxml.WebDAVTextElement):
namespace = calendarserver_namespace
- name = "sequence"
+ name = "in-reply-to"
##
# Notifications
@@ -649,7 +656,8 @@
name = "share"
allowed_children = {
- (calendarserver_namespace, "set" ) : (0, None),
+ (calendarserver_namespace, "set" ) : (0, None),
+ (calendarserver_namespace, "remove" ) : (0, None),
}
class InviteSet (davxml.WebDAVElement):
@@ -657,10 +665,11 @@
name = "set"
allowed_children = {
- (calendarserver_namespace, "summary" ) : (0, 1),
- (calendarserver_namespace, "attendee" ) : (1, 1),
- (calendarserver_namespace, "read" ) : (0, 1),
- (calendarserver_namespace, "read-write" ): (0, 1),
+ (dav_namespace, "href" ) : (1, 1),
+ (calendarserver_namespace, "summary" ) : (0, 1),
+ (calendarserver_namespace, "read" ) : (0, 1),
+ (calendarserver_namespace, "read-write" ) : (0, 1),
+ (calendarserver_namespace, "read-write-schedule" ) : (0, 1),
}
class InviteRemove (davxml.WebDAVElement):
@@ -668,9 +677,10 @@
name = "remove"
allowed_children = {
- (calendarserver_namespace, "attendee" ) : (1, 1),
- (calendarserver_namespace, "read" ) : (0, 1),
- (calendarserver_namespace, "read-write" ): (0, 1),
+ (dav_namespace, "href" ) : (1, 1),
+ (calendarserver_namespace, "read" ) : (0, 1),
+ (calendarserver_namespace, "read-write" ) : (0, 1),
+ (calendarserver_namespace, "read-write-schedule" ) : (0, 1),
}
class InviteUser (davxml.WebDAVElement):
@@ -679,13 +689,13 @@
allowed_children = {
(calendarserver_namespace, "href" ) : (1, 1),
- (calendarserver_namespace, "access" ) : (0, 1),
- (calendarserver_namespace, "summary" ) : (0, 1),
(calendarserver_namespace, "invite-noresponse" ) : (0, 1),
(calendarserver_namespace, "invite-deleted" ) : (0, 1),
(calendarserver_namespace, "invite-accepted" ) : (0, 1),
(calendarserver_namespace, "invite-declined" ) : (0, 1),
(calendarserver_namespace, "invite-invalid" ) : (0, 1),
+ (calendarserver_namespace, "access" ) : (1, 1),
+ (calendarserver_namespace, "summary" ) : (0, 1),
}
class InviteAccess (davxml.WebDAVElement):
@@ -693,8 +703,9 @@
name = "access"
allowed_children = {
- (calendarserver_namespace, "read" ) : (0, 1),
- (calendarserver_namespace, "read-write" ): (0, 1),
+ (calendarserver_namespace, "read" ) : (0, 1),
+ (calendarserver_namespace, "read-write" ) : (0, 1),
+ (calendarserver_namespace, "read-write-schedule" ): (0, 1),
}
class Invite (davxml.WebDAVElement):
@@ -763,6 +774,23 @@
InviteSummary.qname() : (0, 1),
}
+ allowed_attributes = {
+ "shared-type" : True,
+ }
+
+class InviteReply (davxml.WebDAVElement):
+ namespace = calendarserver_namespace
+ name = "invite-reply"
+
+ allowed_children = {
+ (dav_namespace, "href") : (0, 1),
+ InviteStatusAccepted.qname() : (0, 1),
+ InviteStatusDeclined.qname() : (0, 1),
+ HostURL.qname() : (0, 1),
+ InReplyTo.qname() : (0, 1),
+ InviteSummary.qname() : (0, 1),
+ }
+
class ResourceUpdateAdded(davxml.WebDAVEmptyElement):
namespace = calendarserver_namespace
name = "resource-added-notification"
@@ -809,8 +837,8 @@
allowed_children = {
DTStamp.qname() : (0, None),
UID.qname() : (0, None),
- Sequence.qname() : (0, None),
InviteNotification.qname() : (0, None),
+ InviteReply.qname() : (0, None),
ResourceUpdateNotification.qname() : (0, None),
SharedCalendarUpdateNotification.qname() : (0, None),
}
@@ -826,7 +854,7 @@
allowed_children = { (davxml.dav_namespace, "href"): (0, 1) }
-class NotificationType (davxml.WebDAVTextElement):
+class NotificationType (davxml.WebDAVElement):
"""
A property to indicate what type of notification the resource represents.
"""
@@ -835,6 +863,10 @@
hidden = True
protected = True
+ allowed_children = {
+ InviteNotification.qname() : (0, None),
+ InviteReply.qname() : (0, None),
+ }
##
# Extensions to davxml.ResourceType
Modified: CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/notifications.py
===================================================================
--- CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/notifications.py 2010-03-12 19:39:52 UTC (rev 5291)
+++ CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/notifications.py 2010-03-12 19:42:28 UTC (rev 5292)
@@ -84,7 +84,7 @@
yield self._writeNotification(request, uid, rname, xmltype, xmldata)
# Update database
- self.notificationsDB().addOrUpdateRecord(NotificationRecord(uid, rname, xmltype))
+ self.notificationsDB().addOrUpdateRecord(NotificationRecord(uid, rname, xmltype.name))
def _writeNotification(self, request, uid, rname, xmltype, xmldata):
raise NotImplementedError
Modified: CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/sharing.py 2010-03-12 19:39:52 UTC (rev 5291)
+++ CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/sharing.py 2010-03-12 19:42:28 UTC (rev 5292)
@@ -16,7 +16,6 @@
from twext.python.log import LoggingMixIn
from twext.web2 import responsecode
-from twext.web2.dav.element.base import PCDATAElement
from twext.web2.dav.http import ErrorResponse, MultiStatusResponse
from twext.web2.dav.util import allDataFromStream
from twext.web2.http import HTTPError, Response, StatusResponse
@@ -143,12 +142,12 @@
Return the DAV:resourcetype stripped of any shared elements.
"""
- rtype = self.resourceType()
- newchildren = [child for child in rtype.children if child.qname() not in (
- customxml.SharedOwner.qname(),
- )] if rtype.children else ()
- rtype.children = newchildren if newchildren else None
- return rtype
+ if self.isCalendarCollection():
+ return "calendar"
+ elif self.isAddressBookCollection():
+ return "addressbook"
+ else:
+ return ""
def validUserIDForShare(self, userid):
"""
@@ -252,11 +251,10 @@
# Look for existing invite and update its fields or create new one
record = self.invitesDB().recordForUserID(userid)
if record:
- record.sequence += 1
record.access = inviteAccessMapFromXML[type(ace)]
record.summary = summary
else:
- record = Invite(str(uuid4()), 1, userid, inviteAccessMapFromXML[type(ace)], "NEEDS-ACTION", summary)
+ record = Invite(str(uuid4()), userid, inviteAccessMapFromXML[type(ace)], "NEEDS-ACTION", summary)
# Send invite
yield self.sendInvite(record, request)
@@ -314,11 +312,11 @@
pass
# Generate invite XML
- xmltype = customxml.InviteNotification.name
+ typeAttr = {'shared-type':self.sharedResourceType()}
+ xmltype = customxml.InviteNotification(**typeAttr)
xmldata = customxml.Notification(
customxml.DTStamp.fromString(dateTimeToString(datetime.datetime.now(tz=utc))),
customxml.UID.fromString(record.inviteuid),
- customxml.Sequence.fromString(str(record.sequence)),
customxml.InviteNotification(
davxml.HRef.fromString(record.userid),
inviteStatusMapToXML[record.state](),
@@ -326,11 +324,11 @@
customxml.HostURL(
davxml.HRef.fromString(hosturl),
),
- self.sharedResourceType(),
customxml.Organizer(
davxml.HRef.fromString(owner),
),
customxml.InviteSummary.fromString(record.summary),
+ **typeAttr
),
).toxml()
@@ -362,14 +360,10 @@
summary = None
for item in inviteset.children:
if isinstance(item, davxml.HRef):
- for attendeeItem in item.children:
- if isinstance(attendeeItem, PCDATAElement):
- userid = attendeeItem.data
+ userid = str(item)
continue
if isinstance(item, customxml.InviteSummary):
- for summaryItem in item.children:
- if isinstance(summaryItem, PCDATAElement):
- summary = summaryItem.data
+ summary = str(item)
continue
if isinstance(item, customxml.ReadAccess) or isinstance(item, customxml.ReadWriteAccess):
access = item
@@ -401,9 +395,7 @@
access = []
for item in inviteremove.children:
if isinstance(item, davxml.HRef):
- for attendeeItem in item.children:
- if isinstance(attendeeItem, PCDATAElement):
- userid = attendeeItem.data
+ userid = str(item)
continue
if isinstance(item, customxml.ReadAccess) or isinstance(item, customxml.ReadWriteAccess):
access.append(item)
@@ -541,8 +533,8 @@
set of shared calendfars.
"""
- def acceptShare(self, request, hostUrl, inviteUID, displayname=None):
- return self._changeShare(request, "ACCEPTED", hostUrl, inviteUID, displayname)
+ def acceptShare(self, request, hostUrl, replytoUID, displayname=None):
+ return self._changeShare(request, "ACCEPTED", hostUrl, replytoUID, displayname)
def wouldAcceptShare(self, hostUrl, request):
return succeed(True)
@@ -551,11 +543,11 @@
""" Remove a shared calendar named in resourceName """
return succeed(True)
- def declineShare(self, request, hostUrl, inviteUID):
- return self._changeShare(request, "DECLINED", hostUrl, inviteUID)
+ def declineShare(self, request, hostUrl, replytoUID):
+ return self._changeShare(request, "DECLINED", hostUrl, replytoUID)
@inlineCallbacks
- def _changeShare(self, request, state, hostUrl, inviteUID, displayname=None):
+ def _changeShare(self, request, state, hostUrl, replytoUID, displayname=None):
""" Accept an invite to a shared calendar """
# Change state in sharer invite
@@ -571,8 +563,41 @@
))
# Change the record
- yield sharedCalendar.changeUserInviteState(request, inviteUID, owner, state, displayname)
+ yield sharedCalendar.changeUserInviteState(request, replytoUID, owner, state, displayname)
+ yield self.sendReply(request, owner, sharedCalendar, state, hostUrl, replytoUID, displayname)
+
+ @inlineCallbacks
+ def sendReply(self, request, sharee, sharedCalendar, state, hostUrl, replytoUID, displayname=None):
+
+
+ # Locate notifications collection for sharer
+ sharer = (yield sharedCalendar.ownerPrincipal(request))
+ notifications = (yield request.locateResource(sharer.notificationURL()))
+
+ # Generate invite XML
+ notificationUID = "%s-reply" % (replytoUID,)
+ xmltype = customxml.InviteReply()
+ xmldata = customxml.Notification(
+ customxml.DTStamp.fromString(dateTimeToString(datetime.datetime.now(tz=utc))),
+ customxml.UID.fromString(notificationUID),
+ customxml.InviteReply(
+ *(
+ (
+ davxml.HRef.fromString(sharee),
+ inviteStatusMapToXML[state](),
+ customxml.HostURL(
+ davxml.HRef.fromString(hostUrl),
+ ),
+ customxml.InReplyTo.fromString(replytoUID),
+ ) + ((customxml.InviteSummary.fromString(displayname),) if displayname is not None else ())
+ )
+ ),
+ ).toxml()
+
+ # Add to collections
+ yield notifications.addNotification(request, notificationUID, xmltype, xmldata)
+
def xmlPOSTNoAuth(self, encoding, request):
def _handleResponse(result):
response = Response(code=responsecode.OK)
@@ -583,40 +608,36 @@
return error.value.response
return Response(code=responsecode.BAD_REQUEST)
- def _handleInviteUpdate(inviteupdatedoc):
+ def _handleInviteReply(invitereplydoc):
""" Handle a user accepting or declining a sharing invite """
hostUrl = None
accepted = None
summary = None
- inviteUID = None
- for item in inviteupdatedoc.children:
+ replytoUID = None
+ for item in invitereplydoc.children:
if isinstance(item, customxml.InviteStatusAccepted):
accepted = True
elif isinstance(item, customxml.InviteStatusDeclined):
accepted = False
elif isinstance(item, customxml.InviteSummary):
- for summaryitem in item.children:
- if isinstance(summaryitem, PCDATAElement):
- summary = summaryitem.data
+ summary = str(item)
elif isinstance(item, customxml.HostURL):
for hosturlItem in item.children:
if isinstance(hosturlItem, davxml.HRef):
- for hrefItem in hosturlItem.children:
- if isinstance(hrefItem, PCDATAElement):
- hostUrl = hrefItem.data
- elif isinstance(item, customxml.UID):
- inviteUID = str(item)
+ hostUrl = str(hosturlItem)
+ elif isinstance(item, customxml.InReplyTo):
+ replytoUID = str(item)
- if accepted is None or hostUrl is None or inviteUID is None:
+ if accepted is None or hostUrl is None or replytoUID is None:
raise HTTPError(ErrorResponse(
responsecode.FORBIDDEN,
(customxml.calendarserver_namespace, "valid-request"),
"missing required XML elements",
))
if accepted:
- return self.acceptShare(request, hostUrl, inviteUID, displayname=summary)
+ return self.acceptShare(request, hostUrl, replytoUID, displayname=summary)
else:
- return self.declineShare(request, hostUrl, inviteUID)
+ return self.declineShare(request, hostUrl, replytoUID)
def _getData(data):
try:
@@ -627,7 +648,7 @@
root = doc.root_element
xmlDocHanders = {
- customxml.InviteNotification: _handleInviteUpdate,
+ customxml.InviteReply: _handleInviteReply,
}
if type(root) in xmlDocHanders:
return xmlDocHanders[type(root)](root).addCallbacks(_handleResponse, errback=_handleErrorResponse)
@@ -637,8 +658,9 @@
return allDataFromStream(request.stream).addCallback(_getData)
inviteAccessMapToXML = {
- "read-only" : customxml.ReadAccess,
- "read-write" : customxml.ReadWriteAccess,
+ "read-only" : customxml.ReadAccess,
+ "read-write" : customxml.ReadWriteAccess,
+ "read-write-schedule" : customxml.ReadWriteScheduleAccess,
}
inviteAccessMapFromXML = dict([(v,k) for k,v in inviteAccessMapToXML.iteritems()])
@@ -653,9 +675,8 @@
class Invite(object):
- def __init__(self, inviteuid, sequence, userid, access, state, summary):
+ def __init__(self, inviteuid, userid, access, state, summary):
self.inviteuid = inviteuid
- self.sequence = sequence
self.userid = userid
self.access = access
self.state = state
@@ -708,9 +729,9 @@
def addOrUpdateRecord(self, record):
- self._db_execute("""insert or replace into INVITE (INVITEUID, SEQUENCE, USERID, ACCESS, STATE, SUMMARY)
- values (:1, :2, :3, :4, :5, :6)
- """, record.inviteuid, record.sequence, record.userid, record.access, record.state, record.summary,
+ self._db_execute("""insert or replace into INVITE (INVITEUID, USERID, ACCESS, STATE, SUMMARY)
+ values (:1, :2, :3, :4, :5)
+ """, record.inviteuid, record.userid, record.access, record.state, record.summary,
)
def removeRecordForUserID(self, userid):
@@ -746,7 +767,6 @@
#
# INVITE table is the primary table
# INVITEUID: UID for this invite
- # SEQUENCE: sequence number for this invite
# NAME: identifier of invitee
# ACCESS: Access mode for share
# STATE: Invite response status
@@ -756,7 +776,6 @@
"""
create table INVITE (
INVITEUID text unique,
- SEQUENCE integer,
USERID text unique,
ACCESS text,
STATE text,
Modified: CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/static.py 2010-03-12 19:39:52 UTC (rev 5291)
+++ CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/static.py 2010-03-12 19:42:28 UTC (rev 5292)
@@ -1317,7 +1317,7 @@
child = self.createSimilarFile(self.fp.child(rname).path)
child.fp.setContent(xmldata)
child.writeDeadProperty(davxml.GETContentType.fromString(generateContentType(MimeType("text", "xml", params={"charset":"utf-8"}))))
- child.writeDeadProperty(customxml.NotificationType.fromString(xmltype))
+ child.writeDeadProperty(customxml.NotificationType(xmltype))
return succeed(True)
Modified: CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/test_sharing.py
===================================================================
--- CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/test_sharing.py 2010-03-12 19:39:52 UTC (rev 5291)
+++ CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/test_sharing.py 2010-03-12 19:42:28 UTC (rev 5292)
@@ -45,6 +45,7 @@
self.resource.validUserIDForShare = self._fakeValidUserID
self.resource.sendInvite = lambda record, request:succeed(True)
+ self.resource.removeInvite = lambda record, request:succeed(True)
def _fakeValidUserID(self, userid):
if userid.endswith("@example.com"):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100312/3046ddae/attachment-0001.html>
More information about the calendarserver-changes
mailing list