def plonegroup_contact_transition(contact, event):
    """
        React when a IPloneGroupContact transition is done
    """
    if event.transition and event.transition.id == 'deactivate':
        # check if the transition is selected
        registry = getUtility(IRegistry)
        pp = api.portal.get_tool('portal_properties')
        errors = []
        if contact.UID() in registry[ORGANIZATIONS_REGISTRY]:
            errors.append(_('This contact is selected in configuration'))
        elif pp.site_properties.enable_link_integrity_checks:
            search_value_in_objects(contact, contact.UID(), p_types=[], type_fields={})
            storage = ILinkIntegrityInfo(contact.REQUEST)
            breaches = storage.getIntegrityBreaches()
            if contact in breaches:
                errors.append(_("This contact is used in following content: ${items}",
                                mapping={'items': ', '.join(['<a href="%s" target="_blank">%s</a>'
                                                             % (i.absolute_url(), i.Title())
                                                             for i in breaches[contact]])}))
        if errors:
            smi = IStatusMessage(contact.REQUEST)
            smi.addStatusMessage(_('You cannot deactivate this item !'), type='error')
            smi.addStatusMessage(errors[0], type='error')
            view_url = getMultiAdapter((contact, contact.REQUEST), name=u'plone_context_state').view_url()
            # contact.REQUEST['RESPONSE'].redirect(view_url)
            raise Redirect(view_url)
Beispiel #2
0
def on_removed_resource(resource, event):
    request = getattr(resource, 'REQUEST', None)

    if request is None:
        return

    info = ILinkIntegrityInfo(request)

    if info.integrityCheckingEnabled():
        if info.getIntegrityBreaches():
            return

        # info.isConfirmedItem simply does not work
        # it is really awful to have to deal with these internals

        if 'form.submitted' not in request:
            return

        if 'form.button.Cancel' in request:
            return

        if getattr(request, 'link_integrity_events_counter', 0) != 2:
            return

    log.info('extinguising resource {}'.format(resource.uuid()))
    db.extinguish_resource(resource.uuid())
def referenceRemoved(obj, event, toInterface=IContactContent):
    """Store information about the removed link integrity reference.
    """
    # inspired from z3c/relationfield/event.py:breakRelations
    # and plone/app/linkintegrity/handlers.py:referenceRemoved
    # if the object the event was fired on doesn't have a `REQUEST` attribute
    # we can safely assume no direct user action was involved and therefore
    # never raise a link integrity exception...
    request = aq_get(obj, 'REQUEST', None)
    if not request:
        return
    storage = ILinkIntegrityInfo(request)

    catalog = component.queryUtility(ICatalog)
    intids = component.queryUtility(IIntIds)
    if catalog is None or intids is None:
        return

    # find all relations that point to us
    obj_id = intids.queryId(obj)
    if obj_id is None:
        return

    rels = list(catalog.findRelations({'to_id': obj_id}))
    for rel in rels:
        if toInterface.providedBy(rel.to_object):
            storage.addBreach(rel.from_object, rel.to_object)
Beispiel #4
0
def isLinked(obj):
    """ check if the given content object is linked from another one
        WARNING: don't use this function in your code!!
            it is a helper for the link integrity code and will potentially
            abort the ongoing transaction, giving you unexpected results...
    """
    # first check to see if link integrity handling has been enabled at all
    # and if so, if the removal of the object was already confirmed, i.e.
    # while replaying the request;  unfortunately this makes it necessary
    # to import from plone.app.linkintegrity here, hence the try block...
    try:
        from plone.app.linkintegrity.interfaces import ILinkIntegrityInfo
        info = ILinkIntegrityInfo(obj.REQUEST)
    except (ImportError, TypeError):
        # if p.a.li isn't installed the following check can be cut short...
        return False
    if not info.integrityCheckingEnabled():
        return False
    if info.isConfirmedItem(obj):
        return True
    # otherwise, when not replaying the request already, it is tried to
    # delete the object, making it possible to find out if it was referenced,
    # i.e. in case a link integrity exception was raised
    linked = False
    parent = obj.aq_inner.aq_parent
    try:
        parent.manage_delObjects(obj.getId())
    except OFS.ObjectManager.BeforeDeleteException, e:
        linked = True
    def is_relevant(self):
        request = self.obj.REQUEST
        if getattr(request, '_activity_reported', False):
            return False
        else:
            setattr(request, '_activity_reported', True)

        info = ILinkIntegrityInfo(request)
        if not info.integrityCheckingEnabled():
            return True

        elif info.isConfirmedItem(self.obj):
            return True

        if request.URL.endswith('/sl_delete_object'):
            return True

        if request.has_key('form.submitted') and \
                request.URL.endswith('/delete_confirmation'):
            return True

        if request.URL.endswith('/folder_delete'):
            return True

        if request.has_key('form.button.Cancel'):
            return True

        return False
    def delete(self):
        uids = self.request['uids']
        ctool = getToolByName(self.context, 'portal_catalog')
        mtool = getToolByName(self.context, 'portal_membership')
        brains = ctool(UID=uids)
        fails = []
        success = 0
        integrity_info = ILinkIntegrityInfo(self.request)
        for b in brains:
            obj = b.getObject()
            integrity_info.addDeletedItem(obj)
            if not mtool.checkPermission('Delete objects', obj):
                fails.append(translate(_(u"Unauthorized: ${path}",
                                         mapping={'path': b.getPath()}),
                                       context=self.request))
            else:
                try:
                    parent = obj.getParentNode()
                    parent.manage_delObjects([obj.getId()])
                except LinkIntegrityNotificationException:
                    pass
                finally:
                    success += 1

        IStatusMessage(self.request).add(_("msg_objects_deleted",
                                           default="${num} object(s) deleted",
                                           mapping={'num': success}))
        if fails:
            IStatusMessage(self.request).add(
                      _("msg_objects_delete_failed",
                        default="${num} object(s) were not deleted : ${fails}",
                        mapping={'num': len(fails), 'fails': ", ".join(fails)}),
                      'error')
Beispiel #7
0
def referenceRemoved(obj, event, toInterface=IContactContent):
    """Store information about the removed link integrity reference.
    """
    # inspired from z3c/relationfield/event.py:breakRelations
    # and plone/app/linkintegrity/handlers.py:referenceRemoved
    # if the object the event was fired on doesn't have a `REQUEST` attribute
    # we can safely assume no direct user action was involved and therefore
    # never raise a link integrity exception...
    request = aq_get(obj, 'REQUEST', None)
    if not request:
        return
    storage = ILinkIntegrityInfo(request)

    catalog = component.queryUtility(ICatalog)
    intids = component.queryUtility(IIntIds)
    if catalog is None or intids is None:
        return

    # find all relations that point to us
    obj_id = intids.queryId(obj)
    if obj_id is None:
        return

    rels = list(catalog.findRelations({'to_id': obj_id}))
    for rel in rels:
        if toInterface.providedBy(rel.to_object):
            storage.addBreach(rel.from_object, rel.to_object)
 def test_plonegroupOrganizationRemoved_1(self):
     """ We cannot remove an organization selected in settings and used in an object """
     view = self.portal.restrictedTraverse(
         '{0}/{1}/department1/delete_confirmation'.format(DEFAULT_DIRECTORY_ID, PLONEGROUP_ORG))
     self.assertRaises(LinkIntegrityNotificationException, view.render)
     storage = ILinkIntegrityInfo(view.REQUEST)
     breaches = storage.getIntegrityBreaches()
     self.assertIn(self.contacts[0], breaches)
     self.assertSetEqual(breaches[self.contacts[0]], set([self.portal['acontent1']]))
 def test_plonegroupOrganizationRemoved_1(self):
     """ We cannot remove an organization selected in settings and used in an object """
     view = self.portal.restrictedTraverse(
         '{0}/{1}/department1/delete_confirmation'.format(
             DEFAULT_DIRECTORY_ID, PLONEGROUP_ORG))
     self.assertRaises(LinkIntegrityNotificationException, view.render)
     storage = ILinkIntegrityInfo(view.REQUEST)
     breaches = storage.getIntegrityBreaches()
     self.assertIn(self.contacts[0], breaches)
     self.assertSetEqual(breaches[self.contacts[0]],
                         set([self.portal['acontent1']]))
 def integrityBreaches(self):
     info = ILinkIntegrityInfo(self.request).getIntegrityBreaches()
     byTitle = lambda a, b: cmp(a.Title(), b.Title())
     breaches = []
     for target, sources in info.items():
         breaches.append({
             'title': target.Title(),
             'type': target.getPortalTypeName(),
             'url': target.absolute_url(),
             'sources': sorted(sources, byTitle),
         })
     return sorted(breaches, lambda a, b: cmp(a['title'], b['title']))
    def test_delete_content_succeeds_with_link_integrity_breach(self):
        doc2 = self.portal[self.portal.invokeFactory("Document",
                                                     id="doc2",
                                                     title="My Document")]
        from plone.app.linkintegrity.interfaces import ILinkIntegrityInfo

        info = ILinkIntegrityInfo(self.layer["request"])
        info.addBreach(doc2, self.doc1)
        service = self.traverse("/plone/doc1", method="DELETE")
        service()
        self.assertEqual(204, info.context.response.status)
        self.assertNotIn("doc1", self.portal.objectIds())
 def test_delete_content_succeeds_with_link_integrity_breach(self):
     doc2 = self.portal[self.portal.invokeFactory(
         'Document',
         id='doc2',
         title='My Document',
     )]
     from plone.app.linkintegrity.interfaces import ILinkIntegrityInfo
     info = ILinkIntegrityInfo(self.layer['request'])
     info.addBreach(doc2, self.doc1)
     service = self.traverse('/plone/doc1', method='DELETE')
     service()
     self.assertEqual(204, info.context.response.status)
     self.assertNotIn('doc1', self.portal.objectIds())
Beispiel #13
0
 def integrityBreaches(self):
     info = ILinkIntegrityInfo(self.request).getIntegrityBreaches()
     byTitle = lambda a, b: cmp((a.Title(), a.getId()), (b.Title(), b.getId()))
     breaches = []
     for target, sources in info.items():
         breaches.append({
             'title': target.Title(),
             'type': target.getPortalTypeName(),
             'type_title': self.getPortalTypeTitle(target),
             'url': target.absolute_url(),
             'sources': sorted(sources, byTitle),
         })
     return sorted(breaches, lambda a, b: cmp(a['title'], b['title']))
def referenceRemoved(obj, event):
    """ store information about the removed link integrity reference """
    assert IReference.providedBy(obj)
    assert obj is event.object          # just making sure...
    if not obj.relationship in get_protected_relationships():
        return                          # skip for other removed references
    # if the object the event was fired on doesn't have a `REQUEST` attribute
    # we can safely assume no direct user action was involved and therefore
    # never raise a link integrity exception...
    request = aq_get(obj, 'REQUEST', None)
    if not request:
        return
    storage = ILinkIntegrityInfo(request)
    storage.addBreach(obj.getSourceObject(), obj.getTargetObject())
Beispiel #15
0
def delete_integrity(context, event):
    request = getRequest()
    if request is not None:
        path = context.getPhysicalPath()
        for base in _ignorepaths(request):
            if tuple(path[:len(base)]) == base:
                # allow deletion of Plone site marked by before_site_delete()
                return
        used_by = InUseBy(context, request)
        if len(used_by) > 0:
            info = ILinkIntegrityInfo(request)
            for brain in used_by._brainmap.values():
                info.addBreach(brain._unrestrictedGetObject(), context)
            raise LinkIntegrityNotificationException(context)
Beispiel #16
0
 def integrityBreaches(self):
     info = ILinkIntegrityInfo(self.request).getIntegrityBreaches()
     byTitle = lambda a, b: cmp((a.Title(), a.getId()), (b.Title(), b.getId()))
     breaches = []
     for target, sources in info.items():
         breaches.append(
             {
                 "title": target.Title(),
                 "type": target.getPortalTypeName(),
                 "type_title": self.getPortalTypeTitle(target),
                 "url": target.absolute_url(),
                 "sources": sorted(sources, byTitle),
             }
         )
     return sorted(breaches, lambda a, b: cmp(a["title"], b["title"]))
Beispiel #17
0
    def __call__(self):
        payload = self.request.get('data', None)
        if not payload:
            raise BadRequest('No data given')

        # TODO validate payload contains blocks and confirmed flag.
        self.link_integrity = ILinkIntegrityInfo(self.request)

        data = json.loads(payload)
        self.block = uuidToObject(data['block'])

        if self.request.get('form.submitted', False):

            if self.link_integrity:
                # Always allow deletion of block, regardless of the integrity
                # check.
                self.request.environ[self.link_integrity.marker] = 'all'

            self.context.manage_delObjects([self.block.id])
            transaction_note('Deleted %s' % self.block.absolute_url())
            return json_response(self.request, proceed=True)
        else:
            return json_response(self.request,
                                 content=self.confirm_template(),
                                 proceed=False)
Beispiel #18
0
def createCommitteesFolder(portal):
    # New in profile version 1 (software version 1.0.3)
    if 'committees' in portal.objectIds():
        committees = portal['committees']
        if committees.portal_type == 'Committee Folder': return
        request = getattr(portal, 'REQUEST')
        getattr(request,
                'environ')[ILinkIntegrityInfo(request).getEnvMarker()] = 'all'
        # WTF: bug in plone.app.linkintegrity-1.0.12 line 43 AttributeError: 'NoneType' object has no attribute 'UID'
        try:
            portal.manage_delObjects('committees')
        except AttributeError:
            # OK, that was #fail. Try it without events.
            try:
                portal._delObject('committees', suppress_events=True)
            except AttributeError:
                pass
    committees = portal[portal.invokeFactory('Committee Folder', 'committees')]
    committees.setTitle(u'Committees')
    committees.setDescription(
        u'The following describes the committees, subcommittees, and other components of EDRN.'
    )
    committees.rdfDataSource = u'http://edrn-dev.jpl.nasa.gov/cancerdataexpo/rdf-data/committees/rdf'
    committees.setExcludeFromNav(True)
    committees.reindexObject()
    def test_enable_link_integrity_checks_active(self):
        self.browser.open("%s/@@editing-controlpanel" % self.portal_url)
        self.browser.getControl("Enable link integrity checks")\
            .selected = True
        self.browser.getControl('Save').click()

        self.assertTrue(
            ILinkIntegrityInfo(self.request).integrityCheckingEnabled())
Beispiel #20
0
def personnel_contact_removed(del_obj, event):
    """
        Check if a personnel held_position is used as sender.
    """
    # only interested by held_position user
    if del_obj.portal_type == 'person':
        return
    try:
        portal = api.portal.get()
        pp = portal.portal_properties
        catalog = portal.portal_catalog
    except api.portal.CannotGetPortalError:
        # When deleting site, the portal is no more found...
        return
    if pp.site_properties.enable_link_integrity_checks:
        storage = ILinkIntegrityInfo(aq_get(del_obj, 'REQUEST', None))
        for brain in catalog.unrestrictedSearchResults(portal_type=['dmsoutgoingmail'], sender_index=[del_obj.UID()]):
            storage.addBreach(brain._unrestrictedGetObject(), del_obj)
Beispiel #21
0
def isLinked(obj):
    """ check if the given content object is linked from another one

        WARNING: this function can be time consuming !!

            It deletes the object in a subtransaction that is rollbacked.
            In other words, the object is kept safe.

            Nevertheless, this implies that it also deletes recursively
            all object's subobjects and references, which can be very
            expensive.
    """
    # first check to see if link integrity handling has been enabled at all
    # and if so, if the removal of the object was already confirmed, i.e.
    # while replaying the request;  unfortunately this makes it necessary
    # to import from plone.app.linkintegrity here, hence the try block...
    try:
        from plone.app.linkintegrity.interfaces import ILinkIntegrityInfo

        info = ILinkIntegrityInfo(obj.REQUEST)
    except (ImportError, TypeError):
        # if p.a.li isn't installed the following check can be cut short...
        return False
    if not info.integrityCheckingEnabled():
        return False
    if info.isConfirmedItem(obj):
        return True
    # otherwise, when not replaying the request already, it is tried to
    # delete the object, making it possible to find out if it was referenced,
    # i.e. in case a link integrity exception was raised
    linked = False
    parent = obj.aq_inner.aq_parent
    try:
        savepoint = transaction.savepoint()
        parent.manage_delObjects(obj.getId())
    except OFS.ObjectManager.BeforeDeleteException:
        linked = True
    except:  # ignore other exceptions, not useful to us at this point
        pass
    finally:
        savepoint.rollback()
    return linked
Beispiel #22
0
def handle_remove_event(obj, event):
    """If an object will be removed on the senders instance, we need to create a
    publisher delete job.
    """
    # the event is notified for every subobject, but we only want to check
    # the top object which the users tries to delete
    if obj is not event.object:
        return

    workflow = get_workflow_name(obj)
    if not workflow or workflow not in config.PUBLISHING_WORKFLOWS:
        # we don't have a workflow or the workflow does not publish ever - so we
        # don't need to delete anything on the receiver.
        return

    # the event handler is fired twice (once from link integrity check), but
    # we just want to do our stuff once. And we should only do it if the user
    # already did confirm.
    do_delete = False
    request = getattr(obj, 'REQUEST', None)
    if request is None:
        do_delete = True
    else:
        info = ILinkIntegrityInfo(request)
        if not info.integrityCheckingEnabled():
            do_delete = True
        elif info.isConfirmedItem(obj):
            do_delete = True

    if request.URL.endswith('/sl_delete_object'):
        do_delete = True
    if request.has_key('form.submitted') and \
            request.URL.endswith('/delete_confirmation'):
        do_delete = True
    if request.URL.endswith('/folder_delete'):
        do_delete = True
    if request.has_key('form.button.Cancel'):
        do_delete = True

    # register the job
    if do_delete:
        obj.restrictedTraverse('@@publisher.delete')()
def handle_remove_event(obj, event):
    """If an object will be removed on the senders instance, we need to create a
    publisher delete job.
    """
    # the event is notified for every subobject, but we only want to check
    # the top object which the users tries to delete
    if obj is not event.object:
        return

    workflow = get_workflow_name(obj)
    if not workflow or workflow not in config.PUBLISHING_WORKFLOWS:
        # we don't have a workflow or the workflow does not publish ever - so we
        # don't need to delete anything on the receiver.
        return

    # the event handler is fired twice (once from link integrity check), but
    # we just want to do our stuff once. And we should only do it if the user
    # already did confirm.
    do_delete = False
    request = getattr(obj, 'REQUEST', None)
    if request is None:
        do_delete = True
    else:
        info = ILinkIntegrityInfo(request)
        if not info.integrityCheckingEnabled():
            do_delete = True
        elif info.isConfirmedItem(obj):
            do_delete = True

    if request.URL.endswith('/sl_delete_object'):
        do_delete = True
    if request.has_key('form.submitted') and \
            request.URL.endswith('/delete_confirmation'):
        do_delete = True
    if request.URL.endswith('/folder_delete'):
        do_delete = True
    if request.has_key('form.button.Cancel'):
        do_delete = True

    # register the job
    if do_delete:
        obj.restrictedTraverse('@@publisher.delete')()
Beispiel #24
0
def isLinked(obj):
    """ check if the given content object is linked from another one

        WARNING: this function can be time consuming !!

            It deletes the object in a subtransaction that is rollbacked.
            In other words, the object is kept safe.

            Nevertheless, this implies that it also deletes recursively
            all object's subobjects and references, which can be very
            expensive.
    """
    # first check to see if link integrity handling has been enabled at all
    # and if so, if the removal of the object was already confirmed, i.e.
    # while replaying the request;  unfortunately this makes it necessary
    # to import from plone.app.linkintegrity here, hence the try block...
    try:
        from plone.app.linkintegrity.interfaces import ILinkIntegrityInfo
        info = ILinkIntegrityInfo(obj.REQUEST)
    except (ImportError, TypeError):
        # if p.a.li isn't installed the following check can be cut short...
        return False
    if not info.integrityCheckingEnabled():
        return False
    if info.isConfirmedItem(obj):
        return True
    # otherwise, when not replaying the request already, it is tried to
    # delete the object, making it possible to find out if it was referenced,
    # i.e. in case a link integrity exception was raised
    linked = False
    parent = obj.aq_inner.aq_parent
    try:
        savepoint = transaction.savepoint()
        parent.manage_delObjects(obj.getId())
    except OFS.ObjectManager.BeforeDeleteException:
        linked = True
    except:  # ignore other exceptions, not useful to us at this point
        pass
    finally:
        savepoint.rollback()
    return linked
def referenceRemoved(obj, event):
    """ store information about the removed link integrity reference """
    assert IReference.providedBy(obj)
    assert obj is event.object          # just making sure...
    if not obj.relationship == referencedRelationship:
        return                          # skip for other removed references
    # if the object the event was fired on doesn't have a `REQUEST` attribute
    # we can safely assume no direct user action was involved and therefore
    # never raise a link integrity exception...
    request = aq_get(obj, 'REQUEST', None)
    if not request:
        return
    storage = ILinkIntegrityInfo(request)
    source = obj.getSourceObject()
    if not IBaseObject.providedBy(source) and hasattr(source, 'context'):
        source = source.context
    target = obj.getTargetObject()
    if not IBaseObject.providedBy(target) and hasattr(target, 'context'):
        target = target.context
    if source is not None and target is not None:
        storage.addBreach(source, target)
Beispiel #26
0
def referenceRemoved(obj, event):
    """ store information about the removed link integrity reference """
    assert IReference.providedBy(obj)
    assert obj is event.object  # just making sure...
    if not obj.relationship == referencedRelationship:
        return  # skip for other removed references
    # if the object the event was fired on doesn't have a `REQUEST` attribute
    # we can safely assume no direct user action was involved and therefore
    # never raise a link integrity exception...
    request = aq_get(obj, 'REQUEST', None)
    if not request:
        return
    storage = ILinkIntegrityInfo(request)
    source = obj.getSourceObject()
    if not IBaseObject.providedBy(source) and hasattr(source, 'context'):
        source = source.context
    target = obj.getTargetObject()
    if not IBaseObject.providedBy(target) and hasattr(target, 'context'):
        target = target.context
    if source is not None and target is not None:
        storage.addBreach(source, target)
Beispiel #27
0
def reference_document_removed(obj, event):
    """
        Check if there is a relation with another Document.
        Like collective.contact.core.subscribers.referenceRemoved.
        Where referenceObjectRemoved is also used
    """
    request = aq_get(obj, 'REQUEST', None)
    if not request:
        return
    # if '_link_integrity_check_' not in request:
    #     request.set('_link_integrity_check_', True)
    storage = ILinkIntegrityInfo(request)
    # confirmed = request.get('HTTP_REFERER').endswith('delete_confirmation?')

    catalog = queryUtility(ICatalog)
    intids = queryUtility(IIntIds)
    if catalog is None or intids is None:
        return

    obj_id = intids.queryId(obj)

    # find all relations that point to us
    for rel in catalog.findRelations({'to_id': obj_id, 'from_attribute': 'reply_to'}):
        storage.addBreach(rel.from_object, rel.to_object)
    # find relations we point
    for rel in catalog.findRelations({'from_id': obj_id, 'from_attribute': 'reply_to'}):
        storage.addBreach(rel.to_object, rel.from_object)
def plonegroup_contact_transition(contact, event):
    """
        React when a IPloneGroupContact transition is done
    """
    if event.transition and event.transition.id == 'deactivate':
        # check if the transition is selected
        pp = api.portal.get_tool('portal_properties')
        errors = []
        if contact.UID() in get_registry_organizations():
            errors.append(_('This contact is selected in configuration'))
        elif pp.site_properties.enable_link_integrity_checks:
            search_value_in_objects(contact,
                                    contact.UID(),
                                    p_types=[],
                                    type_fields={})
            storage = ILinkIntegrityInfo(contact.REQUEST)
            breaches = storage.getIntegrityBreaches()
            if contact in breaches:
                errors.append(
                    _("This contact is used in following content: ${items}",
                      mapping={
                          'items':
                          ', '.join([
                              '<a href="%s" target="_blank">%s</a>' %
                              (i.absolute_url(), i.Title())
                              for i in breaches[contact]
                          ])
                      }))
        if errors:
            smi = IStatusMessage(contact.REQUEST)
            smi.addStatusMessage(_('You cannot deactivate this item !'),
                                 type='error')
            smi.addStatusMessage(errors[0], type='error')
            view_url = getMultiAdapter((contact, contact.REQUEST),
                                       name=u'plone_context_state').view_url()
            # contact.REQUEST['RESPONSE'].redirect(view_url)
            raise Redirect(view_url)
Beispiel #29
0
def referencedObjectRemoved(obj, event):
    """ check if the removal was already confirmed or redirect to the form """
    # if the object the event was fired on doesn't have a `REQUEST` attribute
    # we can safely assume no direct user action was involved and therefore
    # never raise a link integrity exception...
    request = aq_get(obj, 'REQUEST', None)
    if not request:
        return
    info = ILinkIntegrityInfo(request)
    # first we check if link integrity checking was enabled
    if not info.integrityCheckingEnabled():
        return

    # since the event gets called for every subobject before it's
    # called for the item deleted directly via _delObject (event.object)
    # itself, but we do not want to present the user with a confirmation
    # form for every (referred) subobject, so we remember and skip them...
    info.addDeletedItem(obj)
    if obj is not event.object:
        return

    # if the number of expected events has been stored to help us prevent
    # multiple forms (i.e. in folder_delete), we wait for the next event
    # if we know there will be another...
    if info.moreEventsToExpect():
        return

    # at this point all subobjects have been removed already, so all
    # link integrity breaches caused by that have been collected as well;
    # if there aren't any (after things have been cleaned up),
    # we keep lurking in the shadows...
    if not info.getIntegrityBreaches():
        return

    # if the user has confirmed to remove the currently handled item in a
    # previous confirmation form we won't need it anymore this time around...
    if info.isConfirmedItem(obj):
        return

    # otherwise we raise an exception and pass the object that is supposed
    # to be removed as the exception value so we can use it as the context
    # for the view triggered by the exception;  this is needed since the
    # view is an adapter for the exception and a request, so it gets the
    # exception object as the context, which is not very useful...
    raise LinkIntegrityNotificationException(obj)
def referencedObjectRemoved(obj, event):
    """ check if the removal was already confirmed or redirect to the form """
    # if the object the event was fired on doesn't have a `REQUEST` attribute
    # we can safely assume no direct user action was involved and therefore
    # never raise a link integrity exception...
    request = aq_get(obj, 'REQUEST', None)
    if not request:
        return
    info = ILinkIntegrityInfo(request)
    # first we check if link integrity checking was enabled
    if not info.integrityCheckingEnabled():
        return

    # since the event gets called for every subobject before it's
    # called for the item deleted directly via _delObject (event.object)
    # itself, but we do not want to present the user with a confirmation
    # form for every (referred) subobject, so we remember and skip them...
    info.addDeletedItem(obj)
    if obj is not event.object:
        return

    # if the number of expected events has been stored to help us prevent
    # multiple forms (i.e. in folder_delete), we wait for the next event
    # if we know there will be another...
    if info.moreEventsToExpect():
        return

    # at this point all subobjects have been removed already, so all
    # link integrity breaches caused by that have been collected as well;
    # if there aren't any (after things have been cleaned up),
    # we keep lurking in the shadows...
    if not info.getIntegrityBreaches():
        return

    # if the user has confirmed to remove the currently handled item in a
    # previous confirmation form we won't need it anymore this time around...
    if info.isConfirmedItem(obj):
        return

    # otherwise we raise an exception and pass the object that is supposed
    # to be removed as the exception value so we can use it as the context
    # for the view triggered by the exception;  this is needed since the
    # view is an adapter for the exception and a request, so it gets the
    # exception object as the context, which is not very useful...
    raise LinkIntegrityNotificationException(obj)
Beispiel #31
0
    def __call__(self):
        # this view is intended to provide an action called by the
        # confirmation form;  all it does is prepare the request for
        # the retry exception and raise it...
        request = aq_inner(self.request)
        clicked = request.form.has_key
        if clicked('delete') or clicked('delete_all'):
            # the user choose to actually delete the referred to object,
            # so we reconstruct the original request which we interrupted
            # before, store the so far confirmed items and retry it...
            body, env = decodeRequestData(request.get('original_request'))

            marker = ILinkIntegrityInfo(request).getEnvMarker()
            if clicked('delete_all'):
                env[marker] = 'all'
            else:
                env[marker] = request.get('confirmed_items')
            auth = request._authUserPW()
            if auth is not None:
                authtoken = b64encode('%s:%s' % auth)
                env['HTTP_AUTHORIZATION'] = 'Basic %s' % authtoken
            env['HTTP_COOKIE'] = request.get('HTTP_COOKIE', '')

            # Update the original environment with the new one. In a WSGI
            # context, we want to update the dict, not overwrite it, because
            # we actually want to modify the WSGI environ. We also need to
            # make sure we don't touch keys that are not strings
            request._orig_env.update(env)

            # Set the stdin for the request
            new_stdin = StringIO(body)
            if 'wsgi.input' in request._orig_env:
                request._orig_env['wsgi.input'] = new_stdin
            setattr(request, 'stdin', new_stdin)

            raise Retry
        else:
            # the user choose to cancel the removal, in which case we
            # redirect back to the original HTTP_REFERER url...
            msg = _(u'Removal cancelled.')
            IStatusMessage(request).addStatusMessage(msg, type='info')
            request.RESPONSE.redirect(request.get('cancel_url'))
def search_value_in_objects(s_obj, ref, p_types=[], type_fields={}):
    """
        Searching a value (reference to an object like id or uid) in fields of objects.
        Parameters:
            * s_obj : the object that is maybe referenced in another objects fields
            * ref : the value to search in field
            * p_types : portal_types that will be only searched
            * type_fields : dict containing as key portal_type and as value a list of fields that must be searched.
                            If a portal_type is not given, all fields will be searched
    """
    # we check all dexterity objects fields to see if ref is used in
    # we can't check only fields using plonegroup vocabulary because maybe another vocabulary name is used
    # this can be long but this operation is not made so often

    request = aq_get(s_obj, 'REQUEST', None)
    if not request:
        return
    try:
        catalog = api.portal.get_tool('portal_catalog')
    except api.portal.CannotGetPortalError:
        # When deleting site, the portal is no more found...
        return

    storage = ILinkIntegrityInfo(request)

    def list_fields(ptype, filter_interfaces=(IText, ICollection, IChoice)):
        """ return for the portal_type the selected fields """
        if ptype not in type_fields:
            type_fields[ptype] = []
            fti = getUtility(IDexterityFTI, name=ptype)
            for name, fld in getFieldsInOrder(fti.lookupSchema()):
                for iface in filter_interfaces:
                    if iface.providedBy(fld):
                        type_fields[ptype].append(name)
                        break
            # also lookup behaviors
            for behavior_id in fti.behaviors:
                behavior = getUtility(IBehavior, behavior_id).interface
                for name, fld in getFieldsInOrder(behavior):
                    for iface in filter_interfaces:
                        if iface.providedBy(fld):
                            type_fields[ptype].append(name)
                            break
        return type_fields[ptype]

    def check_value(val):
        if isinstance(val, basestring) and val == ref:
            return True
        return False

    def check_attribute(val):
        """ check the attribute value and walk in it """
        if isinstance(val, dict):
            for v in val.values():
                res = check_attribute(v)
                if res:
                    return res
        elif base_hasattr(val, '__iter__'):
            for v in val:
                res = check_attribute(v)
                if res:
                    return res
        elif check_value(val):
            res = [val]
            return res
        return []

    for brain in catalog.unrestrictedSearchResults(portal_types=p_types,
                                                   object_provides=IDexterityContent.__identifier__):
        obj = brain._unrestrictedGetObject()
        ptype = obj.portal_type
        for attr in list_fields(ptype):
            if base_hasattr(obj, attr):
                res = check_attribute(getattr(obj, attr))
                if res:
                    storage.addBreach(obj, s_obj)
                    break
Beispiel #33
0
class DeleteBlocks(BrowserView):

    confirm_template = ViewPageTemplateFile(
        'templates/block_delete_confirmation.pt')

    def __init__(self, context, request):
        super(DeleteBlocks, self).__init__(context, request)
        self.block = None
        self.link_integrity = None

    def __call__(self):
        payload = self.request.get('data', None)
        if not payload:
            raise BadRequest('No data given')

        # TODO validate payload contains blocks and confirmed flag.
        self.link_integrity = ILinkIntegrityInfo(self.request)

        data = json.loads(payload)
        self.block = uuidToObject(data['block'])

        if self.request.get('form.submitted', False):

            if self.link_integrity:
                # Always allow deletion of block, regardless of the integrity
                # check.
                self.request.environ[self.link_integrity.marker] = 'all'

            self.context.manage_delObjects([self.block.id])
            transaction_note('Deleted %s' % self.block.absolute_url())
            return json_response(self.request, proceed=True)
        else:
            return json_response(self.request,
                                 content=self.confirm_template(),
                                 proceed=False)

    def get_link_integrity_breaches(self):
        if isLinked(self.block):
            breaches = self.link_integrity.getIntegrityBreaches()
            breaches_info = []
            sources = breaches.values()
            sources = len(sources) and sources[0] or sources

            for source in sources:
                breaches_info.append({'title': source.title_or_id(),
                                      'url': source.absolute_url()})

            return breaches_info
        else:
            return None

    def is_locked_for_current_user(self):
        locking_info = self.block.restrictedTraverse('@@plone_lock_info', None)
        if locking_info:
            return locking_info.is_locked_for_current_user()
        else:
            return False

    @property
    def context_state(self):
        return self.block.restrictedTraverse('@@plone_context_state')

    def block_payload(self):
        block = IUUID(self.block)
        return json.dumps({'block': block})
def clean_folder(self):
    """ find folders that are empty and delete them
        the loop run recursively until there is no more
        folders to cancel
    """
    catalog = self.portal_catalog
    total = 0
    transaction_threshold = 20

    # var for infinite loop
    empty_count = 42

    # Start information log
    info("START")
    out = StringIO()

    forced_delete = []

    while empty_count != 0:

        # Secure infinite loop
        empty_count = 0

        # Get all folders
        folders = catalog.unrestrictedSearchResults({
                                    'portal_type': ('ATFolder', 'Folder')
                                    })

        # Find empty folders and delete them
        for folder in folders:
            obj = folder._unrestrictedGetObject()
            if len(obj.getFolderContents()) == 0:
                empty_count += 1
                total += 1
                refs = obj.getBRefs(relationship='isReferencing')
                try:
                    obj.aq_parent.manage_delObjects([folder.id])
                except LinkIntegrityNotificationException:
                    li = ILinkIntegrityInfo(self.REQUEST)
                    self.REQUEST.environ['link_integrity_info'] = \
                        li.encodeConfirmedItems([obj])
                    forced_delete.append((obj.absolute_url(), refs))

                info(obj.absolute_url())

                # Commiting transaction
                if empty_count % transaction_threshold == 0:
                    info("Commit: delete %s folders", transaction_threshold)
                    transaction.savepoint()

    # End information log
    info("COMPLETE, %s folders deleted", total)
    print >> out, ("The following linkintegrity conflicts were encountered:")
    print >> out, ("The conflicting objects have been deleted, "
                   "but the referencing pages should be updated.")

    for failed, referencing in forced_delete:
        print >> out, "This object failed reference integrity: ", failed
        print >> out, "It was referenced by:"
        for r in referencing:
            print >> out, r.absolute_url()

    print >> out, "Total objects deleted %s" % total
    out.seek(0)

    return out.read()
Beispiel #35
0
 def confirmedItems(self):
     info = ILinkIntegrityInfo(self.request)
     targets = info.getIntegrityBreaches().keys()
     return info.encodeConfirmedItems(additions=targets)
Beispiel #36
0
def clean_folder(self):
    """ find folders that are empty and delete them
        the loop run recursively until there is no more
        folders to cancel
    """
    catalog = self.portal_catalog
    total = 0
    transaction_threshold = 20

    # var for infinite loop
    empty_count = 42

    # Start information log
    info("START")
    out = StringIO()

    forced_delete = []

    while empty_count != 0:

        # Secure infinite loop
        empty_count = 0

        # Get all folders
        folders = catalog.unrestrictedSearchResults(
            {'portal_type': ('ATFolder', 'Folder')})

        # Find empty folders and delete them
        for folder in folders:
            obj = folder._unrestrictedGetObject()
            if len(obj.getFolderContents()) == 0:
                empty_count += 1
                total += 1
                refs = obj.getBRefs(relationship='isReferencing')
                try:
                    obj.aq_parent.manage_delObjects([folder.id])
                except LinkIntegrityNotificationException:
                    li = ILinkIntegrityInfo(self.REQUEST)
                    self.REQUEST.environ['link_integrity_info'] = \
                        li.encodeConfirmedItems([obj])
                    forced_delete.append((obj.absolute_url(), refs))

                info(obj.absolute_url())

                # Commiting transaction
                if empty_count % transaction_threshold == 0:
                    info("Commit: delete %s folders", transaction_threshold)
                    transaction.savepoint()

    # End information log
    info("COMPLETE, %s folders deleted", total)
    print >> out, ("The following linkintegrity conflicts were encountered:")
    print >> out, ("The conflicting objects have been deleted, "
                   "but the referencing pages should be updated.")

    for failed, referencing in forced_delete:
        print >> out, "This object failed reference integrity: ", failed
        print >> out, "It was referenced by:"
        for r in referencing:
            print >> out, r.absolute_url()

    print >> out, "Total objects deleted %s" % total
    out.seek(0)

    return out.read()
Beispiel #37
0
    def __call__(self):
        _logger.info('INGEST EVERYTHING FULLY')

        # Turn OFF content rules during ingest
        contentRules = getUtility(IRuleStorage)
        contentRulesState = contentRules.active
        contentRules.active = False

        # Find out what paths to ingest
        context = aq_inner(self.context)
        portalURL = getToolByName(context, 'portal_url')
        portal = portalURL.getPortalObject()
        reportEmail = portal.getProperty('ingestReportEmail',
                                         _defaultIngestReportEmail)
        paths = portal.getProperty('edrnIngestPaths', [])
        doNotPublish = portal.getProperty('nonPublishedIngestPaths',
                                          _doNotPublish)
        doNotDelete = portal.getProperty('nonClearedIngestPaths', _doNotDelete)
        report = [
            u'The following is a report of the RDF ingest for the EDRN portal at {}:'
            .format(portalURL())
        ]

        try:
            # No paths?  No need to continue.
            if len(paths) == 0:
                _logger.info(
                    "There are no ingest paths, so there's nothing to ingest.")
                report.append(
                    u'There are no ingest paths configured for the portal, so no ingest'
                )
                return

            # We'll need the workflow tool later on.
            wfTool = getToolByName(context, 'portal_workflow')

            # Ignore link integrity checks
            request = aq_inner(self.request)
            getattr(
                request,
                'environ')[ILinkIntegrityInfo(request).getEnvMarker()] = 'all'

            # Ingest and publish each path
            for path in paths:
                try:
                    _logger.info('Starting ingest of "%s"', path)
                    report.append(u'Starting ingest of "{}"'.format(path))
                    obj = portal.restrictedTraverse(path.split('/'))
                    if path not in doNotDelete:
                        obj.manage_delObjects(obj.objectIds())
                    ingestor = getMultiAdapter((obj, self.request),
                                               name=u'ingest')
                    ingestor.render = False
                    ingestor()
                    transaction.commit()
                    _logger.info('Ingest of "%s" completed', path)
                    report.append(u'Ingest of "{}" completed'.format(path))
                    # Some paths don't need publication
                    if path not in doNotPublish:
                        self._publish(wfTool, obj)
                        _logger.info('And published all of "%s" too', path)
                        report.append(
                            u'Published everything in "{}"'.format(path))
                    else:
                        _logger.info(
                            'Skipping publishing of "%s" since it takes care of its own publication state',
                            path)
                        report.append(
                            u'Skipping publishing of "{}"; it takes care of its own publication'
                            .format(path))
                    transaction.commit()
                except:
                    _logger.exception('Ingest failed for "%s"', path)
                    report.append(u'Ingest failed for "{}"'.format(path))

            # And re-index
            _logger.info('Clearing and rebuilding the catalog')
            report.append(u'Clearing and rebuilding the catalog.')
            catalog = getToolByName(context, 'portal_catalog')
            catalog.clearFindAndRebuild()
            transaction.commit()

            # OK, now we can restore whatever the content rule state was
            contentRules.active = contentRulesState
            _logger.info('All ingestion completed')
            report.append(u'All ingestion completed')
        finally:
            date = unicode(datetime.date.today().isoformat())
            plone.api.portal.send_email(
                recipient=reportEmail,
                subject=u'EDRN Portal Ingest {} for {}'.format(
                    date, portalURL()),
                body=u'\n'.join(report))
Beispiel #38
0
 def confirmedItems(self):
     info = ILinkIntegrityInfo(self.request)
     targets = info.getIntegrityBreaches().keys()
     return info.encodeConfirmedItems(additions=targets)
def search_value_in_objects(s_obj, ref, p_types=[], type_fields={}):
    """
        Searching a value (reference to an object like id or uid) in fields of objects.
        Parameters:
            * s_obj : the object that is maybe referenced in another objects fields
            * ref : the value to search in field
            * p_types : portal_types that will be only searched
            * type_fields : dict containing as key portal_type and as value a list of fields that must be searched.
                            If a portal_type is not given, all fields will be searched
    """
    # we check all dexterity objects fields to see if ref is used in
    # we can't check only fields using plonegroup vocabulary because maybe another vocabulary name is used
    # this can be long but this operation is not made so often

    request = aq_get(s_obj, 'REQUEST', None)
    if not request:
        return
    try:
        catalog = api.portal.get_tool('portal_catalog')
    except api.portal.CannotGetPortalError:
        # When deleting site, the portal is no more found...
        return

    storage = ILinkIntegrityInfo(request)

    def list_fields(ptype, filter_interfaces=(IText, ICollection, IChoice)):
        """ return for the portal_type the selected fields """
        if ptype not in type_fields:
            type_fields[ptype] = []
            fti = getUtility(IDexterityFTI, name=ptype)
            for name, fld in getFieldsInOrder(fti.lookupSchema()):
                for iface in filter_interfaces:
                    if iface.providedBy(fld):
                        type_fields[ptype].append(name)
                        break
            # also lookup behaviors
            for behavior_id in fti.behaviors:
                behavior = getUtility(IBehavior, behavior_id).interface
                for name, fld in getFieldsInOrder(behavior):
                    for iface in filter_interfaces:
                        if iface.providedBy(fld):
                            type_fields[ptype].append(name)
                            break
        return type_fields[ptype]

    def check_value(val):
        if isinstance(val, basestring) and val == ref:
            return True
        return False

    def check_attribute(val):
        """ check the attribute value and walk in it """
        if isinstance(val, dict):
            for v in val.values():
                res = check_attribute(v)
                if res:
                    return res
        elif base_hasattr(val, '__iter__'):
            for v in val:
                res = check_attribute(v)
                if res:
                    return res
        elif check_value(val):
            res = [val]
            return res
        return []

    for brain in catalog.unrestrictedSearchResults(
            portal_types=p_types,
            object_provides=IDexterityContent.__identifier__):
        obj = brain._unrestrictedGetObject()
        ptype = obj.portal_type
        for attr in list_fields(ptype):
            if base_hasattr(obj, attr):
                res = check_attribute(getattr(obj, attr))
                if res:
                    storage.addBreach(obj, s_obj)
                    break