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 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 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_update_transitions_auc_config(self): api.portal.set_registry_record(AUC_RECORD, u'no_check') # no check config = get_dms_config(['transitions_auc', 'dmsincomingmail']) self.assertSetEqual(set(config.keys()), {'close', 'propose_to_agent'}) self.assertTrue(all( config['propose_to_agent'].values())) # can always do transition self.assertTrue(all( config['close'].values())) # can always do transition # n_plus_1 api.portal.set_registry_record(AUC_RECORD, u'n_plus_1') # only one transition config = get_dms_config(['transitions_auc', 'dmsincomingmail']) self.assertSetEqual(set(config.keys()), {'close', 'propose_to_agent'}) self.assertTrue(all(config['propose_to_agent'].values())) self.assertTrue(all(config['close'].values())) # we simulate the adding of a level without user org1, org2 = get_registry_organizations()[0:2] api.group.create('{}_n_plus_1'.format(org1), 'N+1') set_dms_config(['wf_from_to', 'dmsincomingmail', 'n_plus', 'to'], [('closed', 'close'), ('proposed_to_agent', 'propose_to_agent'), ('proposed_to_n_plus_1', 'propose_to_n_plus_1')]) update_transitions_auc_config('dmsincomingmail') config = get_dms_config(['transitions_auc', 'dmsincomingmail']) self.assertSetEqual( set(config.keys()), {'close', 'propose_to_n_plus_1', 'propose_to_agent'}) self.assertTrue(all(config['propose_to_n_plus_1'].values())) self.assertTrue(all(config['propose_to_agent'].values())) self.assertTrue(all(config['close'].values())) # we simulate the adding of a level and a user update_transitions_auc_config('dmsincomingmail', 'add', '{}_n_plus_1'.format(org1)) config = get_dms_config(['transitions_auc', 'dmsincomingmail']) self.assertTrue(config['propose_to_n_plus_1'][org1]) self.assertFalse(config['propose_to_agent'] [org1]) # cannot do transition because user self.assertTrue(config['propose_to_agent'][org2]) # mandatory # reset config set_dms_config(['transitions_auc', 'dmsincomingmail'], value='dict') set_dms_config(['wf_from_to', 'dmsincomingmail', 'n_plus', 'to'], [('closed', 'close'), ('proposed_to_agent', 'propose_to_agent')]) api.portal.set_registry_record(AUC_RECORD, 'mandatory') config = get_dms_config(['transitions_auc', 'dmsincomingmail']) self.assertFalse(any( config['propose_to_agent'].values())) # all is False self.assertTrue(all(config['close'].values())) # we simulate the adding of a level without user set_dms_config(['wf_from_to', 'dmsincomingmail', 'n_plus', 'to'], [('closed', 'close'), ('proposed_to_agent', 'propose_to_agent'), ('proposed_to_n_plus_1', 'propose_to_n_plus_1')]) update_transitions_auc_config('dmsincomingmail') config = get_dms_config(['transitions_auc', 'dmsincomingmail']) self.assertSetEqual( set(config.keys()), {'close', 'propose_to_n_plus_1', 'propose_to_agent'}) self.assertFalse(any( config['propose_to_n_plus_1'].values())) # all is False self.assertFalse(any( config['propose_to_agent'].values())) # all is False self.assertTrue(all(config['close'].values())) # we simulate the adding of a level and a user update_transitions_auc_config('dmsincomingmail', 'add', '{}_n_plus_1'.format(org1)) config = get_dms_config(['transitions_auc', 'dmsincomingmail']) self.assertTrue(config['propose_to_n_plus_1'] [org1]) # can do transition because user self.assertFalse(config['propose_to_n_plus_1'][org2]) self.assertFalse(config['propose_to_agent'][org1]) self.assertFalse(config['propose_to_agent'][org2])
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)