Revision: 9270 http://trac.macosforge.org/projects/calendarserver/changeset/9270 Author: glyph@apple.com Date: 2012-05-24 13:33:22 -0700 (Thu, 24 May 2012) Log Message: ----------- UID case normalizers for ICalendar, ICalendarObject Modified Paths: -------------- CalendarServer/branches/users/glyph/uuid-normalize/txdav/caldav/datastore/util.py Modified: CalendarServer/branches/users/glyph/uuid-normalize/txdav/caldav/datastore/util.py =================================================================== --- CalendarServer/branches/users/glyph/uuid-normalize/txdav/caldav/datastore/util.py 2012-05-24 20:32:47 UTC (rev 9269) +++ CalendarServer/branches/users/glyph/uuid-normalize/txdav/caldav/datastore/util.py 2012-05-24 20:33:22 UTC (rev 9270) @@ -14,34 +14,38 @@ # See the License for the specific language governing permissions and # limitations under the License. ## -from twistedcaldav.config import config """ Utility logic common to multiple backend implementations. """ +import os +from uuid import UUID + +from zope.interface.declarations import implements + +from txdav.caldav.icalendarstore import IAttachmentStorageTransport + +from twisted.python.failure import Failure +from twisted.internet.defer import inlineCallbacks, Deferred, returnValue +from twisted.internet.protocol import Protocol + from twext.python.log import Logger + +from twext.web2 import http_headers + from twext.python.vcomponent import InvalidICalendarDataError from twext.python.vcomponent import VComponent -from twext.web2 import http_headers -from twisted.internet.defer import inlineCallbacks, Deferred, returnValue -from twisted.internet.protocol import Protocol - from twistedcaldav.datafilters.peruserdata import PerUserDataFilter from twistedcaldav.datafilters.privateevents import PrivateEventFilter -from txdav.caldav.icalendarstore import IAttachmentStorageTransport - from txdav.common.icommondatastore import ( InvalidObjectResourceError, NoSuchObjectResourceError, InternalDataStoreError, HomeChildNameAlreadyExistsError ) +from txdav.base.datastore.util import normalizeUUIDOrNot -from zope.interface.declarations import implements - -import os - log = Logger() validationBypass = False @@ -88,6 +92,7 @@ raise InvalidObjectResourceError(e) + @inlineCallbacks def dropboxIDFromCalendarObject(calendarObject): """ @@ -135,6 +140,7 @@ returnValue(uid + ".dropbox") + @inlineCallbacks def _migrateCalendar(inCalendar, outCalendar, getComponent, merge=False): """ @@ -170,7 +176,6 @@ bad_count += 1 continue - if ctype not in ("VEVENT", "VTODO"): log.error("Migration skipping unsupported (%s) calendar object %r" % (ctype, calendarObject)) @@ -241,6 +246,7 @@ returnValue((ok_count, bad_count,)) + # MIME helpers - mostly copied from twext.web2.static def loadMimeTypes(mimetype_locations=['/etc/mime.types']): @@ -280,12 +286,15 @@ return contentTypes + + def getType(filename, types, defaultType="application/octet-stream"): _ignore_p, ext = os.path.splitext(filename) ext = ext.lower() return types.get(ext, defaultType) + class _AttachmentMigrationProto(Protocol, object): def __init__(self, storeTransport): self.storeTransport = storeTransport @@ -330,6 +339,7 @@ complete. """ if not merge: + from twistedcaldav.config import config yield outHome.removeCalendarWithName("calendar") if config.RestrictCalendarsToOneComponentType: yield outHome.removeCalendarWithName("tasks") @@ -434,6 +444,7 @@ return '<Storing Attachment: %r%s>' % (self.attachment.name(), host) + class StorageTransportBase(object): """ Base logic shared between file- and sql-based L{IAttachmentStorageTransport} @@ -467,3 +478,57 @@ def writeSequence(self, seq): return self.write(''.join(seq)) + + + +def fixOneCalendarObject(component): + """ + Correct the properties which may contain a user's directory UUID within a + single calendar component, by normalizing the directory UUID. + + @param component: any iCalendar component. + @type component: L{twistedcaldav.ical.Component} + + @return: a 2-tuple of the number of fixes performed and the new + L{Component} + """ + fixes = 0 + for calprop in component.properties(): + if calprop.name() in ( + "ATTENDEE", "ORGANIZER", PerUserDataFilter.PERUSER_UID + ): + preval = calprop.value() + postval = normalizeUUIDOrNot(preval) + if preval != postval: + fixes += 1 + calprop.setValue(preval) + for subc in component.subcomponents(): + count, fixsubc = fixOneCalendarObject(subc) + fixes += count + return fixes, component + + + +@inlineCallbacks +def fixOneCalendarHome(home): + """ + Correct the case of UIDs on one L{ICalendarHome}. + + @return: a L{Deferred} that fires with the number of fixes made when the + fixes are complete. + """ + fixedThisHome = 0 + for calendar in (yield home.calendars()): + for calObj in (yield calendar.calendarObjects()): + try: + comp = (yield calObj.component()) + fixCount, comp = fixOneCalendarObject(comp) + fixedThisHome += fixCount + if fixCount: + yield calObj.setComponent(comp) + except: + log.err(Failure(), + 'Error while processing calendar/object %r %r' % ( + calendar.name(), calObj.name() + )) + returnValue(fixedThisHome)