Back to index

plone3  3.1.7
move.py
Go to the documentation of this file.
00001 from OFS.SimpleItem import SimpleItem
00002 from persistent import Persistent 
00003 
00004 from zope.interface import implements, Interface
00005 from zope.component import adapts
00006 from zope.formlib import form
00007 from zope import schema
00008 
00009 from zope.event import notify
00010 from zope.app.container.contained import ObjectMovedEvent
00011 from zope.app.container.contained import notifyContainerModified
00012 
00013 import OFS.subscribers
00014 from OFS.event import ObjectWillBeMovedEvent
00015 from OFS.CopySupport import sanity_check
00016 
00017 from plone.contentrules.rule.interfaces import IExecutable, IRuleElementData
00018 
00019 from plone.app.contentrules.browser.formhelper import AddForm, EditForm 
00020 from plone.app.vocabularies.catalog import SearchableTextSourceBinder
00021 from plone.app.form.widgets.uberselectionwidget import UberSelectionWidget
00022 import transaction
00023 
00024 from Acquisition import aq_inner, aq_parent, aq_base
00025 from ZODB.POSException import ConflictError
00026 from Products.CMFCore.utils import getToolByName
00027 from Products.CMFPlone import PloneMessageFactory as _
00028 
00029 from Products.CMFPlone import utils
00030 from Products.statusmessages.interfaces import IStatusMessage
00031 
00032 class IMoveAction(Interface):
00033     """Interface for the configurable aspects of a move action.
00034     
00035     This is also used to create add and edit forms, below.
00036     """
00037     
00038     target_folder = schema.Choice(title=_(u"Target folder"),
00039                                   description=_(u"As a path relative to the portal root."),
00040                                   required=True,
00041                                   source=SearchableTextSourceBinder({'is_folderish' : True},
00042                                                                     default_query='path:'))
00043          
00044 class MoveAction(SimpleItem):
00045     """The actual persistent implementation of the action element.
00046     """
00047     implements(IMoveAction, IRuleElementData)
00048     
00049     target_folder = ''
00050     element = 'plone.actions.Move'
00051     
00052     @property
00053     def summary(self):
00054         return _(u"Move to folder ${folder}", mapping=dict(folder=self.target_folder))
00055     
00056 class MoveActionExecutor(object):
00057     """The executor for this action.
00058     """
00059     implements(IExecutable)
00060     adapts(Interface, IMoveAction, Interface)
00061          
00062     def __init__(self, context, element, event):
00063         self.context = context
00064         self.element = element
00065         self.event = event
00066 
00067     def __call__(self):
00068         portal_url = getToolByName(self.context, 'portal_url', None)
00069         if portal_url is None:
00070             return False
00071         
00072         obj = self.event.object
00073         parent = aq_parent(aq_inner(obj))
00074         
00075         path = self.element.target_folder
00076         if len(path) > 1 and path[0] == '/':
00077             path = path[1:]
00078         target = portal_url.getPortalObject().unrestrictedTraverse(str(path), None)
00079     
00080         if target is None:
00081             self.error(obj, _(u"Target folder ${target} does not exist.", mapping={'target' : path}))
00082             return False
00083             
00084         if target.absolute_url() == parent.absolute_url():
00085             # We're already here!
00086             return True
00087         
00088         try:
00089             obj._notifyOfCopyTo(target, op=1)
00090         except ConflictError:
00091             raise
00092         except Exception, e:
00093             self.error(obj, str(e))
00094             return False
00095 
00096         # Are we trying to move into the same container that we copied from?
00097         if not sanity_check(target, obj):
00098             return False
00099 
00100         old_id = obj.getId()
00101         new_id = self.generate_id(target, old_id)
00102 
00103         notify(ObjectWillBeMovedEvent(obj, parent, old_id, target, new_id))
00104 
00105         obj.manage_changeOwnershipType(explicit=1)
00106 
00107         try:
00108             parent._delObject(old_id, suppress_events=True)
00109         except TypeError:
00110             # BBB: removed in Zope 2.11
00111             parent._delObject(old_id)
00112         
00113         obj = aq_base(obj)
00114         obj._setId(new_id)
00115 
00116         try:
00117             target._setObject(new_id, obj, set_owner=0, suppress_events=True)
00118         except TypeError:
00119             # BBB: removed in Zope 2.11
00120             target._setObject(new_id, obj, set_owner=0)
00121         obj = target._getOb(new_id)
00122 
00123         notify(ObjectMovedEvent(obj, parent, old_id, target, new_id))
00124         notifyContainerModified(parent)
00125         if aq_base(parent) is not aq_base(target):
00126             notifyContainerModified(target)
00127 
00128         obj._postCopy(target, op=1)
00129         
00130         # try to make ownership implicit if possible
00131         obj.manage_changeOwnershipType(explicit=0)
00132         
00133         return True
00134         
00135     def error(self, obj, error):
00136         request = getattr(self.context, 'REQUEST', None)
00137         if request is not None:
00138             title = utils.pretty_title_or_id(obj, obj)
00139             message = _(u"Unable to move ${name} as part of content rule 'move' action: ${error}",
00140                           mapping={'name' : title, 'error' : error})
00141             IStatusMessage(request).addStatusMessage(message, type="error")
00142             
00143     def generate_id(self, target, old_id):
00144         taken = getattr(target, 'has_key', None)
00145         if taken is None:
00146             item_ids = set(target.objectIds())
00147             taken = lambda x: x in item_ids
00148         if not taken(old_id):
00149             return old_id
00150         idx = 1
00151         while taken("%s.%d" % (old_id, idx)):
00152             idx += 1
00153         return "%s.%d" % (old_id, idx)
00154         
00155 class MoveAddForm(AddForm):
00156     """An add form for move-to-folder actions.
00157     """
00158     form_fields = form.FormFields(IMoveAction)
00159     form_fields['target_folder'].custom_widget = UberSelectionWidget
00160     label = _(u"Add Move Action")
00161     description = _(u"A move action can move an object to a different folder.")
00162     form_name = _(u"Configure element")
00163     
00164     def create(self, data):
00165         a = MoveAction()
00166         form.applyChanges(a, self.form_fields, data)
00167         return a
00168 
00169 class MoveEditForm(EditForm):
00170     """An edit form for move rule actions.
00171     
00172     Formlib does all the magic here.
00173     """
00174     form_fields = form.FormFields(IMoveAction)
00175     form_fields['target_folder'].custom_widget = UberSelectionWidget
00176     label = _(u"Edit Move Action")
00177     description = _(u"A move action can move an object to a different folder.")
00178     form_name = _(u"Configure element")