[CalendarServer-changes] [7384] CalendarServer/branches/users/sagen/gm2submission

source_changes at macosforge.org source_changes at macosforge.org
Fri Apr 29 10:56:33 PDT 2011


Revision: 7384
          http://trac.macosforge.org/projects/calendarserver/changeset/7384
Author:   sagen at apple.com
Date:     2011-04-29 10:56:32 -0700 (Fri, 29 Apr 2011)
Log Message:
-----------
Applying inbox fix to branch

Modified Paths:
--------------
    CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/__init__.py
    CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/task.py
    CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/test/__init__.py
    CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/test/test_task.py
    CalendarServer/branches/users/sagen/gm2submission/calendarserver/tap/caldav.py
    CalendarServer/branches/users/sagen/gm2submission/twisted/plugins/caldav.py
    CalendarServer/branches/users/sagen/gm2submission/twistedcaldav/test/test_upgrade.py
    CalendarServer/branches/users/sagen/gm2submission/twistedcaldav/upgrade.py

Modified: CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/__init__.py
===================================================================
--- CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/__init__.py	2011-04-29 17:35:22 UTC (rev 7383)
+++ CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/__init__.py	2011-04-29 17:56:32 UTC (rev 7384)
@@ -1,19 +0,0 @@
-##
-# Copyright (c) 2005-2009 Apple 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.
-##
-
-"""
-CalendarServer "sidecar" processes
-"""

Modified: CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/task.py
===================================================================
--- CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/task.py	2011-04-29 17:35:22 UTC (rev 7383)
+++ CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/task.py	2011-04-29 17:56:32 UTC (rev 7384)
@@ -1,342 +0,0 @@
-# Copyright (c) 2005-2010 Apple 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.
-##
-
-from __future__ import with_statement
-
-__all__ = [
-    "CalDAVTaskService",
-    "CalDAVTaskServiceMaker",
-    "CalDAVTaskOptions",
-    "Task",
-]
-
-import os
-from datetime import date, timedelta
-
-from zope.interface import implements
-
-from twisted.application.service import MultiService, Service, IServiceMaker
-from twisted.internet.defer import DeferredList, inlineCallbacks, returnValue
-from twisted.internet.reactor import callLater
-from twisted.plugin import IPlugin
-from twisted.python.usage import Options, UsageError
-
-from twext.python.log import Logger, LoggingMixIn
-from twext.python.log import logLevelForNamespace, setLogLevelForNamespace
-
-from twistedcaldav.config import config
-from twistedcaldav.stdconfig import DEFAULT_CONFIG, DEFAULT_CONFIG_FILE
-from twistedcaldav.ical import Component
-from twistedcaldav.scheduling.cuaddress import LocalCalendarUser
-from twistedcaldav.scheduling.scheduler import DirectScheduler
-
-from calendarserver.tap.util import getRootResource, FakeRequest
-from calendarserver.tools.purge import purgeOldEvents
-
-log = Logger()
-
- at inlineCallbacks
-def processInboxItem(rootResource, directory, inboxFile, inboxItemFile, uuid):
-    log.debug("Processing inbox item %s" % (inboxItemFile,))
-
-    principals = rootResource.getChild("principals")
-    ownerPrincipal = principals.principalForUID(uuid)
-    cua = "urn:uuid:%s" % (uuid,)
-    owner = LocalCalendarUser(cua, ownerPrincipal,
-        inboxFile, ownerPrincipal.scheduleInboxURL())
-
-    data = inboxItemFile.iCalendarText()
-    calendar = Component.fromString(data)
-    try:
-        method = calendar.propertyValue("METHOD")
-    except ValueError:
-        returnValue(None)
-
-    if method == "REPLY":
-        # originator is attendee sending reply
-        originator = calendar.getAttendees()[0]
-    else:
-        # originator is the organizer
-        originator = calendar.getOrganizer()
-
-    originatorPrincipal = principals.principalForCalendarUserAddress(originator)
-    originator = LocalCalendarUser(originator, originatorPrincipal)
-    recipients = (owner,)
-    scheduler = DirectScheduler(FakeRequest(rootResource, "PUT"), inboxItemFile)
-    yield scheduler.doSchedulingViaPUT(originator, recipients, calendar, internal_request=False)
-
-    if os.path.exists(inboxItemFile.fp.path):
-        os.remove(inboxItemFile.fp.path)
-
-
-
-class Task(object):
-
-    def __init__(self, service, fileName):
-        self.service = service
-        self.taskName = fileName.split(".")[0]
-        self.taskFile = os.path.join(self.service.processingDir, fileName)
-
-    @inlineCallbacks
-    def run(self):
-        methodName = "task_%s" % (self.taskName,)
-        method = getattr(self, methodName, None)
-        if method:
-            try:
-                log.warn("Running task '%s'" % (self.taskName))
-                yield method()
-                log.warn("Completed task '%s'" % (self.taskName))
-            except Exception, e:
-                log.error("Failed task '%s' (%s)" % (self.taskName, e))
-                os.remove(self.taskFile)
-                raise
-        else:
-            log.error("Unknown task requested: '%s'" % (self.taskName))
-            os.remove(self.taskFile)
-            returnValue(None)
-
-    @inlineCallbacks
-    def task_scheduleinboxes(self):
-
-        calendars = self.service.root.getChild("calendars")
-        uidDir = calendars.getChild("__uids__")
-
-        inboxItems = set()
-        with open(self.taskFile) as input:
-            for inboxItem in input:
-                inboxItem = inboxItem.strip()
-                inboxItems.add(inboxItem)
-
-        for inboxItem in list(inboxItems):
-            log.info("Processing inbox item: %s" % (inboxItem,))
-            ignore, uuid, ignore, fileName = inboxItem.rsplit("/", 3)
-
-            homeFile = uidDir.getChild(uuid)
-            if not homeFile:
-                continue
-
-            inboxFile = homeFile.getChild("inbox")
-            if not inboxFile:
-                continue
-
-            inboxItemFile = inboxFile.getChild(fileName)
-
-            yield processInboxItem(
-                self.service.root,
-                self.service.directory,
-                inboxFile,
-                inboxItemFile,
-                uuid
-            )
-            inboxItems.remove(inboxItem)
-
-            # Rewrite the task file in case we exit before we're done
-            with open(self.taskFile + ".tmp", "w") as output:
-                for inboxItem in inboxItems:
-                    output.write("%s\n" % (inboxItem,))
-            os.rename(self.taskFile + ".tmp", self.taskFile)
-
-        os.remove(self.taskFile)
-
-
-    @inlineCallbacks
-    def task_purgeoldevents(self):
-
-        with open(self.taskFile) as input:
-            try:
-                value = input.read().strip()
-                days = int(value)
-            except ValueError:
-                log.error("Illegal value for purge days: %s" % (value,))
-            else:
-                cutoff = (date.today() -
-                    timedelta(days=days)).strftime("%Y%m%dT000000Z")
-                count = (yield purgeOldEvents(self.service.directory,
-                    self.service.root, cutoff))
-                log.info("Purged %d events" % (count,))
-
-        os.remove(self.taskFile)
-
-
-class CalDAVTaskService(Service):
-
-    def __init__(self, root):
-        self.root = root
-        self.directory = root.directory
-        self.seconds = 30 # How often to check for new tasks in incomingDir
-        self.taskDir = os.path.join(config.DataRoot, "tasks")
-        # New task files are placed into "incoming"
-        self.incomingDir = os.path.join(self.taskDir, "incoming")
-        # Task files get moved into "processing" and then removed when complete
-        self.processingDir = os.path.join(self.taskDir, "processing")
-
-    def startService(self):
-        log.info("Starting task service")
-
-        if not os.path.exists(self.taskDir):
-            os.mkdir(self.taskDir)
-        if not os.path.exists(self.incomingDir):
-            os.mkdir(self.incomingDir)
-        if not os.path.exists(self.processingDir):
-            os.mkdir(self.processingDir)
-
-        callLater(self.seconds, self.periodic, first=True)
-
-
-    def periodic(self, first=False):
-        # log.debug("Checking for tasks")
-
-        deferreds = []
-
-        try:
-            if first:
-                # check the processing directory to see if there are any tasks
-                # that didn't complete during the last server run; start those
-                for fileName in os.listdir(self.processingDir):
-                    if fileName.endswith(".task"):
-                        log.debug("Restarting old task: %s" % (fileName,))
-                        deferreds.append(Task(self, fileName).run())
-
-            for fileName in os.listdir(self.incomingDir):
-                if fileName.endswith(".task"):
-                    log.debug("Found new task: %s" % (fileName,))
-                    os.rename(os.path.join(self.incomingDir, fileName),
-                        os.path.join(self.processingDir, fileName))
-                    deferreds.append(Task(self, fileName).run())
-
-        finally:
-            callLater(self.seconds, self.periodic)
-
-        return DeferredList(deferreds)
-
-
-
-class CalDAVTaskOptions(Options):
-    optParameters = [[
-        "config", "f", DEFAULT_CONFIG_FILE, "Path to configuration file."
-    ]]
-
-    def __init__(self, *args, **kwargs):
-        super(CalDAVTaskOptions, self).__init__(*args, **kwargs)
-
-        self.overrides = {}
-
-    def _coerceOption(self, configDict, key, value):
-        """
-        Coerce the given C{val} to type of C{configDict[key]}
-        """
-        if key in configDict:
-            if isinstance(configDict[key], bool):
-                value = value == "True"
-
-            elif isinstance(configDict[key], (int, float, long)):
-                value = type(configDict[key])(value)
-
-            elif isinstance(configDict[key], (list, tuple)):
-                value = value.split(',')
-
-            elif isinstance(configDict[key], dict):
-                raise UsageError(
-                    "Dict options not supported on the command line"
-                )
-
-            elif value == 'None':
-                value = None
-
-        return value
-
-    def _setOverride(self, configDict, path, value, overrideDict):
-        """
-        Set the value at path in configDict
-        """
-        key = path[0]
-
-        if len(path) == 1:
-            overrideDict[key] = self._coerceOption(configDict, key, value)
-            return
-
-        if key in configDict:
-            if not isinstance(configDict[key], dict):
-                raise UsageError(
-                    "Found intermediate path element that is not a dictionary"
-                )
-
-            if key not in overrideDict:
-                overrideDict[key] = {}
-
-            self._setOverride(
-                configDict[key], path[1:],
-                value, overrideDict[key]
-            )
-
-
-    def opt_option(self, option):
-        """
-        Set an option to override a value in the config file. True, False, int,
-        and float options are supported, as well as comma seperated lists. Only
-        one option may be given for each --option flag, however multiple
-        --option flags may be specified.
-        """
-
-        if "=" in option:
-            path, value = option.split('=')
-            self._setOverride(
-                DEFAULT_CONFIG,
-                path.split('/'),
-                value,
-                self.overrides
-            )
-        else:
-            self.opt_option('%s=True' % (option,))
-
-    opt_o = opt_option
-
-    def postOptions(self):
-        config.load(self['config'])
-        config.updateDefaults(self.overrides)
-        self.parent['pidfile'] = None
-
-
-class CalDAVTaskServiceMaker (LoggingMixIn):
-    implements(IPlugin, IServiceMaker)
-
-    tapname = "caldav_task"
-    description = "Calendar Server Task Process"
-    options = CalDAVTaskOptions
-
-    def makeService(self, options):
-
-        svc = MultiService()
-        #
-        # The task sidecar doesn't care about system SACLs
-        #
-        config.EnableSACLs = False
-
-        #
-        # Change default log level to "info" as its useful to have
-        # that during startup
-        #
-        oldLogLevel = logLevelForNamespace(None)
-        setLogLevelForNamespace(None, "info")
-
-        rootResource = getRootResource(config, svc)
-
-        CalDAVTaskService(rootResource).setServiceParent(svc)
-
-        # Change log level back to what it was before
-        setLogLevelForNamespace(None, oldLogLevel)
-
-        return svc
-

Modified: CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/test/__init__.py
===================================================================
--- CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/test/__init__.py	2011-04-29 17:35:22 UTC (rev 7383)
+++ CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/test/__init__.py	2011-04-29 17:56:32 UTC (rev 7384)
@@ -1,15 +0,0 @@
-##
-# Copyright (c) 2010 Apple 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.
-##

Modified: CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/test/test_task.py
===================================================================
--- CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/test/test_task.py	2011-04-29 17:35:22 UTC (rev 7383)
+++ CalendarServer/branches/users/sagen/gm2submission/calendarserver/sidecar/test/test_task.py	2011-04-29 17:56:32 UTC (rev 7384)
@@ -1,216 +0,0 @@
-##
-# Copyright (c) 2009 Apple 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.
-##
-
-import os, zlib
-
-from calendarserver.sidecar.task import CalDAVTaskServiceMaker, CalDAVTaskOptions, Task
-from os.path import dirname, abspath
-from twext.python.plistlib import writePlist
-from twisted.python.usage import Options
-from twistedcaldav.config import config, ConfigDict
-from twistedcaldav.stdconfig import DEFAULT_CONFIG
-from twistedcaldav.test.util import TestCase, todo
-from twisted.internet.defer import inlineCallbacks
-
-# Points to top of source tree.
-sourceRoot = dirname(dirname(dirname(dirname(abspath(__file__)))))
-
-
-# TODO: update or delete task sidecar
-class CalDAVTaskServiceTest(object): # TestCase):
-    """
-    Test various parameters of our usage.Options subclass
-    """
-    def setUp(self):
-        """
-        Set up our options object, giving it a parent, and forcing the
-        global config to be loaded from defaults.
-        """
-        TestCase.setUp(self)
-        self.options = CalDAVTaskOptions()
-        self.options.parent = Options()
-        self.options.parent["uid"] = 0
-        self.options.parent["gid"] = 0
-        self.options.parent["nodaemon"] = False
-
-        self.config = ConfigDict(DEFAULT_CONFIG)
-
-        accountsFile = os.path.join(sourceRoot, "twistedcaldav/directory/test/accounts.xml")
-        self.config["DirectoryService"] = {
-            "params": {"xmlFile": accountsFile},
-            "type": "twistedcaldav.directory.xmlfile.XMLDirectoryService"
-        }
-
-        self.config.DocumentRoot   = self.mktemp()
-        self.config.DataRoot       = self.mktemp()
-        self.config.ProcessType    = "Single"
-        self.config.Memcached.ClientEnabled = False
-        self.config.Memcached.ServerEnabled = False
-
-
-        pemFile = os.path.join(sourceRoot, "twistedcaldav/test/data/server.pem")
-        self.config.SSLPrivateKey = pemFile
-        self.config.SSLCertificate = pemFile
-
-        os.mkdir(self.config.DocumentRoot)
-        os.mkdir(self.config.DataRoot)
-
-        self.configFile = self.mktemp()
-
-        self.writeConfig()
-
-    def writeConfig(self):
-        """
-        Flush self.config out to self.configFile
-        """
-        writePlist(self.config, self.configFile)
-
-    def tearDown(self):
-        config.setDefaults(DEFAULT_CONFIG)
-        config.reload()
-
-    def makeService(self):
-        self.options.parseOptions(["-f", self.configFile])
-        return CalDAVTaskServiceMaker().makeService(self.options)
-
-    @todo("FIXME: fix after new store changes")
-    @inlineCallbacks
-    def test_taskService(self):
-        service = self.makeService()
-
-        structure = {
-            "calendars" : {
-                "__uids__" : {
-                    "64" : {
-                        "23" : {
-                            "6423F94A-6B76-4A3A-815B-D52CFD77935D" : {
-                                "calendar": {
-                                    "@xattrs" :
-                                    {
-                                        "WebDAV:{DAV:}resourcetype" : zlib.compress("<?xml version='1.0' encoding='UTF-8'?>\r\n<resourcetype xmlns='DAV:'>\r\n<collection/>\r\n<calendar xmlns='urn:ietf:params:xml:ns:caldav'/>\r\n</resourcetype>\r\n"),
-                                    },
-                                },
-                                "inbox": {
-                                    "unprocessed.ics": {
-                                        "@contents" : unprocessed,
-                                    }
-                                },
-                            }
-                        }
-                    }
-                }
-            },
-        }
-
-        self.createHierarchy(structure, root=self.config.DocumentRoot)
-
-        structure = {
-            "tasks" : {
-                "incoming" : { },
-                "processing" : {
-                    "scheduleinboxes.task" : {
-                        "@contents" : os.path.join(
-                            self.config.DocumentRoot,
-                            "calendars",
-                            "__uids__",
-                            "64",
-                            "23",
-                            "6423F94A-6B76-4A3A-815B-D52CFD77935D",
-                            "inbox",
-                            "unprocessed.ics"
-                        ),
-                    },
-                },
-            },
-        }
-
-        self.createHierarchy(structure, root=self.config.DataRoot)
-
-        task = Task(service, "scheduleinboxes.task")
-        yield task.run()
-
-        # Aftwards we want to see a .ics file in calendar and inbox
-        structure = {
-            "calendars" : {
-                "__uids__" : {
-                    "64" : {
-                        "23" : {
-                            "6423F94A-6B76-4A3A-815B-D52CFD77935D" : {
-                                "calendar": {
-                                    ".db.sqlite" : {
-                                        "@contents" : None,
-                                    },
-                                    "*.ics": {
-                                        "@contents" : None,
-                                    },
-                                },
-                                "inbox": {
-                                    ".db.sqlite" : {
-                                        "@contents" : None,
-                                    },
-                                    "*.ics": {
-                                        "@contents" : None,
-                                    },
-                                },
-                            }
-                        }
-                    }
-                }
-            },
-        }
-        self.assertTrue(self.verifyHierarchy(self.config.DocumentRoot, structure))
-
-unprocessed = """BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-METHOD:REQUEST
-PRODID:-//Apple Inc.//iCal 4.0.1//EN
-BEGIN:VTIMEZONE
-TZID:US/Pacific
-BEGIN:STANDARD
-DTSTART:20071104T020000
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
-TZNAME:PST
-TZOFFSETFROM:-0700
-TZOFFSETTO:-0800
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:20070311T020000
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-TZNAME:PDT
-TZOFFSETFROM:-0800
-TZOFFSETTO:-0700
-END:DAYLIGHT
-END:VTIMEZONE
-BEGIN:VEVENT
-UID:A40F4892-B40F-4C0F-B8D0-F4EB2C97F4B9
-DTSTART;TZID=US/Pacific:20091209T120000
-DTEND;TZID=US/Pacific:20091209T130000
-ATTENDEE;CN=Wilfredo Sanchez;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=N
- EEDS-ACTION;EMAIL=wsanchez at example.com;RSVP=TRUE:/principals/__uids__/6423F94
- A-6B76-4A3A-815B-D52CFD77935D/
-ATTENDEE;CUTYPE=INDIVIDUAL;CN=Morgen Sagen;PARTSTAT=ACCEPTED:mailto:sagen at exam
- ple.com
-CREATED:20091209T183541Z
-DTSTAMP:20091209T183612Z
-ORGANIZER;CN=Morgen Sagen:mailto:sagen at example.com
-SEQUENCE:6
-SUMMARY:Test
-TRANSP:OPAQUE
-END:VEVENT
-END:VCALENDAR
-""".replace("\n", "\r\n")
-

Modified: CalendarServer/branches/users/sagen/gm2submission/calendarserver/tap/caldav.py
===================================================================
--- CalendarServer/branches/users/sagen/gm2submission/calendarserver/tap/caldav.py	2011-04-29 17:35:22 UTC (rev 7383)
+++ CalendarServer/branches/users/sagen/gm2submission/calendarserver/tap/caldav.py	2011-04-29 17:56:32 UTC (rev 7384)
@@ -69,7 +69,7 @@
 from twistedcaldav.mail import IMIPReplyInboxResource
 from twistedcaldav import memcachepool
 from twistedcaldav.stdconfig import DEFAULT_CONFIG, DEFAULT_CONFIG_FILE
-from twistedcaldav.upgrade import UpgradeFileSystemFormatService
+from twistedcaldav.upgrade import UpgradeFileSystemFormatService, PostDBImportService
 
 from calendarserver.tap.util import pgServiceFromConfig
 
@@ -429,7 +429,6 @@
     L{DelayedStartupProcessMonitor}:
 
         - regular slave processes (CalDAV workers)
-        - task sidecar
         - notifier
         - mail gateway
     """
@@ -506,27 +505,8 @@
             self.monitor.addProcess("mailgateway", mailGatewayArgv,
                                env=PARENT_ENVIRONMENT)
 
-        self.maker.log_info("Adding task service")
-        taskArgv = [
-            sys.executable,
-            sys.argv[0],
-        ]
-        if config.UserName:
-            taskArgv.extend(("-u", config.UserName))
-        if config.GroupName:
-            taskArgv.extend(("-g", config.GroupName))
-        taskArgv.extend((
-            "--reactor=%s" % (config.Twisted.reactor,),
-            "-n", "caldav_task",
-            "-f", self.configPath,
-        ))
 
-        self.monitor.addProcess(
-            "caldav_task", taskArgv, env=PARENT_ENVIRONMENT
-        )
 
-
-
 class CalDAVServiceMaker (LoggingMixIn):
     implements(IPlugin, IServiceMaker)
 
@@ -982,7 +962,8 @@
             mainService = createMainService(cp, store)
             upgradeSvc = UpgradeFileSystemFormatService(config,
                 UpgradeToDatabaseService.wrapService(
-                    CachingFilePath(config.DocumentRoot), mainService,
+                    CachingFilePath(config.DocumentRoot),
+                    PostDBImportService(config, store, mainService),
                     store, uid=uid, gid=gid
                 )
             )

Modified: CalendarServer/branches/users/sagen/gm2submission/twisted/plugins/caldav.py
===================================================================
--- CalendarServer/branches/users/sagen/gm2submission/twisted/plugins/caldav.py	2011-04-29 17:35:22 UTC (rev 7383)
+++ CalendarServer/branches/users/sagen/gm2submission/twisted/plugins/caldav.py	2011-04-29 17:56:32 UTC (rev 7384)
@@ -50,6 +50,5 @@
 
 
 TwistedCalDAV     = TAP("calendarserver.tap.caldav.CalDAVServiceMaker")
-CalDAVTask        = TAP("calendarserver.sidecar.task.CalDAVTaskServiceMaker")
 CalDAVNotifier    = TAP("twistedcaldav.notify.NotificationServiceMaker")
 CalDAVMailGateway = TAP("twistedcaldav.mail.MailGatewayServiceMaker")

Modified: CalendarServer/branches/users/sagen/gm2submission/twistedcaldav/test/test_upgrade.py
===================================================================
--- CalendarServer/branches/users/sagen/gm2submission/twistedcaldav/test/test_upgrade.py	2011-04-29 17:35:22 UTC (rev 7383)
+++ CalendarServer/branches/users/sagen/gm2submission/twistedcaldav/test/test_upgrade.py	2011-04-29 17:56:32 UTC (rev 7384)
@@ -318,7 +318,6 @@
             },
             MailGatewayTokensDatabase.dbFilename : { "@contents" : None },
             "%s-journal" % (MailGatewayTokensDatabase.dbFilename,) : { "@contents" : None },
-            "tasks" : {"incoming" : {}}
         }
 
         (yield self.verifyDirectoryComparison(before, after))
@@ -385,12 +384,6 @@
         }
 
         after = {
-            "tasks" :
-            {
-                "incoming" :
-                {
-                },
-            },
             ".calendarserver_version" :
             {
                 "@contents" : "2",
@@ -505,12 +498,6 @@
                 {
                 },
             },
-            "tasks" :
-            {
-                "incoming" :
-                {
-                },
-            },
             ".calendarserver_version" :
             {
                 "@contents" : "2",
@@ -597,12 +584,6 @@
                 {
                 },
             },
-            "tasks" :
-            {
-                "incoming" :
-                {
-                },
-            },
             ".calendarserver_version" :
             {
                 "@contents" : "2",
@@ -691,12 +672,6 @@
             {
                 "@contents" : "",
             },
-            "tasks" :
-            {
-                "incoming" :
-                {
-                },
-            },
             ".calendarserver_version" :
             {
                 "@contents" : "2",
@@ -770,12 +745,6 @@
         }
 
         after = {
-            "tasks" :
-            {
-                "incoming" :
-                {
-                },
-            },
             ".calendarserver_version" :
             {
                 "@contents" : "2",
@@ -886,12 +855,6 @@
         }
 
         after = {
-            "tasks" :
-            {
-                "incoming" :
-                {
-                },
-            },
             ".calendarserver_version" :
             {
                 "@contents" : "2",
@@ -1006,12 +969,6 @@
         }
 
         after = {
-            "tasks" :
-            {
-                "incoming" :
-                {
-                },
-            },
             ".calendarserver_version" :
             {
                 "@contents" : "2",
@@ -1115,12 +1072,6 @@
 
 
         after = {
-            "tasks" :
-            {
-                "incoming" :
-                {
-                },
-            },
             "calendars" :
             {
                 "__uids__" :

Modified: CalendarServer/branches/users/sagen/gm2submission/twistedcaldav/upgrade.py
===================================================================
--- CalendarServer/branches/users/sagen/gm2submission/twistedcaldav/upgrade.py	2011-04-29 17:35:22 UTC (rev 7383)
+++ CalendarServer/branches/users/sagen/gm2submission/twistedcaldav/upgrade.py	2011-04-29 17:56:32 UTC (rev 7384)
@@ -33,10 +33,14 @@
 from twistedcaldav.mail import MailGatewayTokensDatabase
 from twistedcaldav.ical import Component
 from twistedcaldav import caldavxml
+from twistedcaldav.ical import Component
+from twistedcaldav.scheduling.cuaddress import LocalCalendarUser
+from twistedcaldav.scheduling.scheduler import DirectScheduler
 
+
 from twisted.application.service import Service
 from twisted.internet import reactor
-from twisted.internet.defer import inlineCallbacks, succeed
+from twisted.internet.defer import inlineCallbacks, succeed, returnValue
 
 from calendarserver.tools.util import getDirectory
 from calendarserver.tools.resources import migrateResources
@@ -46,6 +50,8 @@
     "txdav.base.propertystore.xattr.PropertyStore.deadPropertyXattrPrefix"
 )
 
+INBOX_ITEMS = "inboxitems.txt"
+
 log = Logger()
 
 def xattrname(n):
@@ -318,22 +324,7 @@
             os.chown(journalPath, uid, gid)
 
 
-    def createTaskServiceDirectory(config, uid, gid):
 
-        taskDir = os.path.join(config.DataRoot, "tasks")
-        if not os.path.exists(taskDir):
-            os.mkdir(taskDir)
-        os.chown(taskDir, uid, gid)
-
-        incomingDir = os.path.join(taskDir, "incoming")
-        if not os.path.exists(incomingDir):
-            os.mkdir(incomingDir)
-        os.chown(incomingDir, uid, gid)
-
-        return incomingDir
-
-
-
     directory = getDirectory()
 
     docRoot = config.DocumentRoot
@@ -429,13 +420,12 @@
                                         if not inboxItem.startswith("."):
                                             inboxItems.add(os.path.join(inboxPath, inboxItem))
 
-            incomingDir = createTaskServiceDirectory(config, uid, gid)
             if inboxItems:
-                taskFile = os.path.join(incomingDir, "scheduleinboxes.task")
-                with open(taskFile, "w") as out:
+                inboxItemsFile = os.path.join(config.DataRoot, INBOX_ITEMS)
+                with open(inboxItemsFile, "w") as out:
                     for item in inboxItems:
                         out.write("%s\n" % (item))
-                os.chown(taskFile, uid, gid)
+                os.chown(inboxItemsFile, uid, gid)
 
             if total:
                 log.warn("Processing %d calendar homes in %s" % (total, uidHomes))
@@ -713,3 +703,152 @@
 
 
 
+class PostDBImportService(Service, object):
+    """
+    Service for processing non-implicit inbox items after data has been
+    imported into the DB
+    """
+
+    def __init__(self, config, store, service):
+        """
+        Initialize the service.
+        """
+        self.wrappedService = service
+        self.store = store
+        self.config = config
+
+    def startService(self):
+        """
+        Start the service.
+        """
+        self.processInboxItems()
+
+
+    @inlineCallbacks
+    def processInboxItems(self):
+        """
+        When data is migrated from a non-implicit scheduling server there can
+        be inbox items that clients have not yet processed.  This method
+        runs those inbox items through the implicit scheduling mechanism.
+        """
+
+        inboxItemsList = os.path.join(self.config.DataRoot, INBOX_ITEMS)
+        if os.path.exists(inboxItemsList):
+
+            root = getRootResource(self.config, self.store)
+            directory = root.getDirectory()
+            principalCollection = directory.principalCollection
+
+            inboxItems = set()
+            with open(inboxItemsList) as input:
+                for inboxItem in input:
+                    inboxItem = inboxItem.strip()
+                    inboxItems.add(inboxItem)
+
+            try:
+                for inboxItem in list(inboxItems):
+                    log.info("Processing inbox item: %s" % (inboxItem,))
+                    ignore, uuid, ignore, fileName = inboxItem.rsplit("/", 3)
+
+                    record = directory.recordWithUID(uuid)
+                    if not record:
+                        continue
+
+                    principal = principalCollection.principalForRecord(record)
+                    if not principal:
+                        continue
+
+                    request = FakeRequest(root, "PUT", None)
+                    request.checkedSACL = True
+                    request.authnUser = request.authzUser = davxml.Principal(
+                        davxml.HRef.fromString("/principals/__uids__/%s/" % (uuid,))
+                    )
+
+                    calendarHome = yield principal.calendarHome(request)
+                    if not calendarHome:
+                        continue
+
+                    inbox = yield calendarHome.getChild("inbox")
+                    if inbox and inbox.exists():
+
+                        inboxItemResource = yield inbox.getChild(fileName)
+                        if inboxItemResource and inboxItemResource.exists():
+
+                            uri = "/calendars/__uids__/%s/inbox/%s" % (uuid,
+                                fileName)
+                            request.path = uri
+                            request._rememberResource(inboxItemResource, uri)
+
+                            yield self.processInboxItem(
+                                root,
+                                directory,
+                                principal,
+                                request,
+                                inbox,
+                                inboxItemResource,
+                                uuid,
+                                uri
+                            )
+                    inboxItems.remove(inboxItem)
+
+            except Exception, e:
+                log.error("Error processing inbox item: %s (%s)" % (inboxItem, e))
+                log.error("Restart calendar service to reattempt processing")
+
+            finally:
+                # Rewrite the inbox items file in case we exit before we're
+                # done so we'll pick up where we left off next time we start up.
+                if inboxItems:
+                    with open(inboxItemsList + ".tmp", "w") as output:
+                        for inboxItem in inboxItems:
+                            output.write("%s\n" % (inboxItem,))
+                    os.rename(inboxItemsList + ".tmp", inboxItemsList)
+                else:
+                    os.remove(inboxItemsList)
+
+        reactor.callLater(0, self.wrappedService.setServiceParent, self.parent)
+
+
+    @inlineCallbacks
+    def processInboxItem(self, root, directory, principal, request, inbox,
+        inboxItem, uuid, uri):
+        """
+        Run an individual inbox item through implicit scheduling and remove
+        the inbox item.
+        """
+
+        log.debug("Processing inbox item %s" % (inboxItem,))
+
+        ownerPrincipal = principal
+        cua = "urn:uuid:%s" % (uuid,)
+        owner = LocalCalendarUser(cua, ownerPrincipal,
+            inbox, ownerPrincipal.scheduleInboxURL())
+
+        data = yield inboxItem.iCalendarText()
+        calendar = Component.fromString(data)
+        try:
+            method = calendar.propertyValue("METHOD")
+        except ValueError:
+            returnValue(None)
+
+        if method == "REPLY":
+            # originator is attendee sending reply
+            originator = calendar.getAttendees()[0]
+        else:
+            # originator is the organizer
+            originator = calendar.getOrganizer()
+
+        principalCollection = directory.principalCollection
+        originatorPrincipal = principalCollection.principalForCalendarUserAddress(originator)
+        originator = LocalCalendarUser(originator, originatorPrincipal)
+        recipients = (owner,)
+
+        txn = request._newStoreTransaction
+        scheduler = DirectScheduler(request, inboxItem)
+        # Process inbox item
+        yield scheduler.doSchedulingViaPUT(originator, recipients, calendar,
+            internal_request=False)
+        # Remove item
+        yield inboxItem.storeRemove(request, True, uri)
+        yield txn.commit()
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110429/177d5cea/attachment-0001.html>


More information about the calendarserver-changes mailing list