[CalendarServer-changes] [706] CalendarServer/trunk/twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Tue Dec 5 16:35:45 PST 2006
Revision: 706
http://trac.macosforge.org/projects/calendarserver/changeset/706
Author: wsanchez at apple.com
Date: 2006-12-05 16:35:44 -0800 (Tue, 05 Dec 2006)
Log Message:
-----------
Move scheduling resource implementation to new schedule.py.
Removes POST method from classes other than ScheduleOutboxResource.
Removes need for isScheduleInboxResource(), isScheduleOutboxResource(), ICalendarSchedulingCollectionResource.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/__init__.py
CalendarServer/trunk/twistedcaldav/directory/__init__.py
CalendarServer/trunk/twistedcaldav/extensions.py
CalendarServer/trunk/twistedcaldav/icaldav.py
CalendarServer/trunk/twistedcaldav/itip.py
CalendarServer/trunk/twistedcaldav/method/__init__.py
CalendarServer/trunk/twistedcaldav/method/mkcol.py
CalendarServer/trunk/twistedcaldav/resource.py
CalendarServer/trunk/twistedcaldav/static.py
Removed Paths:
-------------
CalendarServer/trunk/twistedcaldav/http.py
CalendarServer/trunk/twistedcaldav/method/post.py
CalendarServer/trunk/twistedcaldav/method/schedule_common.py
Modified: CalendarServer/trunk/twistedcaldav/__init__.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/__init__.py 2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/__init__.py 2006-12-06 00:35:44 UTC (rev 706)
@@ -25,17 +25,25 @@
from twisted.web2.static import File, loadMimeTypes
__all__ = [
+ "authkerb",
"caldavxml",
"customxml",
"dateops",
"db",
"directory",
"dropbox",
+ "extensions",
"ical",
+ "icaldav",
"index",
"instance",
+ "itip",
+ "logging",
+ "notifications",
"principalindex",
"resource",
+ "root",
+ "schedule",
"sql",
"static",
]
Modified: CalendarServer/trunk/twistedcaldav/directory/__init__.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/__init__.py 2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/directory/__init__.py 2006-12-06 00:35:44 UTC (rev 706)
@@ -21,11 +21,11 @@
"""
__all__ = [
+ "apache",
"appleopendirectory",
- "cred",
"directory",
"idirectory",
- "resource",
+ "principal",
"sqldb",
"xmlfile",
]
Modified: CalendarServer/trunk/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/extensions.py 2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/extensions.py 2006-12-06 00:35:44 UTC (rev 706)
@@ -29,11 +29,14 @@
import urllib
import time
+from twisted.internet.defer import succeed
from twisted.web2 import responsecode
from twisted.web2.http import HTTPError, Response, RedirectResponse
from twisted.web2.http_headers import MimeType
from twisted.web2.stream import FileStream
from twisted.web2.static import MetaDataMixin
+from twisted.web2.dav import davxml
+from twisted.web2.dav.davxml import dav_namespace
from twisted.web2.dav.http import StatusResponse
from twisted.web2.dav.static import DAVFile as SuperDAVFile
from twisted.web2.dav.resource import DAVResource as SuperDAVResource
@@ -47,6 +50,25 @@
"""
Extended L{twisted.web2.dav.static.DAVFile} implementation.
"""
+ def readProperty(self, property, request):
+ if type(property) is tuple:
+ qname = property
+ else:
+ qname = property.qname()
+
+ if qname == (dav_namespace, "resourcetype"):
+ return succeed(self.resourceType())
+
+ return super(DAVFile, self).readProperty(property, request)
+
+ def resourceType(self):
+ # Allow live property to be overriden by dead property
+ if self.deadProperties().contains((dav_namespace, "resourcetype")):
+ return self.deadProperties().get((dav_namespace, "resourcetype"))
+ if self.isCollection():
+ return davxml.ResourceType.collection
+ return davxml.ResourceType.empty
+
def render(self, req):
"""You know what you doing."""
if not self.fp.exists():
Deleted: CalendarServer/trunk/twistedcaldav/http.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/http.py 2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/http.py 2006-12-06 00:35:44 UTC (rev 706)
@@ -1,121 +0,0 @@
-##
-# Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# DRI: Wilfredo Sanchez, wsanchez at apple.com
-##
-
-__all__ = [
- "ScheduleResponseResponse",
- "ScheduleResponseQueue"
-]
-
-from twisted.python import log
-from twisted.python.failure import Failure
-from twisted.web2 import responsecode
-from twisted.web2.dav import davxml
-from twisted.web2.dav.http import errorForFailure, messageForFailure, statusForFailure
-from twisted.web2.http import Response
-from twisted.web2.http_headers import MimeType
-
-from twistedcaldav import caldavxml
-
-class ScheduleResponseResponse (Response):
- """
- ScheduleResponse L{Response} object.
- Renders itself as a CalDAV:schedule-response XML document.
- """
- def __init__(self, xml_responses, location=None):
- """
- @param xml_responses: an interable of davxml.Response objects.
- @param location: the value of the location header to return in the response,
- or None.
- """
-
- Response.__init__(self, code=responsecode.OK,
- stream=caldavxml.ScheduleResponse(*xml_responses).toxml())
-
- self.headers.setHeader("content-type", MimeType("text", "xml"))
-
- if location is not None:
- self.headers.setHeader("location", location)
-
-class ScheduleResponseQueue (object):
- """
- Stores a list of (typically error) responses for use in a
- L{ScheduleResponse}.
- """
- def __init__(self, method, success_response):
- """
- @param method: the name of the method generating the queue.
- @param success_response: the response to return in lieu of a
- L{ScheduleResponse} if no responses are added to this queue.
- """
- self.responses = []
- self.method = method
- self.success_response = success_response
- self.location = None
-
- def setLocation(self, location):
- """
- @param location: the value of the location header to return in the response,
- or None.
- """
- self.location = location
-
- def add(self, recipient, what, reqstatus=None, calendar=None):
- """
- Add a response.
- @param recipient: the recipient for this response.
- @param what: a status code or a L{Failure} for the given recipient.
- @param status: the iTIP request-status for the given recipient.
- @param calendar: the calendar data for the given recipient response.
- """
- if type(what) is int:
- code = what
- error = None
- message = responsecode.RESPONSES[code]
- elif isinstance(what, Failure):
- code = statusForFailure(what)
- error = errorForFailure(what)
- message = messageForFailure(what)
- else:
- raise AssertionError("Unknown data type: %r" % (what,))
-
- if code > 400: # Error codes only
- log.err("Error during %s for %s: %s" % (self.method, recipient, message))
-
- children = []
- children.append(caldavxml.Recipient(davxml.HRef.fromString(recipient)))
- children.append(caldavxml.RequestStatus(reqstatus))
- if calendar is not None:
- children.append(caldavxml.CalendarData.fromCalendar(calendar))
- if error is not None:
- children.append(error)
- if message is not None:
- children.append(davxml.ResponseDescription(message))
- self.responses.append(caldavxml.Response(*children))
-
- def response(self):
- """
- Generate a L{ScheduleResponseResponse} with the responses contained in the
- queue or, if no such responses, return the C{success_response} provided
- to L{__init__}.
- @return: the response.
- """
- if self.responses:
- return ScheduleResponseResponse(self.responses, self.location)
- else:
- return self.success_response
-
Modified: CalendarServer/trunk/twistedcaldav/icaldav.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/icaldav.py 2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/icaldav.py 2006-12-06 00:35:44 UTC (rev 706)
@@ -107,20 +107,6 @@
iCalendar data for the requested resource.
"""
-class ICalendarSchedulingCollectionResource(ICalDAVResource):
- """
- CalDAV scheduling collection resource type, e.g. schedule INBOX.
- """
- def isScheduleInbox():
- """
- True if this is a schedule Inbox.
- """
-
- def isScheduleOutbox():
- """
- True if this is an schedule Outbox.
- """
-
class ICalendarPrincipalResource(IDAVResource):
"""
CalDAV principle resource.
Modified: CalendarServer/trunk/twistedcaldav/itip.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/itip.py 2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/itip.py 2006-12-06 00:35:44 UTC (rev 706)
@@ -47,7 +47,7 @@
from twistedcaldav.ical import Property, iCalendarProductID
from twistedcaldav.method import report_common
from twistedcaldav.method.put_common import storeCalendarObjectResource
-from twistedcaldav.resource import CalendarPrincipalCollectionResource, isCalendarCollectionResource
+from twistedcaldav.resource import isCalendarCollectionResource
__version__ = "0.0"
Modified: CalendarServer/trunk/twistedcaldav/method/__init__.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/__init__.py 2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/method/__init__.py 2006-12-06 00:35:44 UTC (rev 706)
@@ -28,14 +28,10 @@
"delete",
"mkcalendar",
"mkcol",
- "post",
"put",
- "put_common",
- "report_common",
"report_calquery",
- "report_multiget",
"report_freebusy",
- "schedule_common",
+ "report_multiget",
"x_apple_subscribe",
"x_apple_unsubscribe",
]
Modified: CalendarServer/trunk/twistedcaldav/method/mkcol.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/mkcol.py 2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/method/mkcol.py 2006-12-06 00:35:44 UTC (rev 706)
@@ -29,6 +29,7 @@
from twisted.web2.http import HTTPError, StatusResponse
from twistedcaldav import customxml
+from twistedcaldav.icaldav import ICalDAVResource
def http_MKCOL(self, request):
#
Deleted: CalendarServer/trunk/twistedcaldav/method/post.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/post.py 2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/method/post.py 2006-12-06 00:35:44 UTC (rev 706)
@@ -1,44 +0,0 @@
-##
-# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# DRI: Cyrus Daboo, cdaboo at apple.com
-##
-
-"""
-CalDAV POST method.
-"""
-
-__all__ = ["http_POST"]
-
-from twisted.web2.dav.util import parentForURL
-
-from twistedcaldav import caldavxml
-from twistedcaldav.method.schedule_common import processScheduleRequest
-
-def http_POST(self, request):
- """
- The CalDAV POST method.
-
- This uses a generator function yielding either L{waitForDeferred} objects or L{Response} objects.
- This allows for code that follows a 'linear' execution pattern rather than having to use nested
- L{Deferred} callbacks. The logic is easier to follow this way plus we don't run into deep nesting
- issues which the other approach would have with large numbers of recipients.
- """
- d = request.locateResource(parentForURL(request.uri))
- # Check authentication and access controls
- d.addCallback(lambda parent: parent.authorize(request, (caldavxml.Schedule(),)))
- # Do the work
- d.addCallback(lambda _: processScheduleRequest(self, "POST", request))
- return d
Deleted: CalendarServer/trunk/twistedcaldav/method/schedule_common.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/schedule_common.py 2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/method/schedule_common.py 2006-12-06 00:35:44 UTC (rev 706)
@@ -1,374 +0,0 @@
-##
-# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# DRI: Cyrus Daboo, cdaboo at apple.com
-##
-
-"""
-CalDAV Schedule processing.
-"""
-
-__all__ = ["processScheduleRequest"]
-
-from twisted.internet import reactor
-from twisted.internet.defer import deferredGenerator, maybeDeferred, waitForDeferred
-from twisted.python import failure, log
-from twisted.web2 import responsecode
-from twisted.web2.dav import davxml
-from twisted.web2.dav.http import ErrorResponse
-from twisted.web2.dav.util import joinURL
-from twisted.web2.http import HTTPError
-
-from twistedcaldav import caldavxml
-from twistedcaldav import customxml
-from twistedcaldav import itip
-from twistedcaldav.caldavxml import caldav_namespace, TimeRange
-from twistedcaldav.http import ScheduleResponseQueue
-from twistedcaldav.ical import Component
-from twistedcaldav.method import report_common
-from twistedcaldav.method.put_common import storeCalendarObjectResource
-from twistedcaldav.resource import CalendarPrincipalCollectionResource, isScheduleOutboxResource, isCalendarCollectionResource
-
-import md5
-import time
-
-def processScheduleRequest(self, method, request):
- """
- This is a generator function that yields L{waitForDeffered} or L{Response} objects. It handles processing of scheduling
- requests on an Outbox. These can currently come from either a SCHEDULE or POST method. SCHEDULE will be deprecated soon.
-
- @param method: the C{str} containing the current HTTP method.
- @param request: the L{twisted.web2.server.Request} for the current HTTP request.
- """
-
- # Must be targetting an OUTBOX
- if not isScheduleOutboxResource(self):
- log.err("%s must target an schedule Outbox collection: %s" % (method, self,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "supported-collection")))
-
- # Must be content-type text/calendar
- content_type = request.headers.getHeader("content-type")
- if content_type is not None and (content_type.mediaType, content_type.mediaSubtype) != ("text", "calendar"):
- log.err("MIME type %s not allowed in calendar collection" % (content_type,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "supported-calendar-data")))
-
- # Must have Originator header
- originator = request.headers.getRawHeaders("originator")
- if originator is None or (len(originator) != 1):
- log.err("%s request must have Originator header" % (method,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-specified")))
- else:
- originator = originator[0]
-
- # Verify that Originator is a valid calendar user (has an INBOX)
- inboxURL = None
- oprincipal = self.principalForCalendarUserAddress(originator)
- if oprincipal is not None:
- inboxURL = oprincipal.scheduleInboxURL()
- if inboxURL is None:
- log.err("Could not find Inbox for originator: %s" % (originator,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
-
- # Get list of Recipient headers
- rawrecipients = request.headers.getRawHeaders("recipient")
- if rawrecipients is None or (len(rawrecipients) == 0):
- log.err("%s request must have at least one Recipient header" % (method,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "recipient-specified")))
-
- # Recipient header may be comma separated list
- recipients = []
- for rawrecipient in rawrecipients:
- for r in rawrecipient.split(","):
- r = r.strip()
- if len(r):
- recipients.append(r)
-
- timerange = TimeRange(start="20000101", end="20000102")
- recipients_state = {"OK":0, "BAD":0}
-
- # Parse the calendar object from the HTTP request stream
- try:
- d = waitForDeferred(Component.fromIStream(request.stream))
- yield d
- calendar = d.getResult()
- except:
- log.err("Error while handling %s: %s" % (method, failure.Failure(),))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
-
- # Must be a valid calendar
- try:
- calendar.validCalendarForCalDAV()
- except ValueError:
- log.err("%s request calendar component is not valid: %s" % (method, calendar,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
-
- # Must have a METHOD
- if not calendar.isValidMethod():
- log.err("%s request must have valid METHOD property in calendar component: %s" % (method, calendar,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
-
- # Verify iTIP behaviour
- if not calendar.isValidITIP():
- log.err("%s request must have a calendar component that satisfies iTIP requirements: %s" % (method, calendar,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
-
- # Verify that the ORGANIZER's cu address maps to the request.uri
- outboxURL = None
- organizer = calendar.getOrganizer()
- if organizer is not None:
- oprincipal = self.principalForCalendarUserAddress(organizer)
- if oprincipal is not None:
- outboxURL = oprincipal.scheduleOutboxURL()
- if outboxURL is None:
- log.err("ORGANIZER in calendar data is not valid: %s" % (calendar,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "organizer-allowed")))
-
- # Prevent spoofing of ORGANIZER with specific METHODs
- if (calendar.propertyValue("METHOD") in ("PUBLISH", "REQUEST", "ADD", "CANCEL", "DECLINECOUNTER")) and (outboxURL != request.uri):
- log.err("ORGANIZER in calendar data does not match owner of Outbox: %s" % (calendar,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "organizer-allowed")))
-
- # Prevent spoofing when doing reply-like METHODs
- if calendar.propertyValue("METHOD") in ("REPLY", "COUNTER", "REFRESH"):
- # Verify that there is a single ATTENDEE property and that the Originator has permission
- # to send on behalf of that ATTENDEE
- attendees = calendar.getAttendees()
-
- # Must have only one
- if len(attendees) != 1:
- log.err("ATTENDEE list in calendar data is wrong: %s" % (calendar,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
-
- # Attendee's Outbox MUST be the request URI
- aoutboxURL = None
- aprincipal = self.principalForCalendarUserAddress(attendees[0])
- if aprincipal is not None:
- aoutboxURL = aprincipal.scheduleOutboxURL()
- if aoutboxURL is None or aoutboxURL != request.uri:
- log.err("ATTENDEE in calendar data does not match owner of Outbox: %s" % (calendar,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
-
- # For free-busy do immediate determination of iTIP result rather than fan-out
- if (calendar.propertyValue("METHOD") == "REQUEST") and (calendar.mainType() == "VFREEBUSY"):
- # Extract time range from VFREEBUSY object
- vfreebusies = [v for v in calendar.subcomponents() if v.name() == "VFREEBUSY"]
- if len(vfreebusies) != 1:
- log.err("iTIP data is not valid for a VFREEBUSY request: %s" % (calendar,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
- dtstart = vfreebusies[0].getStartDateUTC()
- dtend = vfreebusies[0].getEndDateUTC()
- if dtstart is None or dtend is None:
- log.err("VFREEBUSY start/end not valid: %s" % (calendar,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
- timerange.start = dtstart
- timerange.end = dtend
-
- # Do free busy operation
- freebusy = True
- else:
- # Do regular invite (fan-out)
- freebusy = False
-
- # Prepare for multiple responses
- responses = ScheduleResponseQueue(method, responsecode.OK)
-
- # Outbox copy is saved when not doing free busy request
- if not freebusy:
- # Hash the iCalendar data for use as the last path element of the URI path
- name = md5.new(str(calendar) + str(time.time()) + self.fp.path).hexdigest() + ".ics"
-
- # Save a copy of the calendar data into the Outbox
- childURL = joinURL(request.uri, name)
- child = waitForDeferred(request.locateResource(childURL))
- yield child
- child = child.getResult()
- responses.setLocation(childURL)
-
- try:
- d = waitForDeferred(
- maybeDeferred(
- storeCalendarObjectResource,
- request=request,
- sourcecal = False,
- destination = child,
- destination_uri = childURL,
- calendardata = str(calendar),
- destinationparent = self,
- destinationcal = True,
- isiTIP = True
- )
- )
- yield d
- d.getResult()
- except:
- log.err("Error while handling %s: %s" % (method, failure.Failure(),))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "outbox-copy")))
-
- # Store CALDAV:originator property
- child.writeDeadProperty(caldavxml.Originator(davxml.HRef.fromString(originator)))
-
- # Store CALDAV:recipient property
- child.writeDeadProperty(caldavxml.Recipient(*map(davxml.HRef.fromString, recipients)))
-
- # Extract the ORGANIZER property and UID value from the calendar data for use later
- organizerProp = calendar.getOrganizerProperty()
- uid = calendar.resourceUID()
-
- # Loop over each recipient and do appropriate action.
- autoresponses = []
- for recipient in recipients:
- # Get the principal resource for this recipient
- principal = self.principalForCalendarUserAddress(recipient)
-
- # Map recipient to their inbox
- inbox = None
- if principal is not None:
- inboxURL = principal.scheduleInboxURL()
- if inboxURL:
- inbox = waitForDeferred(request.locateResource(inboxURL))
- yield inbox
- inbox = inbox.getResult()
- if inbox is None:
- log.err("Could not find Inbox for recipient: %s" % (recipient,))
- err = HTTPError(ErrorResponse(responsecode.NOT_FOUND, (caldav_namespace, "recipient-exists")))
- responses.add(recipient, failure.Failure(exc_value=err), reqstatus="3.7;Invalid Calendar User")
- recipients_state["BAD"] += 1
-
- # Process next recipient
- continue
- else:
-
- #
- # Check access controls
- #
- try:
- d = waitForDeferred(inbox.checkPrivileges(request, (caldavxml.Schedule(),), principal=davxml.Principal(davxml.HRef.fromString(oprincipal))))
- yield d
- d.getResult()
- except:
- log.err("Could not access Inbox for recipient: %s" % (recipient,))
- err = HTTPError(ErrorResponse(responsecode.NOT_FOUND, (caldav_namespace, "recipient-permisions")))
- responses.add(recipient, failure.Failure(exc_value=err), reqstatus="3.8;No authority")
- recipients_state["BAD"] += 1
-
- # Process next recipient
- continue
-
- # Different behaviour for free-busy vs regular invite
- if freebusy:
- # Extract the ATTENDEE property matching current recipient from the calendar data
- cuas = principal.calendarUserAddresses()
- attendeeProp = calendar.getAttendeeProperty(cuas)
-
- # Find the current recipients calendar-free-busy-set
- fbset = waitForDeferred(principal.calendarFreeBusyURIs(request))
- yield fbset
- fbset = fbset.getResult()
-
- # First list is BUSY, second BUSY-TENTATIVE, third BUSY-UNAVAILABLE
- fbinfo = ([], [], [])
-
- try:
- matchtotal = 0
- for calURL in fbset:
- cal = waitForDeferred(request.locateResource(calURL))
- yield cal
- cal = cal.getResult()
- if cal is None or not cal.exists() or not isCalendarCollectionResource(cal):
- # We will ignore missing calendars. If the recipient has failed to
- # properly manage the free busy set that should not prevent us from working.
- continue
-
- matchtotal = waitForDeferred(report_common.generateFreeBusyInfo(request, cal, fbinfo, timerange, matchtotal))
- yield matchtotal
- matchtotal = matchtotal.getResult()
-
- # Build VFREEBUSY iTIP reply for this recipient
- fbresult = report_common.buildFreeBusyResult(fbinfo, timerange, organizer=organizerProp, attendee=attendeeProp, uid=uid)
-
- responses.add(recipient, responsecode.OK, reqstatus="2.0;Success", calendar=fbresult)
- recipients_state["OK"] += 1
-
- except:
- log.err("Could not determine free busy information: %s" % (recipient,))
- err = HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "recipient-permissions")))
- responses.add(recipient, failure.Failure(exc_value=err), reqstatus="3.8;No authority")
- recipients_state["BAD"] += 1
-
- else:
- # Hash the iCalendar data for use as the last path element of the URI path
- name = md5.new(str(calendar) + str(time.time()) + inbox.fp.path).hexdigest() + ".ics"
-
- # Get a resource for the new item
- childURL = joinURL(inboxURL, name)
- child = waitForDeferred(request.locateResource(childURL))
- yield child
- child = child.getResult()
-
- # Copy calendar to inbox (doing fan-out)
- d = waitForDeferred(
- maybeDeferred(
- storeCalendarObjectResource,
- request=request,
- sourcecal = False,
- destination = child,
- destination_uri = childURL,
- calendardata = str(calendar),
- destinationparent = inbox,
- destinationcal = True,
- isiTIP = True
- )
- )
- yield d
- try:
- d.getResult()
- responses.add(recipient, responsecode.OK, reqstatus="2.0;Success")
- recipients_state["OK"] += 1
-
- # Store CALDAV:originator property
- child.writeDeadProperty(caldavxml.Originator(davxml.HRef.fromString(originator)))
-
- # Store CALDAV:recipient property
- child.writeDeadProperty(caldavxml.Recipient(davxml.HRef.fromString(recipient)))
-
- # Store CALDAV:schedule-state property
- child.writeDeadProperty(caldavxml.ScheduleState(caldavxml.NotProcessed()))
-
- # Look for auto-respond option
- if inbox.hasDeadProperty(customxml.TwistedScheduleAutoRespond):
- autoresponses.append((principal, inbox, child))
- except:
- log.err("Could not store data in Inbox : %s" % (inbox,))
- err = HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "recipient-permissions")))
- responses.add(recipient, failure.Failure(exc_value=err), reqstatus="3.8;No authority")
- recipients_state["BAD"] += 1
-
- # Now we have to do auto-respond
- if len(autoresponses) != 0:
- # First check that we have a method that we can auto-respond to
- if not itip.canAutoRespond(calendar):
- autoresponses = []
-
- # Now do the actual auto response
- for principal, inbox, child in autoresponses:
- # Add delayed reactor task to handle iTIP responses
- reactor.callLater(5.0, itip.handleRequest, *(request, principal, inbox, calendar.duplicate(), child)) #@UndefinedVariable
- #reactor.callInThread(itip.handleRequest, *(request, principal, inbox, calendar.duplicate(), child)) #@UndefinedVariable
-
- # Return with final response if we are done
- yield responses.response()
-
-processScheduleRequest = deferredGenerator(processScheduleRequest)
-
Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/resource.py 2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/resource.py 2006-12-06 00:35:44 UTC (rev 706)
@@ -17,7 +17,7 @@
##
"""
-CalDAV-aware static resources.
+CalDAV-aware resources.
"""
__all__ = [
@@ -25,12 +25,8 @@
"CalendarPrincipalCollectionResource",
"CalendarPrincipalResource",
"CalendarSchedulingCollectionResource",
- "ScheduleInboxResource",
- "ScheduleOutboxResource",
"isCalendarCollectionResource",
"isPseudoCalendarCollectionResource",
- "isScheduleInboxResource",
- "isScheduleOutboxResource",
]
from zope.interface import implements
@@ -56,7 +52,7 @@
import twistedcaldav
from twistedcaldav import caldavxml, customxml
from twistedcaldav.extensions import DAVResource
-from twistedcaldav.icaldav import ICalDAVResource, ICalendarPrincipalResource, ICalendarSchedulingCollectionResource
+from twistedcaldav.icaldav import ICalDAVResource, ICalendarPrincipalResource
from twistedcaldav.caldavxml import caldav_namespace
from twistedcaldav.customxml import apple_namespace
from twistedcaldav.ical import Component as iComponent
@@ -677,74 +673,6 @@
return joinURL(home, DropBox.notificationName)
return None
-class CalendarSchedulingCollectionResource (CalDAVResource):
- """
- CalDAV principal resource.
-
- Extends L{DAVResource} to provide CalDAV scheduling collection
- functionality.
- """
- implements(ICalendarSchedulingCollectionResource)
-
- def isCollection(self):
- return True
-
- def isCalendarCollection(self):
- return False
-
- def isPseudoCalendarCollection(self):
- return True
-
- def isScheduleInbox(self):
- return False
-
- def isScheduleOutbox(self):
- return False
-
- def readProperty(self, property, request):
- if type(property) is tuple:
- qname = property
- else:
- qname = property.qname()
-
- namespace, name = qname
-
- if namespace == dav_namespace:
- if name == "resourcetype":
- types = [davxml.Collection()]
-
- if self.isScheduleInbox(): types.append(caldavxml.ScheduleInbox())
- if self.isScheduleOutbox(): types.append(caldavxml.ScheduleOutbox())
-
- return succeed(davxml.ResourceType(*types))
-
- return super(CalendarSchedulingCollectionResource, self).readProperty(property, request)
-
- def supportedReports(self):
- result = super(CalDAVResource, self).supportedReports()
- result.append(davxml.Report(caldavxml.CalendarQuery(),))
- result.append(davxml.Report(caldavxml.CalendarMultiGet(),))
- # free-busy report not allowed
- return result
-
-class ScheduleInboxResource (CalendarSchedulingCollectionResource):
- """
- CalDAV schedule Inbox resource.
-
- Extends L{DAVResource} to provide CalDAV functionality.
- """
- def isScheduleInbox(self):
- return True
-
-class ScheduleOutboxResource (CalendarSchedulingCollectionResource):
- """
- CalDAV schedule Outbox resource.
-
- Extends L{DAVResource} to provide CalDAV functionality.
- """
- def isScheduleOutbox(self):
- return True
-
##
# Utilities
##
@@ -771,19 +699,3 @@
return False
else:
return resource.isPseudoCalendarCollection()
-
-def isScheduleInboxResource(resource):
- try:
- resource = ICalendarSchedulingCollectionResource(resource)
- except TypeError:
- return False
- else:
- return resource.isScheduleInbox()
-
-def isScheduleOutboxResource(resource):
- try:
- resource = ICalendarSchedulingCollectionResource(resource)
- except TypeError:
- return False
- else:
- return resource.isScheduleOutbox()
Modified: CalendarServer/trunk/twistedcaldav/static.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/static.py 2006-12-06 00:30:33 UTC (rev 705)
+++ CalendarServer/trunk/twistedcaldav/static.py 2006-12-06 00:35:44 UTC (rev 706)
@@ -49,10 +49,11 @@
from twistedcaldav.extensions import ReadOnlyResourceMixIn
from twistedcaldav.ical import Component as iComponent
from twistedcaldav.ical import Property as iProperty
+from twistedcaldav.icaldav import ICalDAVResource
from twistedcaldav.index import Index, IndexSchedule, db_basename
from twistedcaldav.resource import CalDAVResource
-from twistedcaldav.resource import ScheduleInboxResource, ScheduleOutboxResource
from twistedcaldav.resource import isCalendarCollectionResource
+from twistedcaldav.schedule import ScheduleInboxResource, ScheduleOutboxResource
from twistedcaldav.extensions import DAVFile
from twistedcaldav.dropbox import DropBox
from twistedcaldav.directory.idirectory import IDirectoryService
@@ -421,21 +422,6 @@
def __repr__(self):
return "<%s (calendar inbox collection): %s>" % (self.__class__.__name__, self.fp.path)
- ##
- # ACL
- ##
-
- def defaultAccessControlList(self):
- return davxml.ACL(
- # CalDAV:schedule for any authenticated user
- davxml.ACE(
- davxml.Principal(davxml.Authenticated()),
- davxml.Grant(
- davxml.Privilege(caldavxml.Schedule()),
- ),
- ),
- )
-
class ScheduleOutboxFile (ScheduleOutboxResource, ScheduleFile):
"""
Calendar scheduling outbox collection resource.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20061205/3c51ee27/attachment.html
More information about the calendarserver-changes
mailing list