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 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 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())
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())
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)
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)
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)
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
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