def invalidate_ssoev_cache(): """ invalidate cache of SortedSelectedOrganizationsElephantVocabulary """ invalidate_cachekey_volatile_for( 'collective.contact.plonegroup.browser.settings.SortedSelectedOrganizationsElephantVocabulary' )
def test_OMSenderVocabulary(self): voc_inst = OMSenderVocabulary() self.assertEqual(len(voc_inst(self.omail)), 22) # get first part, as unique value, keeping order res = OrderedDict.fromkeys([ ' '.join(s.title.split()[:3]).strip(',') for s in voc_inst(self.omail) ]).keys() # res is sorted by firstname self.assertEqual(res, [ u'Monsieur Fred Agent', u'Monsieur Maxime DG', u'Monsieur Michel Chef', u'Monsieur Stef Agent' ]) api.portal.set_registry_record( 'imio.dms.mail.browser.settings.IImioDmsMailConfig.' 'omail_sender_firstname_sorting', False) invalidate_cachekey_volatile_for( 'imio.dms.mail.vocabularies.OMSenderVocabulary') res = OrderedDict.fromkeys([ ' '.join(s.title.split()[:3]).strip(',') for s in voc_inst(self.omail) ]).keys() # res is sorted by lastname self.assertEqual(res, [ u'Monsieur Fred Agent', u'Monsieur Stef Agent', u'Monsieur Michel Chef', u'Monsieur Maxime DG' ])
def test_volatile_cache_with_parameters(self): """Helper cache @volatile_cache_with_parameters""" self.portal.REQUEST.set('volatile_with_parameters_cached', 'a') self.assertEqual( 'a', volatile_with_parameters_cached(self.portal, 'a'), ) self.portal.REQUEST.set('volatile_with_parameters_cached', 'b') self.assertEqual( 'a', volatile_with_parameters_cached(self.portal, 'a'), ) self.assertEqual( 'b', volatile_with_parameters_cached(self.portal, 'b'), ) self.portal.REQUEST.set('volatile_with_parameters_cached', 'c') self.assertEqual( 'b', volatile_with_parameters_cached(self.portal, 'b'), ) # Test invalidation invalidate_cachekey_volatile_for( generate_key(volatile_with_parameters_cached), ) self.assertEqual( 'c', volatile_with_parameters_cached(self.portal, 'a'), ) self.assertEqual( 'c', volatile_with_parameters_cached(self.portal, 'b'), )
def test_list_wf_states(self): imail = sub_create(self.portal['incoming-mail'], 'dmsincomingmail', datetime.now(), 'my-id') self.assertEqual(list_wf_states(imail, 'unknown'), []) self.assertEqual( [s_id for s_id, s_tit in list_wf_states(imail, 'task')], [ 'created', 'to_assign', 'to_do', 'in_progress', 'realized', 'closed' ]) # We rename a state id states = imail.portal_workflow.task_workflow.states states.manage_renameObject('to_do', 'NEW') # use cache self.assertEqual( [s_id for s_id, s_tit in list_wf_states(imail, 'task')], [ 'created', 'to_assign', 'to_do', 'in_progress', 'realized', 'closed' ]) invalidate_cachekey_volatile_for( 'imio.dms.mail.utils.list_wf_states.task') # 'imio.dms.mail.utils.list_wf_states self.assertEqual( [s_id for s_id, s_tit in list_wf_states(imail, 'task')], [ 'created', 'to_assign', 'in_progress', 'realized', 'closed', 'NEW' ])
def onDashboardCollectionRemoved(obj, event): '''Called whenever a WF transition was triggered on a DashboardCollection.''' try: api.portal.get() except api.portal.CannotGetPortalError: return # when deleting site invalidate_cachekey_volatile_for('collective.eeafaceted.collectionwidget.cachedcollectionvocabulary')
def _doApplyItemSignatures(self): """ The method actually do the job, set the itemSignatures on self.context and following items if defined """ self._check_auth() # only apply if different from meeting item_signatures_def = item_signatures_default() if self.item_signatures != item_signatures_def: items_to_update = _itemsToUpdate( from_item_number=self.context.getItemNumber( relativeTo='meeting'), until_item_number=self.apply_until_item_number, meeting=self.context.getMeeting()) for itemToUpdate in items_to_update: itemToUpdate.setItemSignatures(self.item_signatures) first_item_number = items_to_update[0].getItemNumber( for_display=True) last_item_number = items_to_update[-1].getItemNumber( for_display=True) extras = 'item={0} from_item_number={1} until_item_number={2}'.format( repr(self.context), first_item_number, last_item_number) fplog('manage_item_signatures', extras=extras) # invalidate assembly async load on item invalidate_cachekey_volatile_for( 'Products.PloneMeeting.browser.async.AsyncLoadItemAssemblyAndSignaturesRawFields', get_again=True) api.portal.show_message(_("Item signatures have been updated."), request=self.request) self._finished = True
def contact_modified(obj, event): """ Update the sortable_title index """ # at site removal # if IObjectRemovedEvent.providedBy(event): # return if IPersonnelContact.providedBy(obj): invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.OMSenderVocabulary')
def test_list_wf_states(self): imail = createContentInContainer(self.portal['incoming-mail'], 'dmsincomingmail') self.assertEqual(list_wf_states(imail, 'unknown'), []) self.assertEqual(list_wf_states(imail, 'task'), ['created', 'to_assign', 'to_do', 'in_progress', 'realized', 'closed']) # We rename a state id states = imail.portal_workflow.task_workflow.states states.manage_renameObject('to_do', 'NEW') self.assertEqual(list_wf_states(imail, 'task'), ['created', 'to_assign', 'to_do', 'in_progress', 'realized', 'closed']) invalidate_cachekey_volatile_for('list_wf_states.task') self.assertEqual(list_wf_states(imail, 'task'), ['created', 'to_assign', 'in_progress', 'realized', 'closed', 'NEW'])
def _invalidateCachedVocabularies(self): """Clean cache for vocabularies using MeetingGroups.""" invalidate_cachekey_volatile_for( "Products.PloneMeeting.vocabularies.proposinggroupsvocabulary") invalidate_cachekey_volatile_for( "Products.PloneMeeting.vocabularies.proposinggroupacronymsvocabulary" ) invalidate_cachekey_volatile_for( "Products.PloneMeeting.vocabularies.proposinggroupsforfacetedfiltervocabulary" ) invalidate_cachekey_volatile_for( "Products.PloneMeeting.vocabularies.groupsinchargevocabulary") invalidate_cachekey_volatile_for( "Products.PloneMeeting.vocabularies.askedadvicesvocabulary")
def plonegroup_contact_changed(organization, event): """ Manage an organization change """ # zope.lifecycleevent.ObjectRemovedEvent : delete # zope.lifecycleevent.ObjectModifiedEvent : edit, rename # is the container who's modified at creation ? # bypass if we are removing the Plone Site if IContainerModifiedEvent.providedBy(event) or \ event.object.portal_type == 'Plone Site': return # invalidate vocabularies caches invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.CreatingGroupVocabulary') invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.ActiveCreatingGroupVocabulary') invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.TreatingGroupsWithDeactivatedVocabulary') invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.TreatingGroupsForFacetedFilterVocabulary') # is the current organization a part of own organization organization_path = '/'.join(organization.getPhysicalPath()) if not organization_path.startswith(get_own_organization_path('unfound')): return portal = api.portal.getSite() pcat = portal.portal_catalog brains = pcat.unrestrictedSearchResults(portal_type='organization', path=organization_path) for brain in brains: obj = brain._unrestrictedGetObject() full_title = obj.get_full_title(separator=' - ', first_index=1) for base_folder in (portal['templates']['om'], portal.contacts['contact-lists-folder']): folder = base_folder.get(brain.UID) if folder and folder.title != full_title: folder.title = full_title folder.reindexObject(idxs=['Title', 'SearchableText', 'sortable_title']) modified(folder)
def user_related_modification(event): """ Manage user modification * ignored Products.PluggableAuthService.interfaces.events.IPrincipalCreatedEvent * ignored Products.PluggableAuthService.interfaces.events.IPrincipalDeletedEvent """ # we pass if the config change is not related to users if IConfigurationChangedEvent.providedBy(event) and not isinstance(event.context, UserDataConfiglet): return # we pass if the registry change is not related to plonegroup if (IRecordModifiedEvent.providedBy(event) and event.record.interfaceName and event.record.interface != IContactPlonegroupConfig): return invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.AssignedUsersVocabulary')
def test_get_cachekey_volatile(self): """Helper method that adds a volatile on the portal storing current date.""" method_name = 'My method' plone_utils = api.portal.get_tool('plone_utils') normalized_name = plone_utils.normalizeString(method_name) volatile_name = '_v_{0}'.format(normalized_name) self.assertIsNone(getattr(self.portal, volatile_name, None)) # calling the method will set the volatile on the portal date = get_cachekey_volatile(method_name) self.assertTrue(isinstance(date, datetime)) self.assertTrue(isinstance(getattr(self.portal, volatile_name), datetime)) # calling it again will still return same date self.assertEquals(date, get_cachekey_volatile(method_name)) # volatiles are not removed by tearDown, remove it now to avoid # test isolation issues with test test_invalidate_cachekey_volatile_for invalidate_cachekey_volatile_for(method_name)
def user_related_modification(event): """ Manage user modification * ignored Products.PluggableAuthService.interfaces.events.IPrincipalCreatedEvent * ignored Products.PluggableAuthService.interfaces.events.IPrincipalDeletedEvent """ # we pass if the config change is not related to users if IConfigurationChangedEvent.providedBy(event) and not isinstance(event.context, UserDataConfiglet): return # we pass if the registry change is not related to plonegroup if (IRecordModifiedEvent.providedBy(event) and event.record.interfaceName and event.record.interface != IContactPlonegroupConfig): return invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.AssignedUsersWithDeactivatedVocabulary') invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.AssignedUsersForFacetedFilterVocabulary')
def test_invalidate_cachekey_volatile_for(self): """Helper method that will invalidate a given volatile.""" method_name = 'My method' plone_utils = api.portal.get_tool('plone_utils') normalized_name = plone_utils.normalizeString(method_name) volatile_name = normalized_name self.assertIsNone(getattr(self.portal, volatile_name, None)) # calling the method if volatile does not exist does not break invalidate_cachekey_volatile_for(method_name) # set it now first_date = get_cachekey_volatile(method_name) self.assertTrue(isinstance(first_date, datetime)) invalidate_cachekey_volatile_for(method_name) self.assertIsNone(getattr(self.portal, volatile_name, None)) # if get_cachekey_volatile is called and volatile does not exist, it is created with datetime.now() second_date = get_cachekey_volatile(method_name) self.assertTrue(first_date < second_date)
def test_invalidate_cachekey_volatile_for(self): """Helper method that will invalidate a given volatile.""" method_name = 'My method' plone_utils = api.portal.get_tool('plone_utils') normalized_name = plone_utils.normalizeString(method_name) volatile_name = '_v_{0}'.format(normalized_name) self.assertIsNone(getattr(self.portal, volatile_name, None)) # calling the method if volatile does not exist does not break invalidate_cachekey_volatile_for(method_name) # set it now first_date = get_cachekey_volatile(method_name) self.assertTrue(isinstance(first_date, datetime)) invalidate_cachekey_volatile_for(method_name) self.assertIsNone(getattr(self.portal, volatile_name, None)) # if get_cachekey_volatile is called and volatile does not exist, it is created with datetime.now() second_date = get_cachekey_volatile(method_name) self.assertTrue(first_date < second_date)
def test_get_cachekey_volatile(self): """Helper method that adds a volatile on the portal storing current date.""" method_name = 'My method' plone_utils = api.portal.get_tool('plone_utils') normalized_name = plone_utils.normalizeString(method_name) volatile_name = normalized_name self.assertIsNone(getattr(self.portal, volatile_name, None)) # calling the method will set the volatile on the portal date = get_cachekey_volatile(method_name) self.assertTrue(isinstance(date, datetime)) volatiles = getattr(self.portal, VOLATILE_ATTR, {}) self.assertTrue(isinstance(volatiles.get(volatile_name), datetime)) # calling it again will still return same date self.assertEquals(date, get_cachekey_volatile(method_name)) # volatiles are not removed by tearDown, remove it now to avoid # test isolation issues with test test_invalidate_cachekey_volatile_for invalidate_cachekey_volatile_for(method_name)
def _doApplyItemAssembly(self): """ The method actually do the job, set the itemAssembly on self.context and following items if defined """ self._check_auth() # only update if default proposed value was changed item_assembly_def = item_assembly_default() item_excused_def = item_excused_default() item_absents_def = item_absents_default() item_guests_def = item_guests_default() from_item_number = self.context.getItemNumber(relativeTo='meeting') until_item_number = self.apply_until_item_number items_to_update = _itemsToUpdate( from_item_number=from_item_number, until_item_number=until_item_number, meeting=self.meeting) for itemToUpdate in items_to_update: # only update if we changed default value if self.item_assembly != item_assembly_def: itemToUpdate.setItemAssembly(self.item_assembly) if self.item_excused != item_excused_def: itemToUpdate.setItemAssemblyExcused(self.item_excused) if self.item_absents != item_absents_def: itemToUpdate.setItemAssemblyAbsents(self.item_absents) if self.item_guests != item_guests_def: itemToUpdate.setItemAssemblyGuests(self.item_guests) notifyModifiedAndReindex(itemToUpdate) # invalidate assembly async load on item invalidate_cachekey_volatile_for( 'Products.PloneMeeting.browser.async.AsyncLoadItemAssemblyAndSignaturesRawFields', get_again=True) first_item_number = items_to_update[0].getItemNumber(for_display=True) last_item_number = items_to_update[-1].getItemNumber(for_display=True) extras = 'item={0} from_item_number={1} until_item_number={2}'.format( repr(self.context), first_item_number, last_item_number) fplog('manage_item_assembly', extras=extras) api.portal.show_message(_("Item assemblies have been updated."), request=self.request) self._finished = True
def mark_contact(contact, event): """ Set a marker interface on contact content. """ if IObjectRemovedEvent.providedBy(event): # at site removal if event.object.portal_type == 'Plone Site': return invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.OMSenderVocabulary') return if '/plonegroup-organization' in contact.absolute_url_path(): if not IPloneGroupContact.providedBy(contact): alsoProvides(contact, IPloneGroupContact) if INotPloneGroupContact.providedBy(contact): noLongerProvides(contact, INotPloneGroupContact) # don't check for IPersonnelContact because we can only add organization in this folder elif '/personnel-folder/' in contact.absolute_url_path(): if not IPersonnelContact.providedBy(contact): alsoProvides(contact, IPersonnelContact) if INotPloneGroupContact.providedBy(contact): noLongerProvides(contact, INotPloneGroupContact) # don't check for IPloneGroupContact because we can't add organization in this folder invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.OMSenderVocabulary') else: if not INotPloneGroupContact.providedBy(contact): alsoProvides(contact, INotPloneGroupContact) if IPloneGroupContact.providedBy(contact): noLongerProvides(contact, IPloneGroupContact) if IPersonnelContact.providedBy(contact): noLongerProvides(contact, IPersonnelContact) invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.OMSenderVocabulary') contact.reindexObject(idxs='object_provides')
def group_unassignment(event): """ manage the remove of a user in a plone group """ invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.AssignedUsersWithDeactivatedVocabulary') invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.AssignedUsersForFacetedFilterVocabulary') if event.group_id.endswith(CREATING_GROUP_SUFFIX): invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.ActiveCreatingGroupVocabulary') # we update dms config if 'n_plus_' in event.group_id: update_transitions_auc_config('dmsincomingmail', action='remove', group_id=event.group_id) # i_e ok update_transitions_levels_config(['dmsincomingmail', 'dmsoutgoingmail', 'task'], action='remove', # i_e ok group_id=event.group_id) # we manage the personnel-folder person and held position orgs = organizations_with_suffixes([event.group_id], ['encodeur'], group_as_str=True) if orgs: userid = event.principal portal = api.portal.get() pf = portal['contacts']['personnel-folder'] exist = portal.portal_catalog.unrestrictedSearchResults(mail_type=userid, portal_type='person') if userid in pf: pers = pf[userid] elif exist: pers = exist[0]._unrestrictedGetObject() else: return hps = [b._unrestrictedGetObject() for b in portal.portal_catalog.unrestrictedSearchResults(path='/'.join(pers.getPhysicalPath()), portal_type='held_position')] for hp in hps: if hp.get_organization().UID() == orgs[0] and api.content.get_state(hp) == 'active': api.content.transition(hp, 'deactivate')
def handleApply(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return # store every data on self for k, v in data.items(): setattr(self, k, v) self.apply_until_item_number = \ _itemNumber_to_storedItemNumber( data.get('apply_until_item_number') or u'0' ) self.meeting = self.context.getMeeting() self._doApply() # in any case, if attendee (un)set absent/excused/... invalidate itemvoters caching invalidate_cachekey_volatile_for( 'Products.PloneMeeting.vocabularies.itemvotersvocabulary', get_again=True) # invalidate attendees async load on meeting invalidate_cachekey_volatile_for( 'Products.PloneMeeting.browser.async.AsyncLoadMeetingAssemblyAndSignatures', get_again=True)
def group_assignment(event): """ manage the add of a user in a plone group """ invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.AssignedUsersWithDeactivatedVocabulary') invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.AssignedUsersForFacetedFilterVocabulary') if event.group_id.endswith(CREATING_GROUP_SUFFIX): invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.ActiveCreatingGroupVocabulary') # we update dms config if 'n_plus_' in event.group_id: update_transitions_auc_config('dmsincomingmail', action='add', group_id=event.group_id) # i_e ok update_transitions_levels_config(['dmsincomingmail', 'dmsoutgoingmail', 'task'], action='add', # i_e ok group_id=event.group_id) # we manage the 'lu' label for a new assignment # same functions as IncomingMailInCopyGroupUnreadCriterion userid = event.principal orgs = organizations_with_suffixes([event.group_id], IM_READER_SERVICE_FUNCTIONS, group_as_str=True) if orgs: days_back = 5 start = datetime.datetime(1973, 2, 12) end = datetime.datetime.now() - datetime.timedelta(days=days_back) catalog = api.portal.get_tool('portal_catalog') for brain in catalog(portal_type=['dmsincomingmail', 'dmsincoming_email'], recipient_groups=orgs, labels={'not': ['%s:lu' % userid]}, created={'query': (start, end), 'range': 'min:max'}): # if not brain.recipient_groups: # continue obj = brain.getObject() labeling = ILabeling(obj) user_ids = labeling.storage.setdefault('lu', PersistentList()) # _p_changed is managed user_ids.append(userid) # _p_changed is managed obj.reindexObject(idxs=['labels']) # we manage the personnel-folder person and held position orgs = organizations_with_suffixes([event.group_id], ['encodeur'], group_as_str=True) if orgs: user = api.user.get(userid) start = api.portal.get_registry_record('omail_fullname_used_form', IImioDmsMailConfig, default='firstname') firstname, lastname = separate_fullname(user, start=start) portal = api.portal.get() intids = getUtility(IIntIds) pf = portal['contacts']['personnel-folder'] # exists already exist = portal.portal_catalog.unrestrictedSearchResults(mail_type=userid, portal_type='person') if userid in pf: pers = pf[userid] elif exist: pers = exist[0]._unrestrictedGetObject() else: pers = api.content.create(container=pf, type='person', id=userid, userid=userid, lastname=lastname, firstname=firstname, use_parent_address=False) if api.content.get_state(pers) == 'deactivated': api.content.transition(pers, 'activate') hps = [b._unrestrictedGetObject() for b in portal.portal_catalog.unrestrictedSearchResults(path='/'.join(pers.getPhysicalPath()), portal_type='held_position')] hps_orgs = dict([(hp.get_organization(), hp) for hp in hps]) uid = orgs[0] org = uuidToObject(uid, unrestricted=True) if not org: return if uid in pers: hp = pers[uid] elif org in hps_orgs: hp = hps_orgs[org] else: hp = api.content.create(container=pers, id=uid, type='held_position', email=safe_unicode(user.getProperty('email').lower()), position=RelationValue(intids.getId(org)), use_parent_address=True) if api.content.get_state(hp) == 'deactivated': api.content.transition(hp, 'activate')
def remove_service_chief(self): # remove collection logger.info('Modifying workflows') for folder in (self.imf['mail-searches'], self.omf['mail-searches']): if 'searchfor_proposed_to_service_chief' in folder: api.content.delete( obj=folder['searchfor_proposed_to_service_chief']) # clean dms config for ptype in ('dmsincomingmail', 'dmsoutgoingmail', 'task'): # i_e ok config = get_dms_config(['review_levels', ptype]) if '_validateur' in config: del config['_validateur'] set_dms_config(keys=['review_levels', ptype], value=config) config = get_dms_config(['review_states', ptype]) if 'proposed_to_service_chief' in config: del config['proposed_to_service_chief'] set_dms_config(keys=['review_states', ptype], value=config) def remove_localrole_validateur(dic1): for state1 in dic1: if 'validateur' in dic1[state1]: del dic1[state1]['validateur'] # clean local roles for ptype in ('dmsincomingmail', 'dmsoutgoingmail'): # i_e ok fti = getUtility(IDexterityFTI, name=ptype) lr = getattr(fti, 'localroles') lrg = lr['static_config'] if 'proposed_to_service_chief' in lrg: del lrg['proposed_to_service_chief'] remove_localrole_validateur(lrg) lrg = lr['treating_groups'] if 'proposed_to_service_chief' in lrg: del lrg['proposed_to_service_chief'] remove_localrole_validateur(lrg) lrg = lr['recipient_groups'] if 'proposed_to_service_chief' in lrg: del lrg['proposed_to_service_chief'] remove_localrole_validateur(lrg) lr._p_changed = True # on task fti = getUtility(IDexterityFTI, name='task') lr = getattr(fti, 'localroles') lrg = lr['assigned_group'] if 'validateur' in lrg['to_do']: remove_localrole_validateur(lrg) lrg = lr['parents_assigned_groups'] if 'validateur' in lrg['to_do']: remove_localrole_validateur(lrg) lr._p_changed = True # update registry lst = api.portal.get_registry_record( 'imio.actionspanel.browser.registry.IImioActionsPanelConfig.transitions' ) for entry in ('dmsincomingmail.back_to_service_chief|', 'dmsoutgoingmail.back_to_service_chief|'): if entry not in lst: break lst.remove(entry) else: api.portal.set_registry_record( 'imio.actionspanel.browser.registry.IImioActionsPanelConfig.transitions', lst) # update remark states for attr in ('imail_remark_states', 'omail_remark_states'): lst = (api.portal.get_registry_record( 'imio.dms.mail.browser.settings.IImioDmsMailConfig.{}'.format( attr)) or []) if 'proposed_to_service_chief' in lst: lst.remove('proposed_to_service_chief') api.portal.set_registry_record( 'imio.dms.mail.browser.settings.IImioDmsMailConfig.{}'. format(attr), lst) # Manage workflows and wfadaptations functions = get_registry_functions() if 'validateur' not in [fct['fct_id'] for fct in functions]: return # apply the following only once def remove_adaptation_from_registry(name): record = api.portal.get_registry_record(RECORD_NAME) api.portal.set_registry_record( RECORD_NAME, [d for d in record if d['adaptation'] != name]) # reset workflows self.runProfileSteps('imio.dms.mail', steps=['workflow']) # self.portal.portal_workflow.updateRoleMappings() # done later # Apply workflow adaptations if necessary applied_wfa = [dic['adaptation'] for dic in get_applied_adaptations()] n_plus_1_params = { 'validation_level': 1, 'state_title': u'À valider par le chef de service', 'forward_transition_title': u'Proposer au chef de service', 'backward_transition_title': u'Renvoyer au chef de service', 'function_title': u'N+1' } task_adapt = True for wkf, acr in (('incomingmail_workflow', 'IM'), ('outgoingmail_workflow', 'OM')): if u'imio.dms.mail.wfadaptations.{}SkipProposeToServiceChief'.format( acr) in applied_wfa: remove_adaptation_from_registry( u'imio.dms.mail.wfadaptations.{}SkipProposeToServiceChief'. format(acr)) task_adapt = False if acr == 'OM': folder = self.omf['mail-searches'] if folder['to_validate'].enabled: folder['to_validate'].enabled = False folder['to_validate'].reindexObject() else: logger.info( 'Applying {}ServiceValidation wf adaptation'.format(acr)) sva = getattr(wfadaptations, '{}ServiceValidation'.format(acr))() sva.reapply = True adapt_is_applied = sva.patch_workflow(wkf, **n_plus_1_params) if adapt_is_applied: add_applied_adaptation( 'imio.dms.mail.wfadaptations.{}ServiceValidation'. format(acr), wkf, True, **n_plus_1_params) # update task_workflow update_task_workflow(self.portal) if task_adapt: tsva = TaskServiceValidation() adapt_is_applied = tsva.patch_workflow('task_workflow', **{}) if adapt_is_applied: add_applied_adaptation( 'imio.dms.mail.wfadaptations.TaskServiceValidation', 'task_workflow', False) else: # update collections folder = self.portal['tasks']['task-searches'] for cid in ('to_assign', 'to_close'): if folder[cid].enabled: folder[cid].enabled = False folder[cid].reindexObject() invalidate_cachekey_volatile_for( 'collective.eeafaceted.collectionwidget.cachedcollectionvocabulary' ) # replace EmergencyZoneAdaptation im_workflow = self.wtool['incomingmail_workflow'] if u'imio.dms.mail.wfadaptations.EmergencyZone' in applied_wfa: state = im_workflow.states['proposed_to_manager'] state.title = u'À valider par le CZ'.encode('utf8') for tr, tit in (('back_to_manager', u'Renvoyer au CZ'), ('propose_to_manager', u'Proposer au CZ')): transition = im_workflow.transitions[tr] transition.title = tit.encode('utf8') logger.info('Removing EmergencyZone wf adaptation') remove_adaptation_from_registry( u'imio.dms.mail.wfadaptations.EmergencyZone') # redo OMToPrintAdaptation if u'imio.dms.mail.wfadaptations.OMToPrint' in applied_wfa: logger.info('Applying OMToPrint wf adaptation') tpa = OMToPrintAdaptation() tpa.patch_workflow('outgoingmail_workflow') # redo IMPreManagerValidation if u'imio.dms.mail.wfadaptations.IMPreManagerValidation' in applied_wfa: logger.info('Applying IMPreManagerValidation wf adaptation') params = [ dic['parameters'] for dic in get_applied_adaptations() if dic['adaptation'] == u'imio.dms.mail.wfadaptations.IMPreManagerValidation' ][0] remove_adaptation_from_registry( u'imio.dms.mail.wfadaptations.IMPreManagerValidation') del params['collection_title'] pmva = IMPreManagerValidation() adapt_is_applied = pmva.patch_workflow('incomingmail_workflow', **params) if adapt_is_applied: add_applied_adaptation( 'imio.dms.mail.wfadaptations.IMPreManagerValidation', 'incoming_mail', False, **params) # update wf history to replace review_state and correct history config = { 'dmsincomingmail': { 'wf': 'incomingmail_workflow', # i_e ok 'st': { 'proposed_to_service_chief': 'proposed_to_n_plus_1' }, 'tr': { 'propose_to_service_chief': 'propose_to_n_plus_1', 'back_to_service_chief': 'back_to_n_plus_1' } }, 'dmsoutgoingmail': { 'wf': 'outgoingmail_workflow', 'st': { 'proposed_to_service_chief': 'proposed_to_n_plus_1' }, 'tr': { 'propose_to_service_chief': 'propose_to_n_plus_1', 'back_to_service_chief': 'back_to_n_plus_1' } } } for pt in config: logger.info('Updating history and indexes of {} type'.format(pt)) for i, brain in enumerate(self.catalog(portal_type=pt), 1): obj = brain.getObject() if i % 10000 == 0: logger.info('On brain {}'.format(i)) # update history wfh = [] wkf = self.wtool[config[pt]['wf']] for status in obj.workflow_history.get(config[pt]['wf']): # replace old state by new one if status['review_state'] in config[pt]['st']: status['review_state'] = config[pt]['st'][ status['review_state']] # replace old transition by new one if status['action'] in config[pt]['tr']: status['action'] = config[pt]['tr'][status['action']] wfh.append(status) obj.workflow_history[config[pt]['wf']] = tuple(wfh) # update permissions and roles wkf.updateRoleMappingsFor(obj) # update state_group (use dms_config), permissions, state obj.reindexObject(idxs=[ 'allowedRolesAndUsers', 'review_state', 'state_group' ]) for child in obj.objectValues(): child.reindexObject(idxs=['allowedRolesAndUsers']) # migrate plone groups # First unregister group deletion handlers globalSiteManager.unregisterHandler(pg_group_deleted, (IGroupDeletedEvent, )) globalSiteManager.unregisterHandler(group_deleted, (IGroupDeletedEvent, )) globalSiteManager.unregisterHandler(group_assignment, (IPrincipalAddedToGroupEvent, )) globalSiteManager.unregisterHandler( group_unassignment, (IPrincipalRemovedFromGroupEvent, )) # move users from _validateur to _n_plus_1 for group in api.group.get_groups(): if group.id.endswith('_validateur'): org = group.id.split('_')[0] np1group = api.group.get('{}_n_plus_1'.format(org)) if np1group: for user in api.user.get_users(group=group): api.group.add_user(group=np1group, user=user) api.group.remove_user(group=group, user=user) api.group.delete(group=group) # register again group deletion handlers globalSiteManager.registerHandler(pg_group_deleted, (IGroupDeletedEvent, )) globalSiteManager.registerHandler(group_deleted, (IGroupDeletedEvent, )) globalSiteManager.registerHandler(group_assignment, (IPrincipalAddedToGroupEvent, )) globalSiteManager.registerHandler(group_unassignment, (IPrincipalRemovedFromGroupEvent, )) # remove validateur function functions = get_registry_functions() if 'validateur' in [fct['fct_id'] for fct in functions]: set_registry_functions( [fct for fct in functions if fct['fct_id'] != 'validateur'])
def group_deleted(event): """ Raises exception if group cannot be deleted """ group = event.principal portal = api.portal.get() request = portal.REQUEST # is protected group if group in ('createurs_dossier', 'dir_general', 'encodeurs', 'expedition', 'lecteurs_globaux_cs', 'lecteurs_globaux_ce', 'Administrators', 'Reviewers', 'Site Administrators'): api.portal.show_message(message=_("You cannot delete the group '${group}'.", mapping={'group': group}), request=request, type='error') raise Redirect(request.get('ACTUAL_URL')) parts = group.split('_') if len(parts) == 1: return group_suffix = '_'.join(parts[1:]) # invalidate vocabularies caches invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.CreatingGroupVocabulary') invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.ActiveCreatingGroupVocabulary') def get_query(portal_type, field_p, idx_p, org, suffix): fti = getUtility(IDexterityFTI, name=portal_type) # try: # fti = getUtility(IDexterityFTI, name=portal_type) # except ComponentLookupError: # return {} config = getattr(fti, 'localroles', {}).get(field, None) if not config: return {} for st in config: if suffix in config[st]: return {idx: org} return {} # search in indexes following suffix use in type localroles for (idx, field, pts, domain) in ( ('assigned_group', 'assigned_group', ['task'], 'collective.eeafaceted.z3ctable'), ('treating_groups', 'treating_groups', # ['dmsincomingmail', 'dmsincoming_email', 'dmsoutgoingmail', 'dmsoutgoing_email'], here under too ['dmsincomingmail', 'dmsincoming_email', 'dmsoutgoingmail'], 'collective.eeafaceted.z3ctable'), ('recipient_groups', 'recipient_groups', ['dmsincomingmail', 'dmsincoming_email', 'dmsoutgoingmail'], 'collective.eeafaceted.z3ctable'), ('assigned_group', 'creating_group', ['dmsincomingmail', 'dmsincoming_email', 'dmsoutgoingmail'], 'collective.eeafaceted.z3ctable')): for pt in pts: query = get_query(pt, field, idx, parts[0], group_suffix) if not query: continue query.update({'portal_type': pt}) brains = portal.portal_catalog.unrestrictedSearchResults(**query) if brains: api.portal.show_message(message=_("You cannot delete the group '${group}', used in '${idx}' index.", mapping={'group': group, 'idx': translate(idx, domain=domain, context=request)}), request=request, type='error') api.portal.show_message(message=_("Linked objects: ${list}", mapping={'list': ', '.join(['<a href="%s" ' 'target="_blank">%s</a>' % (b.getURL(), safe_unicode(b.Title)) for b in brains])}), request=request, type='error') raise Redirect(request.get('ACTUAL_URL')) # we update dms config if 'n_plus_' in group: update_transitions_auc_config('dmsincomingmail', action='delete', group_id=group) # i_e ok update_transitions_levels_config(['dmsincomingmail', 'dmsoutgoingmail', 'task'], action='delete', # i_e ok group_id=group)
def contact_plonegroup_change(event): """Event handler when contact.plonegroup records are modified. * update workflow dms config (new groups). * invalidate vocabulary caches. * set localroles on contacts for _encodeur groups. * add a directory by organization in templates/om, templates/oem and contacts/contact-lists-folder. * set local roles on contacts, incoming-mail for group_encoder. """ if (IRecordModifiedEvent.providedBy(event) and event.record.interfaceName and event.record.interface == IContactPlonegroupConfig): registry = getUtility(IRegistry) s_orgs = get_registry_organizations() s_fcts = get_registry_functions() if not s_fcts or not s_orgs: return # we update dms config update_transitions_auc_config('dmsincomingmail') # i_e ok update_transitions_levels_config(['dmsincomingmail', 'dmsoutgoingmail', 'task']) # i_e ok # invalidate vocabularies caches invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.CreatingGroupVocabulary') invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.ActiveCreatingGroupVocabulary') invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.TreatingGroupsWithDeactivatedVocabulary') invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.TreatingGroupsForFacetedFilterVocabulary') portal = api.portal.get() # contributor on a contact can edit too for folder in (portal['outgoing-mail'], portal['contacts'], portal['contacts']['contact-lists-folder']['common']): dic = folder.__ac_local_roles__ for principal in dic.keys(): if principal.endswith('_encodeur'): del dic[principal] for uid in s_orgs: dic["%s_encodeur" % uid] = ['Contributor'] folder._p_changed = True # we add a directory by organization in templates/om om_folder = portal.templates.om oem_folder = portal.templates.oem base_model = om_folder.get('main', None) cl_folder = portal.contacts['contact-lists-folder'] for uid in s_orgs: obj = uuidToObject(uid, unrestricted=True) full_title = obj.get_full_title(separator=' - ', first_index=1) if uid not in om_folder: folder = api.content.create(container=om_folder, type='Folder', id=uid, title=full_title) # alsoProvides(folder, IActionsPanelFolderOnlyAdd) # made now in subscriber # alsoProvides(folder, INextPrevNotNavigable) roles = ['Reader'] if registry['imio.dms.mail.browser.settings.IImioDmsMailConfig.org_templates_encoder_can_edit']: roles += ['Contributor', 'Editor'] api.group.grant_roles(groupname='%s_encodeur' % uid, roles=roles, obj=folder) folder.reindexObjectSecurity() if base_model and base_model.has_been_modified(): logger.info("Copying %s in %s" % (base_model, '/'.join(folder.getPhysicalPath()))) api.content.copy(source=base_model, target=folder) if uid not in oem_folder: folder = api.content.create(container=oem_folder, type='Folder', id=uid, title=full_title) roles = ['Reader'] if registry['imio.dms.mail.browser.settings.IImioDmsMailConfig.org_email_templates_encoder_can_edit']: roles += ['Contributor', 'Editor'] api.group.grant_roles(groupname='%s_encodeur' % uid, roles=roles, obj=folder) folder.reindexObjectSecurity() # if base_model and base_model.has_been_modified(): # logger.info("Copying %s in %s" % (base_model, '/'.join(folder.getPhysicalPath()))) # api.content.copy(source=base_model, target=folder) if uid not in cl_folder: folder = api.content.create(container=cl_folder, type='Folder', id=uid, title=full_title) folder.setLayout('folder_tabular_view') roles = ['Reader', 'Contributor', 'Editor'] api.group.grant_roles(groupname='%s_encodeur' % uid, roles=roles, obj=folder) folder.reindexObjectSecurity() # we manage local roles to give needed permissions related to group_encoder options_config = {portal['incoming-mail']: ['imail_group_encoder'], portal['outgoing-mail']: ['omail_group_encoder'], portal['contacts']: ['imail_group_encoder', 'omail_group_encoder', 'contact_group_encoder'], portal['contacts']['contact-lists-folder']['common']: ['imail_group_encoder', 'omail_group_encoder', 'contact_group_encoder']} ge_config = {opt: api.portal.get_registry_record('imio.dms.mail.browser.settings.IImioDmsMailConfig.{}'.format( opt), default=False) for opt in ('imail_group_encoder', 'omail_group_encoder', 'contact_group_encoder')} group_encoder_config = [dic for dic in s_fcts if dic['fct_id'] == CREATING_GROUP_SUFFIX] # noqa F812 if group_encoder_config: orgs = group_encoder_config[0]['fct_orgs'] for folder in options_config: if any([ge_config[opt] for opt in options_config[folder]]): dic = folder.__ac_local_roles__ for principal in dic.keys(): if principal.endswith(CREATING_GROUP_SUFFIX): del dic[principal] for uid in orgs: dic["{}_{}".format(uid, CREATING_GROUP_SUFFIX)] = ['Contributor'] folder._p_changed = True
def test_pm_GetCategoriesCaching(self): '''Test MeetingConfig.getCategories caching.''' times = 1000 self.meetingConfig.setUseGroupsAsCategories(False) # first test with 10 groups without usingGroups self._setupForMeetingCategories(10, withUsingGroups=False) pm_logger.info('getCategories called %d times with %d activated groups, without usingGroups.' % (times, 10)) pm_logger.info('Not cached..') self._getCategoriesOnMeetingConfig(times=times) # second time, cached pm_logger.info('Cached.') self._getCategoriesOnMeetingConfig(times=times) # remove cache invalidate_cachekey_volatile_for("Products.PloneMeeting.vocabularies.categoriesvocabulary") # first test with 10 groups with usingGroups self._setupForMeetingCategories(10, withUsingGroups=True) pm_logger.info('getCategories called %d times with %d activated groups, with usingGroups.' % (times, 10)) pm_logger.info('No cached.') self._getCategoriesOnMeetingConfig(times=times) # second time, cached pm_logger.info('Cached.') self._getCategoriesOnMeetingConfig(times=times) # remove cache invalidate_cachekey_volatile_for("Products.PloneMeeting.vocabularies.categoriesvocabulary") # test with 100 categories without usingGroups self._setupForMeetingCategories(100, withUsingGroups=False) pm_logger.info('getCategories called %d times with %d activated groups, without usingGroups.' % (times, 100)) pm_logger.info('No cached.') self._getCategoriesOnMeetingConfig(times=times) # second time, cached pm_logger.info('Cached.') self._getCategoriesOnMeetingConfig(times=times) # remove cache invalidate_cachekey_volatile_for("Products.PloneMeeting.vocabularies.categoriesvocabulary") # test with 100 categories with usingGroups self._setupForMeetingCategories(100, withUsingGroups=True) pm_logger.info('getCategories called %d times with %d activated groups, with usingGroups.' % (times, 100)) pm_logger.info('No cached.') self._getCategoriesOnMeetingConfig(times=times) # second time, cached pm_logger.info('Cached.') self._getCategoriesOnMeetingConfig(times=times) # remove cache invalidate_cachekey_volatile_for("Products.PloneMeeting.vocabularies.categoriesvocabulary") # test with 250 categories without usingGroups self._setupForMeetingCategories(250, withUsingGroups=False) pm_logger.info('getCategories called %d times with %d activated groups, without usingGroups.' % (times, 250)) pm_logger.info('No cached.') self._getCategoriesOnMeetingConfig(times=times) # second time, cached pm_logger.info('Cached.') self._getCategoriesOnMeetingConfig(times=times) # remove cache invalidate_cachekey_volatile_for("Products.PloneMeeting.vocabularies.categoriesvocabulary") # test with 250 categories with usingGroups self._setupForMeetingCategories(250, withUsingGroups=True) pm_logger.info('getCategories called %d times with %d activated groups, with usingGroups.' % (times, 250)) pm_logger.info('No cached.') self._getCategoriesOnMeetingConfig(times=1000) # second time, cached pm_logger.info('Cached.') self._getCategoriesOnMeetingConfig(times=1000) # remove cache invalidate_cachekey_volatile_for("Products.PloneMeeting.vocabularies.categoriesvocabulary")
def imiodmsmail_settings_changed(event): """ Manage a record change """ if (IRecordModifiedEvent.providedBy(event) and event.record.interfaceName and event.record.interface != IImioDmsMailConfig): return if event.record.fieldName == 'mail_types': invalidate_cachekey_volatile_for( 'imio.dms.mail.vocabularies.IMMailTypesVocabulary') invalidate_cachekey_volatile_for( 'imio.dms.mail.vocabularies.IMActiveMailTypesVocabulary') if event.record.fieldName == 'omail_types': invalidate_cachekey_volatile_for( 'imio.dms.mail.vocabularies.OMMailTypesVocabulary') invalidate_cachekey_volatile_for( 'imio.dms.mail.vocabularies.OMActiveMailTypesVocabulary') if event.record.fieldName == 'assigned_user_check': update_transitions_auc_config('dmsincomingmail') # i_e ok n_plus_x = 'imio.dms.mail.wfadaptations.IMServiceValidation' in \ [adapt['adaptation'] for adapt in get_applied_adaptations()] snoi = False if event.newValue == u'no_check' or not n_plus_x: snoi = True portal = api.portal.get() folder = portal['incoming-mail']['mail-searches'] if folder['to_treat_in_my_group'].showNumberOfItems != snoi: folder['to_treat_in_my_group'].showNumberOfItems = snoi # noqa folder['to_treat_in_my_group'].reindexObject() if event.record.fieldName in ('org_templates_encoder_can_edit', 'org_email_templates_encoder_can_edit'): folder_id = ('email' in event.record.fieldName) and 'oem' or 'om' portal = api.portal.get() main_folder = portal.templates[folder_id] s_orgs = get_registry_organizations() roles = ['Reader'] all_roles = ['Reader', 'Contributor', 'Editor'] if api.portal.get_registry_record(event.record.__name__): roles = list(all_roles) for uid in s_orgs: if uid not in main_folder: continue folder = main_folder[uid] groupname = '{}_encodeur'.format(uid) api.group.revoke_roles(groupname=groupname, roles=all_roles, obj=folder) api.group.grant_roles(groupname=groupname, roles=roles, obj=folder) if event.record.fieldName == 'imail_group_encoder': if api.portal.get_registry_record( 'imio.dms.mail.browser.settings.IImioDmsMailConfig.imail_group_encoder' ): configure_group_encoder(['dmsincomingmail', 'dmsincoming_email']) if event.record.fieldName == 'omail_group_encoder': if api.portal.get_registry_record( 'imio.dms.mail.browser.settings.IImioDmsMailConfig.omail_group_encoder' ): # configure_group_encoder(['dmsoutgoingmail', 'dmsoutgoing_email']) configure_group_encoder(['dmsoutgoingmail']) if event.record.fieldName == 'contact_group_encoder': if api.portal.get_registry_record( 'imio.dms.mail.browser.settings.IImioDmsMailConfig.contact_group_encoder' ): configure_group_encoder( ['organization', 'person', 'held_position', 'contact_list'], contacts_part=True) # set permission on contacts directory portal = api.portal.get() portal['contacts'].manage_permission( 'imio.dms.mail: Write mail base fields', ('Manager', 'Site Administrator', 'Contributor'), acquire=1) if event.record.fieldName == 'groups_hidden_in_dashboard_filter': invalidate_cachekey_volatile_for( 'imio.dms.mail.vocabularies.TreatingGroupsForFacetedFilterVocabulary' ) if event.record.fieldName == 'users_hidden_in_dashboard_filter': invalidate_cachekey_volatile_for( 'imio.dms.mail.vocabularies.AssignedUsersForFacetedFilterVocabulary' ) if event.record.__name__ == 'imio.dms.mail.imail_folder_period' and event.newValue is not None: portal = api.portal.get() setattr(portal[MAIN_FOLDERS['dmsincomingmail']], 'folder_period', event.newValue) if event.record.__name__ == 'imio.dms.mail.omail_folder_period' and event.newValue is not None: portal = api.portal.get() setattr(portal[MAIN_FOLDERS['dmsoutgoingmail']], 'folder_period', event.newValue)
def onDashboardCollectionModified(obj, event): '''Called whenever a DashboardCollection is modified.''' invalidate_cachekey_volatile_for('collective.eeafaceted.collectionwidget.cachedcollectionvocabulary')
def manageIImioDmsMailConfigChange(event): """ Manage a record change """ if (IRecordModifiedEvent.providedBy(event) and event.record.interfaceName and event.record.interface == IImioDmsMailConfig and event.record.fieldName == 'mail_types'): invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.IMMailTypesVocabulary') invalidate_cachekey_volatile_for('imio.dms.mail.vocabularies.IMActiveMailTypesVocabulary')
def group_assignment(event): """ manage the add of a user in a plone group """ invalidate_cachekey_volatile_for( 'imio.project.pst.vocabularies.ActionEditorsVocabulary')
def _invalidateCachedMethods(self): """Clean cache for vocabularies using MeetingCategories.""" invalidate_cachekey_volatile_for( "Products.PloneMeeting.MeetingConfig.getCategoriesIds") invalidate_cachekey_volatile_for( "Products.PloneMeeting.vocabularies.groupsinchargevocabulary")