# Calendaring is a simple CMF/Plone calendaring implementation. # Copyright (C) 2004 Enfold Systems # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # """ $Id: calendar.py,v 1.8 2005/01/11 00:26:34 dreamcatcher Exp $ """ from types import MethodType, FunctionType from Acquisition import aq_base from AccessControl import ClassSecurityInfo from Globals import InitializeClass from zExceptions import MethodNotAllowed, NotFound, Unauthorized from Products.Archetypes.public import * from Products.Calendaring.config import * from Products.Calendaring.model.traversal import ModelViewMixin from Products.CMFCore.utils import getToolByName, _getViewFor from Products.CMFCore.CMFCorePermissions import ModifyPortalContent, View new_actions = ( {'id': 'export_calendar', 'name': 'Export as iCalendar', 'action': "python: '%s/calendar_export' % object_url.replace('http://', 'webcal://')", 'permissions': (View,), 'category': 'document_actions', }, {'id': 'calendar_day_view', 'name': 'Daily View', 'action': 'string:${object_url}/day_view', 'permissions': (View,), 'category': 'document_actions', }, {'id': 'calendar_week_view', 'name': 'Weekly View', 'action': 'string:${object_url}/week_view', 'permissions': (View,), 'category': 'document_actions', }, {'id': 'calendar_month_view', 'name': 'Monthly View', 'action': 'string:${object_url}/month_view', 'permissions': (View,), 'category': 'document_actions', }, ) def modify_fti(fti): fti['actions'] = fti['actions'] + new_actions class Calendar(ModelViewMixin, BaseFolder): meta_type = portal_type = archetype_name = 'Calendar' filter_content_types = 1 event_types = ('ATEvent', 'Event') allowed_content_types = event_types + ('Calendar', ) _at_rename_after_creation = True security = ClassSecurityInfo() __dav_collection__ = False __dav_resource__ = True isAnObjectManager = False # XXX Breaks PUT handling on NullResource. # A fix has been checked in into Zope 2.7+ # def __len__(self): # return len(self._objects) security.declarePrivate('iterSelf') def iterSelf(self): return iter(self.objectValues()) security.declareProtected(ModifyPortalContent, 'addEvent') def addEvent(self, event): ev = self.getEvent(event, None) if ev is not None: ev.update(event) return event = aq_base(event) self._setObject(event.getId(), event) security.declareProtected(View, 'getEvent') def getEvent(self, event, default=None): for ev in self.iterSelf(): if ev == event: return ev return default security.declareProtected(ModifyPortalContent, 'removeEvent') def removeEvent(self, event): for ev in self.iterSelf(): if ev == event: self.manage_delObjects(ids=[ev.getId()]) security.declareProtected(ModifyPortalContent, 'update') def update(self, calendar=None, **kwargs): # XXX Clashes with BaseObject.update # so we handle carefully if calendar is not None: for event in calendar.iterSelf(): self.addEvent(event) elif kwargs: return BaseFolder.update(self, **kwargs) return None security.declareProtected(ModifyPortalContent, 'clear') def clear(self): ids = self.objectIds() self.manage_delObjects(ids=ids) security.declareProtected(ModifyPortalContent, 'fromFile') def fromFile(self, stream): """ Import events from a file into this calendar """ ct = getToolByName(self, 'portal_calendar') return ct.importCalendar(stream, dest=self, do_action=True) security.declareProtected(View, 'asCalendar') def asCalendar(self, REQUEST=None): """ Export the contents of this Calendar as an iCalendar file """ ct = getToolByName(self, 'portal_calendar') events = self.contentValues(filter={'portal_type':self.event_types}) return ct.exportCalendar(events=events, REQUEST=REQUEST) security.declareProtected(ModifyPortalContent, 'PUT') def PUT(self, REQUEST=None, RESPONSE=None): """ HTTP PUT handler """ if not REQUEST: REQUEST = self.REQUEST if not RESPONSE: RESPONSE = REQUEST.RESPONSE self.dav__init(REQUEST, RESPONSE) self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1) file = REQUEST['BODYFILE'] file.seek(0) if not hasattr(self, 'aq_parent'): # XXX We don't have access to portal_calendar # yet at this time, so we create a volatile # attribute and check it on afterAdd. self._v_upload = file else: self.fromFile(file) self.reindexObject() RESPONSE.setStatus(204) return RESPONSE def manage_afterAdd(self, item, container): BaseFolder.manage_afterAdd(self, item, container) # If the volatile attribute was set # in PUT, then we get the file and # import it. file = getattr(self, '_v_upload', None) if file is not None: self.fromFile(file) self.reindexObject() def manage_beforeDelete(self, item, container): BaseFolder.manage_beforeDelete(self, item, container) ct = getToolByName(item, 'portal_calendar') security.declareProtected(View, 'manage_FTPget') def manage_FTPget(self, REQUEST=None, RESPONSE=None): "Get the raw content for this object (also used for the WebDAV SRC)" if REQUEST is None: REQUEST = self.REQUEST if RESPONSE is None: RESPONSE = REQUEST.RESPONSE return self.asCalendar(REQUEST) def HEAD(self, REQUEST, RESPONSE): """Retrieve resource information without a response body. """ self.dav__init(REQUEST, RESPONSE) # Note that we are willing to acquire the default document # here because what we really care about is whether doing # a GET on this collection / would yield a 200 response. view = None putils = getToolByName(self, 'plone_utils') obj, pages = putils.browserDefault(self) if pages is not None and pages: view = getattr(self, pages[0]) if isinstance(view, (MethodType, FunctionType)): # Ignore methods view = None if view is None: # Try to find a action (view) try: view = _getViewFor(self) except (Unauthorized, 'Unauthorized', 'Not Found'): pass if view is not None: if hasattr(view, 'HEAD'): return view.HEAD(REQUEST, RESPONSE) raise MethodNotAllowed, ( 'Method not supported for this resource.' ) raise NotFound, 'The requested resource does not exist.' registerType(Calendar, PROJECTNAME) InitializeClass(Calendar)