[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