[CalendarServer-changes] [10085] CalendarServer/branches/users/cdaboo/managed-attachments

source_changes at macosforge.org source_changes at macosforge.org
Mon Nov 26 14:06:16 PST 2012


Revision: 10085
          http://trac.calendarserver.org//changeset/10085
Author:   cdaboo at apple.com
Date:     2012-11-26 14:06:16 -0800 (Mon, 26 Nov 2012)
Log Message:
-----------
Support managed attachment re-use during PUT create. Also pass down attachment URI template value into store.

Modified Paths:
--------------
    CalendarServer/branches/users/cdaboo/managed-attachments/calendarserver/tap/util.py
    CalendarServer/branches/users/cdaboo/managed-attachments/twistedcaldav/storebridge.py
    CalendarServer/branches/users/cdaboo/managed-attachments/txdav/caldav/datastore/sql.py
    CalendarServer/branches/users/cdaboo/managed-attachments/txdav/common/datastore/sql.py
    CalendarServer/branches/users/cdaboo/managed-attachments/txdav/common/datastore/test/util.py

Modified: CalendarServer/branches/users/cdaboo/managed-attachments/calendarserver/tap/util.py
===================================================================
--- CalendarServer/branches/users/cdaboo/managed-attachments/calendarserver/tap/util.py	2012-11-26 22:04:00 UTC (rev 10084)
+++ CalendarServer/branches/users/cdaboo/managed-attachments/calendarserver/tap/util.py	2012-11-26 22:06:16 UTC (rev 10085)
@@ -233,8 +233,14 @@
     if quota == 0:
         quota = None
     if txnFactory is not None:
+        if config.EnableSSL:
+            uri = "https://%s:%s" % (config.ServerHostName, config.SSLPort,)
+        else:
+            uri = "http://%s:%s" % (config.ServerHostName, config.HTTPPort,)
+        attachments_uri = uri + "/calendars/__uids__/%(home)s/attachments/%(name)s"
         return CommonSQLDataStore(
-            txnFactory, notifierFactory, FilePath(config.AttachmentsRoot),
+            txnFactory, notifierFactory,
+            FilePath(config.AttachmentsRoot), attachments_uri,
             config.EnableCalDAV, config.EnableCardDAV,
             quota=quota,
             logLabels=config.LogDatabase.LabelsInSQL,

Modified: CalendarServer/branches/users/cdaboo/managed-attachments/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/users/cdaboo/managed-attachments/twistedcaldav/storebridge.py	2012-11-26 22:04:00 UTC (rev 10084)
+++ CalendarServer/branches/users/cdaboo/managed-attachments/twistedcaldav/storebridge.py	2012-11-26 22:06:16 UTC (rev 10085)
@@ -2181,9 +2181,8 @@
         if action == "attachment-add":
             rids = _getRIDs()
             content_type, filename = _getContentInfo()
-            uri = "https://caldav.corp.apple.com:8443/calendars/__uids__/%s/attachments/%s"
             try:
-                attachment, location = (yield self._newStoreObject.addAttachment(uri, rids, content_type, filename, request.stream))
+                attachment, location = (yield self._newStoreObject.addAttachment(rids, content_type, filename, request.stream))
             except AttachmentStoreFailed:
                 raise HTTPError(ErrorResponse(
                     FORBIDDEN,
@@ -2212,9 +2211,8 @@
         elif action == "attachment-update":
             mid = _getMID()
             content_type, filename = _getContentInfo()
-            uri = "https://caldav.corp.apple.com:8443/calendars/__uids__/%s/attachments/%s"
             try:
-                attachment, location = (yield self._newStoreObject.updateAttachment(uri, mid, content_type, filename, request.stream))
+                attachment, location = (yield self._newStoreObject.updateAttachment(mid, content_type, filename, request.stream))
             except AttachmentStoreValidManagedID:
                 raise HTTPError(ErrorResponse(
                     FORBIDDEN,

Modified: CalendarServer/branches/users/cdaboo/managed-attachments/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/managed-attachments/txdav/caldav/datastore/sql.py	2012-11-26 22:04:00 UTC (rev 10084)
+++ CalendarServer/branches/users/cdaboo/managed-attachments/txdav/caldav/datastore/sql.py	2012-11-26 22:06:16 UTC (rev 10085)
@@ -81,6 +81,7 @@
 
 from zope.interface.declarations import implements
 
+import collections
 import os
 import tempfile
 import uuid
@@ -834,8 +835,13 @@
 
         validateCalendarComponent(self, self._calendar, component, inserting, self._txn._migrating)
 
+        if inserting:
+            changes = (yield self.creatingResourceCheckAttachments(component))
+
         yield self.updateDatabase(component, inserting=inserting)
         if inserting:
+            if changes:
+                yield self.createdResourceAttachments(changes)
             yield self._calendar._insertRevision(self._name)
         else:
             yield self._calendar._updateRevision(self._name)
@@ -1289,8 +1295,74 @@
     hasPrivateComment = property(_get_hasPrivateComment, _set_hasPrivateComment)
 
     @inlineCallbacks
-    def addAttachment(self, pathpattern, rids, content_type, filename, stream):
+    def creatingResourceCheckAttachments(self, component):
+        """
+        A new component is going to be stored. Check any ATTACH properties that may be present
+        to verify they owned by the organizer/owner of the resource and re-write the managed-ids.
 
+        @param component: calendar component about to be stored
+        @type component: L{Component}
+        """
+
+        # Retrieve all ATTACH properties with a MANAGED-ID
+        attached = collections.defaultdict(list)
+        attachments = component.getAllPropertiesInAnyComponent("ATTACH", depth=1,)
+        for attachment in attachments:
+            managed_id = attachment.parameterValue("MANAGED-ID")
+            if managed_id is not None:
+                attached[managed_id].append(attachment)
+
+        # Punt if no managed attachments
+        if len(attached) == 0:
+            returnValue(None)
+
+        changes = yield self._addingManagedIDs(attached)
+        returnValue(changes)
+
+
+    @inlineCallbacks
+    def _addingManagedIDs(self, attached):
+        # Now check each managed-id
+        changes = []
+        for managed_id, attachments in attached.items():
+
+            # Must be in the same home as this resource
+            hids = (yield ManagedAttachment.homeForManagedID(self._txn, managed_id))
+            if len(hids) != 1:
+                # This is a bad store error - there should be only one home associated with a managed-id
+                raise InternalDataStoreError
+            if hids[0] != self._parentCollection.ownerHome()._resourceID:
+                raise AttachmentStoreValidManagedID
+
+            # Need to rewrite the managed-id, value in the properties
+            new_id = str(uuid.uuid4())
+            changes.append((managed_id, new_id,))
+            location = self._txn._store.attachmentsURIPattern % {
+                "home": self._parentCollection.ownerHome().name(),
+                "name": new_id,
+            }
+            original_attachment = (yield ManagedAttachment.load(self._txn, managed_id))
+            for attachment in attachments:
+                attachment.setParameter("MANAGED-ID", new_id)
+                attachment.setParameter("MTAG", original_attachment.md5())
+                attachment.setParameter("FMTTYPE", "%s/%s" % (original_attachment.contentType().mediaType, original_attachment.contentType().mediaSubtype))
+                attachment.setParameter("FILENAME", original_attachment.name())
+                attachment.setParameter("SIZE", str(original_attachment.size()))
+                attachment.setValue(location)
+
+        returnValue(changes)
+
+
+    @inlineCallbacks
+    def createdResourceAttachments(self, attached):
+        # Now update the managed id references for each new one
+        for old_id, new_id in attached:
+            new_id = (yield ManagedAttachment.copyManagedID(self._txn, old_id, new_id, self._resourceID))
+
+
+    @inlineCallbacks
+    def addAttachment(self, rids, content_type, filename, stream):
+
         # First write the data stream
 
         # We need to know the resource_ID of the home collection of the owner
@@ -1307,7 +1379,10 @@
         # Now try and adjust the actual calendar data
         calendar = (yield self.component())
 
-        location = pathpattern % (self._parentCollection.ownerHome().name(), attachment.managedID(),)
+        location = self._txn._store.attachmentsURIPattern % {
+            "home": self._parentCollection.ownerHome().name(),
+            "name": attachment.managedID(),
+        }
         attach = Property("ATTACH", location, params={
             "MANAGED-ID": attachment.managedID(),
             "MTAG": attachment.md5(),
@@ -1328,7 +1403,7 @@
 
 
     @inlineCallbacks
-    def updateAttachment(self, pathpattern, managed_id, content_type, filename, stream):
+    def updateAttachment(self, managed_id, content_type, filename, stream):
 
         # First check the supplied managed-id is associated with this resource
         cobjs = (yield ManagedAttachment.referencesTo(self._txn, managed_id))
@@ -1359,7 +1434,10 @@
         # Now try and adjust the actual calendar data
         calendar = (yield self.component())
 
-        location = pathpattern % (self._parentCollection.ownerHome().name(), attachment.managedID(),)
+        location = self._txn._store.attachmentsURIPattern % {
+            "home": self._parentCollection.ownerHome().name(),
+            "name": attachment.managedID(),
+        }
         attach = Property("ATTACH", location, params={
             "MANAGED-ID": attachment.managedID(),
             "MTAG": attachment.md5(),
@@ -2062,6 +2140,23 @@
 
     @classmethod
     @inlineCallbacks
+    def homeForManagedID(cls, txn, managedID):
+        """
+        Find all the calendar object resourceIds referenced by this supplied managed-id.
+        """
+        att = schema.ATTACHMENT
+        attco = schema.ATTACHMENT_CALENDAR_OBJECT
+        rows = (yield Select(
+            [att.CALENDAR_HOME_RESOURCE_ID, ],
+            From=att.join(attco, att.ATTACHMENT_ID == attco.ATTACHMENT_ID, "left outer"),
+            Where=(attco.MANAGED_ID == managedID),
+        ).on(txn))
+        hids = set([row[0] for row in rows]) if rows is not None else set()
+        returnValue(tuple(hids))
+
+
+    @classmethod
+    @inlineCallbacks
     def resourceRemoved(cls, txn, resourceID):
         """
         Remove all attachments referencing the specified resource.
@@ -2080,6 +2175,31 @@
             (yield attachment.removeFromResource(resourceID))
 
 
+    @classmethod
+    @inlineCallbacks
+    def copyManagedID(cls, txn, oldManagedID, newManagedID, referencedBy):
+        """
+        Copy a managed-ID to a new ID and associate the original attachment with the
+        new resource.
+        """
+
+        # Find all reference attachment-ids and dereference
+        attco = schema.ATTACHMENT_CALENDAR_OBJECT
+        aid = (yield Select(
+            [attco.ATTACHMENT_ID, ],
+            From=attco,
+            Where=(attco.MANAGED_ID == oldManagedID),
+        ).on(txn))[0][0]
+
+        yield Insert({
+            attco.ATTACHMENT_ID               : aid,
+            attco.MANAGED_ID                  : newManagedID,
+            attco.CALENDAR_OBJECT_RESOURCE_ID : referencedBy,
+        }).on(txn)
+
+        returnValue(newManagedID)
+
+
     def managedID(self):
         return self._managedID
 

Modified: CalendarServer/branches/users/cdaboo/managed-attachments/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/managed-attachments/txdav/common/datastore/sql.py	2012-11-26 22:04:00 UTC (rev 10084)
+++ CalendarServer/branches/users/cdaboo/managed-attachments/txdav/common/datastore/sql.py	2012-11-26 22:06:16 UTC (rev 10085)
@@ -145,7 +145,8 @@
 
     implements(ICalendarStore)
 
-    def __init__(self, sqlTxnFactory, notifierFactory, attachmentsPath,
+    def __init__(self, sqlTxnFactory, notifierFactory,
+                 attachmentsPath, attachmentsURIPattern,
                  enableCalendars=True, enableAddressBooks=True,
                  label="unlabeled", quota=(2 ** 20),
                  logLabels=False, logStats=False, logStatsLogFile=None, logSQL=False,
@@ -157,6 +158,7 @@
         self.sqlTxnFactory = sqlTxnFactory
         self.notifierFactory = notifierFactory
         self.attachmentsPath = attachmentsPath
+        self.attachmentsURIPattern = attachmentsURIPattern
         self.enableCalendars = enableCalendars
         self.enableAddressBooks = enableAddressBooks
         self.label = label

Modified: CalendarServer/branches/users/cdaboo/managed-attachments/txdav/common/datastore/test/util.py
===================================================================
--- CalendarServer/branches/users/cdaboo/managed-attachments/txdav/common/datastore/test/util.py	2012-11-26 22:04:00 UTC (rev 10084)
+++ CalendarServer/branches/users/cdaboo/managed-attachments/txdav/common/datastore/test/util.py	2012-11-26 22:06:16 UTC (rev 10085)
@@ -188,7 +188,11 @@
                             maxConnections=5)
         quota = deriveQuota(testCase)
         store = CommonDataStore(
-            cp.connection, notifierFactory, attachmentRoot, quota=quota
+            cp.connection,
+            notifierFactory,
+            attachmentRoot,
+            "https://example.com/calendars/__uids__/%(home)s/attachments/%(name)s",
+            quota=quota
         )
         store.label = currentTestID
         cp.startService()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20121126/5b4761ca/attachment-0001.html>


More information about the calendarserver-changes mailing list