def test_plonegroupOrganizationRemoved_4(self): """ We cannot remove an organization selected in settings and used in an object as dict or list """ # set uid in dict self.portal['acontent1'].pg_organization = { 'uid': self.contacts[0].UID() } 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']])) # set uid in list self.portal['acontent2'].pg_organization = [self.contacts[1].UID()] view = self.portal.restrictedTraverse( '{0}/{1}/department2/delete_confirmation'.format( DEFAULT_DIRECTORY_ID, PLONEGROUP_ORG)) self.assertRaises(LinkIntegrityNotificationException, view.render) storage = ILinkIntegrityInfo(view.REQUEST) breaches = storage.getIntegrityBreaches() self.assertIn(self.contacts[1], breaches) self.assertSetEqual(breaches[self.contacts[1]], set([self.portal['acontent2']]))
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)
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 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_2(self): """ We cannot remove an organization no more selected in settings and used in an object """ set_registry_organizations([self.contacts[0].UID() ]) # unselects the contact view = self.portal.restrictedTraverse( '{0}/{1}/department2/delete_confirmation'.format( DEFAULT_DIRECTORY_ID, PLONEGROUP_ORG)) self.assertRaises(LinkIntegrityNotificationException, view.render) storage = ILinkIntegrityInfo(view.REQUEST) breaches = storage.getIntegrityBreaches() self.assertIn(self.contacts[1], breaches) self.assertSetEqual(breaches[self.contacts[1]], set([self.portal['acontent2']]))
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 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)
def confirmedItems(self): info = ILinkIntegrityInfo(self.request) targets = info.getIntegrityBreaches().keys() return info.encodeConfirmedItems(additions=targets)
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})