Confirm deletion event

What is the right way to get the confirm deletion object event?

Today I subscribe a IObjectRemovedEvent:

<configure
    xmlns="http://namespaces.zope.org/zope"
    xmlns:zcml="http://namespaces.zope.org/zcml">

  <subscriber                                                                                                                                                                                                                                                                    
      zcml:condition="installed plone.app.dexterity"
      for="plone.dexterity.interfaces.IDexterityContent
           zope.lifecycleevent.IObjectRemovedEvent"
      handler=".subscribers.myhandler"
      />

</configure>

But it is triggered many times, even before I confirm the deletion.

The docs suggest to read an old thread where Martin Aspelli explain that this event is triggered many times, and the first one is to check if the file can be deleted, and that transaction is rolled back after.

He also suggested to try an untested code:

from plone.app.linkintegrity.interfaces import ILinkIntegrityInfo 

def myhandler(obj, event): 
     request = getattr(obj, 'REQUEST', None) 
     realDelete = False 
     if request is None: 
         realDelete = True 
     else: 
         info = ILinkIntegrityInfo(request) 
         if not info.integrityCheckingEnabled(): 
             realDelete = True 
         elif not info.getIntegrityBreaches(): 
             realDelete = True 
         elif info.isConfirmedItem(obj): 
             realDelete = True 

     if realDelete: 
         # do your thing 

The problem is that this code never works.. In my case the method integrityCheckingEnabled always return True, the method getIntegrityBreaches always return {} and the method isConfirmedItem always return False.

maybe related with:

Maybe.. I really don't know what is going on here.

Doing some greps in omelette I can't find where Plone trigger the ObjectModifiedEvent event.

Can someone point me how is it done?

In one of our addons we use the notify method, but I can't find it at Plone source.

from zope.event import notify
from zope.lifecycleevent import ObjectModifiedEvent

notify(ObjectModifiedEvent(obj))

My mistake.. I was searching for IObjectModifiedEvent instead of ObjectRemovedEvent

Looking the code where the deletion confirmation happen and what happen when Delete button is clicked I think we should create a new event fired in all manage_delObjects calls:

Products/CMFPlone/Portal.py
103:    def manage_delObjects(self, ids=None, REQUEST=None):

Products/CMFPlone/PloneFolder.py
171:    def manage_delObjects(self, ids=None, REQUEST=None):

Products/Archetypes/BaseFolder.py
109:    def manage_delObjects(self, ids=None, REQUEST=None):

Products/MimetypesRegistry/MimeTypesRegistry.py
423:    def manage_delObjects(self, ids, REQUEST=None):

Products/OFSP/help/ObjectManager.py
122:    def manage_delObjects(ids):

Products/PortalTransforms/chain.py
161:    def manage_delObjects(self, ids, REQUEST=None):

plone/dexterity/content.py
661:    def manage_delObjects(self, ids=None, REQUEST=None):

OFS/ObjectManager.py
513:    def manage_delObjects(self, ids=[], REQUEST=None):

OFS/interfaces.py
569:    def manage_delObjects(ids=[], REQUEST=None):

I think the problem is the way link integrity was implemented in Plone 4; that was cleaned in Plone 5, so probably that doesn't happen anymore.

instead of creating a new event you should check if there's a way to identify if the event was fired as part of the link integrity feature or not; I think that was Martin's idea.

@hvelarde like I said before.. he code Martin wrote don't work.. looking at the thread mentioned above, I presume it worked before, but now it is broken.

what I meant is that you should have looked for a solution in that direction: trying to find out which one was the right event to process.

here you are:

def deletion_confirmed():
    """Check if we are in the context of a delete confirmation event.
    We need to be sure we're in the righ event to process it, as
    `IObjectRemovedEvent` is raised up to three times: the first one
    when the delete confirmation window is shown; the second when we
    select the 'Delete' button; and the last, as part of the
    redirection request to the parent container. Why? I have absolutely
    no idea. If we select 'Cancel' after the first event, then no more
    events are fired.
    """
    request = getRequest()
    is_delete_confirmation = 'delete_confirmation' in request.URL
    is_post = request.REQUEST_METHOD == 'POST'
    form_being_submitted = 'form.submitted' in request.form
    return is_delete_confirmation and is_post and form_being_submitted

now just add the following to your event subscriber:

if not deletion_confirmed():
    return

tested and working; now, if you want to find out why 3 IObjectRemovedEvent events are fired, go ahead…

1 Like

@hvelarde nice solution! this should go to Plone docs!

Lot of time ago I reached a similar needs by inspecting the request's content.
Don't remember details (and it was Archetype based) but it was something like this: check if the confirm button is in the request. IIRC you'll find the button only once so you can execute your code one time only (or skip it when the button is here... depends on what you need to do).

This solves our problem, thank you

But I still have the feeling that this event is broken, and should be replaced one day.

If you are using plone 5 go with content rules . this will save time