def TreatingGroupsWithDeactivatedVocabulary__call__(self, context): active_orgs = get_organizations(only_selected=True) not_active_orgs = [ org for org in get_organizations(only_selected=False) if org not in active_orgs ] res_active = [] for active_org in active_orgs: org_uid = active_org.UID() res_active.append( SimpleTerm( org_uid, org_uid, safe_unicode(active_org.get_full_title(first_index=1)))) res = humansorted(res_active, key=attrgetter('title')) res_not_active = [] for not_active_org in not_active_orgs: org_uid = not_active_org.UID() res_not_active.append( SimpleTerm( org_uid, org_uid, _tr('${element_title} (Inactive)', mapping={ 'element_title': safe_unicode( not_active_org.get_full_title(first_index=1)) }))) res = res + humansorted(res_not_active, key=attrgetter('title')) return SimpleVocabulary(res)
def validate(self, value): selected_org_uids = get_organizations(only_selected=True, the_objects=False) removed_orgs_uids = set(selected_org_uids).difference(value) # check that removed orgs are not used as groups_in_charge of an organization orgs = get_organizations(only_selected=False, the_objects=True) for org in orgs: if removed_orgs_uids.intersection(org.groups_in_charge): msgid = "can_not_unselect_plone_group_org" msg = _(msgid, mapping={'org_url': org.absolute_url()}) raise Invalid(msg)
def test_get_organizations_follows_selected_organizations_order(self): self.assertEqual(get_organizations(only_selected=True), [self.dep1]) select_organization(self.dep2.UID()) self.assertEqual(get_organizations(only_selected=True, caching=False), [self.dep1, self.dep2]) select_organization(self.dep1.UID(), remove=True) select_organization(self.dep2.UID(), remove=True) select_organization(self.dep2.UID()) select_organization(self.dep1.UID()) self.assertEqual(get_organizations(only_selected=True, caching=False), [self.dep2, self.dep1])
def _setupForOrgs(self, number_of_orgs): self.changeUser('admin') cfg = self.meetingConfig cfg2 = self.meetingConfig2 # remove existing groups and add our own # make what necessary for groups to be removable... cfg.setOrderedGroupsInCharge(()) cfg.setSelectableCopyGroups(()) cfg.setSelectableAdvisers(()) cfg2.setOrderedGroupsInCharge(()) cfg2.setSelectableCopyGroups(()) cfg2.setSelectableAdvisers(()) orgs = get_organizations(only_selected=True) for org in orgs: self._select_organization(org.UID(), remove=True) for ploneGroup in get_plone_groups(org.UID()): for memberId in ploneGroup.getGroupMemberIds(): ploneGroup.removeMember(memberId) # remove items defined in the tool self._removeConfigObjectsFor(cfg, folders=['recurringitems', 'itemtemplates', 'categories']) self._removeConfigObjectsFor(cfg2, folders=['recurringitems', 'itemtemplates', 'categories']) # remove groups self._removeOrganizations() # create groups for i in range(number_of_orgs): org = self.create('organization', id=i, title='Org %d' % i) self._select_organization(org.UID())
def test_get_organizations_kept_org_uids(self): self.assertEqual(get_organizations(), [self.dep1]) self.assertEqual( get_organizations(kept_org_uids=['some_unexisting_uid']), []) self.assertEqual(get_organizations(kept_org_uids=[self.dep1.UID()]), [self.dep1]) self.assertEqual( get_organizations( kept_org_uids=['some_unexisting_uid', self.dep1.UID()]), [self.dep1]) # make sure order is preserved self.assertEqual( get_organizations(only_selected=False, kept_org_uids=[self.dep2.UID(), self.dep1.UID()]), [self.dep2, self.dep1])
def _turn_ids_into_uids(self, data): org_uids = get_organizations(only_selected=False, the_objects=False) def _get_org_uid(field_name, field_value): """Get org UID as given field_value may be an UID or an id.""" if field_value in org_uids: return field_value else: org_uid = org_id_to_uid(field_value, raise_on_error=False) if org_uid is None: raise BadRequest(ORG_FIELD_VALUE_ERROR % (field_value, field_name)) return org_uid for field_name in self._turn_ids_into_uids_fieldnames: field_value = data.get(field_name) if field_value: if hasattr(field_value, "__iter__"): data[field_name] = [] for v in field_value: data[field_name].append(_get_org_uid(field_name, v)) else: data[field_name] = _get_org_uid(field_name, field_value) return data
def get_order(self, associated_org_uids=[], cfg=None): '''Returns organization position among every selected organizations. If p_associated_org_uids is given, returns the order of the lowest org position. In this case, p_cfg must be given.''' def _get_index(orgs, org): """Return position of org among orgs, return 0 if org not found (not selected), it it like if it was using the first organization.""" try: # +1 to index as index 0 is for no more selected organizations index = orgs.index(org) + 1 except ValueError: index = 0 return index org_uids = get_organizations(only_selected=True, the_objects=False) i = _get_index(org_uids, self.UID()) # if we received associated_org_uids we must consider associated group # that has the lowest position if associated_org_uids: # if we have MeetingConfig.orderedAssociatedOrganizations, we use it # either we use organizations selected in plonegroup org_uids = cfg.getOrderedAssociatedOrganizations() or org_uids # orgs are sorted so, the first we find, we return it for org_uid in org_uids: if org_uid in associated_org_uids: # we found the associated org with lowest position, now check # that the lowest position of this associated group is lower or not # than the position of the proposing group associated_org_index = _get_index(org_uids, org_uid) if associated_org_index < i: i = associated_org_index break return i
def getPoliceGroups(self): orgs = get_organizations() res = [] for org in orgs: if org.getId().startswith(POLICE_GROUP_PREFIX): res.append(org.getId()) return res
def listGrpBudgetInfosAdviser(self): """Returns a list of groups that can be selected on an item to modify budgetInfos field. acronym group start with DGF""" res = [] res.append(('', self.utranslate('make_a_choice', domain='PloneMeeting'))) orgs = get_organizations(not_empty_suffix='budgetimpactreviewers') for group in orgs: res.append((group.id, group.getProperty('title'))) return DisplayList(tuple(res))
def getDptForItem(selg, groupid): # return department res = '' groups = get_organizations() for group in groups: acronym = group.get_acronym() if acronym.find('-') < 0: res = group.id if group.id == groupid: break return res
def _migrateItemsWorkflowHistory(self): """Migrate items workflow_history and remap states.""" # as state "proposed_to_finance" changed to "proposed_to_finance_waiting_advices", # we must update various places # organizations old_finance_value = 'meeting-config-college__state__proposed_to_finance' new_finance_value = 'meeting-config-college__state__proposed_to_finance_waiting_advices' for org in get_organizations(): for field_name in ('item_advice_states', 'item_advice_edit_states', 'item_advice_view_states'): value = getattr(org, field_name) or [] if old_finance_value in value: setattr( org, field_name, tuple( replace_in_list(value, old_finance_value, new_finance_value))) # MeetingConfigs old_finance_value = 'proposed_to_finance' new_finance_value = 'proposed_to_finance_waiting_advices' for cfg in self.tool.objectValues('MeetingConfig'): for field_name in ('itemAdviceStates', 'itemAdviceEditStates', 'itemAdviceViewStates'): value = getattr(cfg, field_name) or [] if old_finance_value in value: setattr( cfg, field_name, tuple( replace_in_list(value, old_finance_value, new_finance_value))) # update item workflow_history and MeetingConfig fields using states/transitions self.updateWFStatesAndTransitions( query={ 'portal_type': ('MeetingItemCollege', 'MeetingItemBourgmestre') }, review_state_mappings={ # meeting-config-college 'proposed_to_finance': 'proposed_to_finance_waiting_advices' }, transition_mappings={ # meeting-config-college 'proposeToFinance': 'wait_advices_from_proposed_to_director', 'askAdvicesByInternalReviewer': 'wait_advices_from_proposed_to_internal_reviewer', 'askAdvicesByItemCreator': 'wait_advices_from_itemcreated', # meeting-config-bourgmestre 'askAdvicesByDirector': 'wait_advices_from_proposed_to_director', }, # will be done by next step in migration update_local_roles=False)
def ActiveCreatingGroupVocabulary__call__(self, context): terms = [] factory = getUtility( IVocabularyFactory, 'collective.contact.plonegroup.organization_services') vocab = factory(context) # we get all orgs where there are plone groups with the creating group suffix and with users to_keep = set( get_organizations(not_empty_suffix=CREATING_GROUP_SUFFIX, only_selected=False, the_objects=False, caching=False)) to_keep |= set( get_organizations(not_empty_suffix=CONTACTS_PART_SUFFIX, only_selected=False, the_objects=False, caching=False)) for term in vocab: if term.value in to_keep: terms.append(term) return SimpleVocabulary(terms)
def getDptPos(self, groupid): # return department position in active groups list res = '' groups = get_organizations() cpt_dpt = 0 for group in groups: acronym = group.get_acronym() if acronym.find('-') < 0: cpt_dpt = cpt_dpt + 1 if group.id == groupid: break res = cpt_dpt return res
def test_get_organizations(self): # only_selected self.assertEqual(get_organizations(only_selected=True), [self.dep1]) self.assertEqual(get_organizations(only_selected=False), [self.dep1, self.dep2]) # the_objects self.assertEqual(get_organizations(the_objects=True), [self.dep1]) self.assertEqual(get_organizations(the_objects=False), [self.uid]) # not_empty_suffix self.assertEqual(get_organizations(not_empty_suffix=None), [self.dep1]) self.assertEqual(get_organizations(not_empty_suffix=u'director'), [self.dep1]) self.assertEqual(get_organizations(not_empty_suffix=u'observer'), [])
def set_creating_group(self, types='', uid='', change='', force=''): """Set creating_group for existing objects.""" if not check_zope_admin(): return "You must be a zope manager to run this script" if not uid or not types: return 'You have to pass types (comma separated) and uid parameters' out = [] ptypes = [typ.strip() for typ in types.split(',')] # TODO check if each ptype exists # TODO check if creating_group is in schema uids = get_organizations(not_empty_suffix=CREATING_GROUP_SUFFIX, only_selected=False, the_objects=False, caching=False) uids += get_organizations(not_empty_suffix=CONTACTS_PART_SUFFIX, only_selected=False, the_objects=False, caching=False) uid = safe_unicode(uid) if uid not in uids: return "You cannot set this uid '{}' not in configured uids '{}'".format( uid, uids) # search pc = self.portal_catalog brains = pc(portal_type=ptypes) out.append('Found {} objects of types {}'.format(len(brains), ptypes)) modified = 0 if change == '1': for brain in brains: obj = brain.getObject() if force == '1' or obj.creating_group is None: modified += 1 obj.creating_group = uid obj.reindexObject(['assigned_group']) out.append('Modified {} objects'.format(modified)) return '\n'.join(out)
def export_orgs(self): """ Export the existing organizations informations as a dictionnary """ member = api.user.get_current() if not member.has_role('Manager'): raise Unauthorized('You must be a Manager to access this script !') if not hasattr(self, 'portal_plonemeeting'): return "PloneMeeting must be installed to run this script !" data = {} for org in get_organizations(only_selected=False): data[org.getId()] = (org.Title(), org.Description(), org.get_acronym()) return data
def orderedOrgs(self): """Display organizations if one of the selected inserting methods relies on organizations. Returns a list of tuples, with organization title as first element and goupsInCharge organizations titles as second element.""" res = [] orgs_inserting_methods = [ method['insertingMethod'] for method in self.cfg.getInsertingMethodsOnAddItem() if 'organization' in self.inserting_methods_fields_mapping[ method['insertingMethod']] ] if orgs_inserting_methods: orgs = get_organizations(only_selected=True) res = [(org.Title(), ', '.join([ gic.Title() for gic in org.get_groups_in_charge(the_objects=True) ] or '')) for org in orgs] return res
def test_ws_showCategories(self): """ Test while getting configInfos with categories. """ self.changeUser('pmCreator1') req = getConfigInfosRequest() req._showCategories = True # Serialize the request so it can be easily tested responseHolder = getConfigInfosResponse() response = SOAPView(self.portal, req).getConfigInfosRequest(req, responseHolder) resp = deserialize(response) expected = """<ns1:getConfigInfosResponse xmlns:ns1="http://ws4pm.imio.be" """ \ """xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" """ \ """xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" """ \ """xmlns:ZSI="http://www.zolera.com/schemas/ZSI/" """ \ """xmlns:xsd="http://www.w3.org/2001/XMLSchema" """ \ """xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">""" # _configInfo for cfg in self.tool.getActiveConfigs(): expected += """ <configInfo xsi:type="ns1:ConfigInfo"> <UID>%s</UID> <id>%s</id> <title>%s</title> <description>%s</description>%s%s </configInfo>""" % (cfg.UID(), cfg.getId(), cfg.Title(), cfg.Description(), self._getItemPositiveDecidedStatesFromConfig(cfg), self._getResultCategoriesForConfig(cfg)) # _groupInfo for grp in get_organizations(): expected += """ <groupInfo xsi:type="ns1:GroupInfo"> <UID>%s</UID> <id>%s</id> <title>%s</title> <description>%s</description> </groupInfo>""" % (grp.UID(), grp.getId(), grp.Title(), grp.Description()) # footer. Empty description is represented like <description/> expected = expected.replace('<description></description>', '<description/>') \ + "\n</ns1:getConfigInfosResponse>\n" self.assertEquals(expected, resp) # the category 'subproducts' is only available to vendors self.assertFalse('<id>subproducts</id>' in resp)
def getServicePos(self, group, meeting=None, late=False): # return service position in active groups list incremented by item for department groupid = group.id cpt_srv = 0 groups = get_organizations() for gr in groups: acronym = gr.get_acronym() if acronym.find('-') >= 0: # only increment if no empty service and not current group if (gr.id != groupid) and (not self.getServiceIsEmpty( gr.id, meeting, late)): cpt_srv = cpt_srv + 1 else: # new department, reset numbering cpt_srv = 1 if gr.id == groupid: break dptid = self.getDptForItem(group.id) cpt_srv = cpt_srv + self.getCountDptItems(meeting, dptid, late) return cpt_srv
def set_default_in_charge_if_misssing_and_fix_certified_sign( default_in_charge_uid, remove_certified_signatures=[], remove_certified_signatures_ignore_pattern=None): cfg_groups = get_organizations(only_selected=False) for group in cfg_groups: if not group.groups_in_charge: group.groups_in_charge = [default_in_charge_uid] logger.info(u"Added default group in charge to {}".format( group.title)) if not remove_certified_signatures_ignore_pattern or not re.match( remove_certified_signatures_ignore_pattern, group.title): # the organisation members create items certified_signatures = [] for signature in group.certified_signatures: if signature.get( 'signature_number') not in remove_certified_signatures: certified_signatures.append(signature) group.certified_signatures = certified_signatures group.reindexObject()
def test_pm_PloneGroupSettingsOrganizationsValidator(self): """Can not unselected an organization if used as groups_in_charge of another organziations.""" self.changeUser('siteadmin') validator = PloneGroupSettingsOrganizationsValidator( self.portal, self.request, None, IContactPlonegroupConfig['organizations'], None) organizations = get_registry_organizations() self.assertIsNone(validator.validate(organizations)) # org can not be unselected if used in another org.groups_in_charge orgs = get_organizations() orgs[0].groups_in_charge = [orgs[1].UID()] with self.assertRaises(Invalid) as cm: validator.validate([organizations[0]]) validation_error_msg = _('can_not_unselect_plone_group_org', mapping={'item_url': orgs[0].absolute_url()}) self.assertEqual(cm.exception.message, validation_error_msg) # but other could be unselected self.assertIsNone(validator.validate([organizations[1]])) # remove groups_in_charge so org may be unselected orgs[0].groups_in_charge = [] self.assertIsNone(validator.validate([organizations[0]]))
def run(self): self.data = self.profileData if not self.data: return self.noDataMessage # Register classes again, after model adaptations have been performed # (see comment in __init__.py) registerClasses() # if we already have existing organizations, we do not add additional ones own_org = get_own_organization() alreadyHaveGroups = bool(own_org.objectValues()) savedMeetingConfigsToCloneTo = {} savedOrgsData = {} if not alreadyHaveGroups or self.data.forceAddUsersAndGroups: # 1) create organizations so we have org UIDS to initialize 'fct_orgs' orgs, active_orgs, savedOrgsData = self.addOrgs(self.data.orgs) # 2) create plonegroup functions (suffixes) to create Plone groups functions = get_registry_functions() function_ids = [function['fct_id'] for function in functions] # append new functions suffixes = MEETING_GROUP_SUFFIXES + EXTRA_GROUP_SUFFIXES for suffix in suffixes: if suffix['fct_id'] not in function_ids: copied_suffix = suffix.copy() copied_suffix['fct_title'] = translate( suffix['fct_title'], domain='PloneMeeting', context=self.request) # if org_path not found, do not fail but log, it is often the case in tests # in which we do not add additional organizations because it breaks some tests copied_suffix['fct_orgs'] = [] for org_path in suffix['fct_orgs']: try: fct_org = own_org.restrictedTraverse(org_path) except KeyError: logger.warning( "Could not find an organization with path {0} " "while setting 'fct_orgs' for {1}".format( org_path, suffix['fct_id'])) continue copied_suffix['fct_orgs'].append(fct_org.UID()) functions.append(copied_suffix) # 3) manage organizations, set every organizations so every Plone groups are created # then disable orgs that are not active invalidate_soev_cache() invalidate_ssoev_cache() already_active_orgs = get_registry_organizations() org_uids = [ org_uid for org_uid in get_organizations(only_selected=False, the_objects=False) if org_uid not in already_active_orgs ] set_registry_organizations(org_uids) set_registry_functions(functions) active_org_uids = [org.UID() for org in active_orgs] set_registry_organizations(already_active_orgs + active_org_uids) # 4) add users to Plone groups self.addUsers(self.data.orgs) # 5) now that organizations are created, we add persons and held_positions self.addPersonsAndHeldPositions(self.data.persons, source=self.profilePath) created_cfgs = [] for mConfig in self.data.meetingConfigs: # XXX we need to defer the management of the 'meetingConfigsToCloneTo' # defined on the mConfig after the creation of every mConfigs because # if we defined in mConfig1.meetingConfigsToCloneTo the mConfig2 id, # it will try to getattr this meetingConfig2 id that does not exist yet... # so save defined values, removed them from mConfig and manage that after savedMeetingConfigsToCloneTo[ mConfig.id] = mConfig.meetingConfigsToCloneTo mConfig.meetingConfigsToCloneTo = [] cfg = self.createMeetingConfig(mConfig, source=self.profilePath) if cfg: created_cfgs.append(cfg) self._finishConfigFor(cfg, data=mConfig) # manage other_mc_correspondences for created_cfg in created_cfgs: self._manageOtherMCCorrespondences(created_cfg) # now that every meetingConfigs have been created, we can manage the meetingConfigsToCloneTo # and orgs advice states related fields for mConfigId in savedMeetingConfigsToCloneTo: if not savedMeetingConfigsToCloneTo[mConfigId]: continue # initialize the attribute on the meetingConfig and call _updateCloneToOtherMCActions cfg = getattr(self.tool, mConfigId) # validate the MeetingConfig.meetingConfigsToCloneTo data that we are about to set # first replace cfg1 and cfg2 by corresponding cfg id adapted_cfgsToCloneTo = deepcopy( savedMeetingConfigsToCloneTo[mConfigId]) for cfgToCloneTo in adapted_cfgsToCloneTo: cfgToCloneTo['meeting_config'] = self.cfg_num_to_id( cfgToCloneTo['meeting_config']) error = cfg.validate_meetingConfigsToCloneTo(adapted_cfgsToCloneTo) if error: raise PloneMeetingError(MEETING_CONFIG_ERROR % (cfg.Title(), cfg.getId(), error)) cfg.setMeetingConfigsToCloneTo(adapted_cfgsToCloneTo) cfg._updateCloneToOtherMCActions() for org_uid, values in savedOrgsData.items(): org = uuidToObject(org_uid, unrestricted=True) # turn cfg1__state__itemcreated into meeting-config-id__state__itemcreated org.item_advice_states = self._correct_advice_states( values['item_advice_states']) org.item_advice_edit_states = self._correct_advice_states( values['item_advice_edit_states']) org.item_advice_view_states = self._correct_advice_states( values['item_advice_view_states']) org.groups_in_charge = [ org_id_to_uid(group_id) for group_id in values['groups_in_charge'] ] # finally, create the current user (admin) member area self.portal.portal_membership.createMemberArea() # at the end, add users outside PloneMeeting groups because # they could have to be added in groups created by the MeetingConfig if not alreadyHaveGroups: # adapt userDescr.ploneGroups to turn cfg_num into cfg_id self.addUsersOutsideGroups(self.data.usersOutsideGroups) # commit before continuing so elements like scales on annex types are correctly saved transaction.commit() return self.successMessage
def validate(self, value): # check that if a suffix is removed, it is not used in MeetingConfig or MeetingItems stored_suffixes = get_all_suffixes(only_enabled=True) # get removed suffixes... saved_suffixes = [func['fct_id'] for func in value] saved_enabled_suffixes = [ func['fct_id'] for func in value if func['enabled'] ] removed_suffixes = list( set(stored_suffixes) - set(saved_enabled_suffixes)) really_removed_suffixes = list( set(stored_suffixes) - set(saved_suffixes)) org_uids = get_organizations(only_selected=False, the_objects=False) removed_plonegroups = [ get_plone_group_id(org_uid, removed_suffix) for org_uid in org_uids for removed_suffix in removed_suffixes ] # ... and new defined fct_orgs as it will remove some suffixed groups stored_functions = get_registry_functions() old_functions = { dic['fct_id']: { 'fct_title': dic['fct_title'], 'fct_orgs': dic['fct_orgs'], 'enabled': dic['enabled'] } for dic in stored_functions } new_functions = { dic['fct_id']: { 'fct_title': dic['fct_title'], 'fct_orgs': dic['fct_orgs'], 'enabled': dic['enabled'] } for dic in value } for new_function, new_function_infos in new_functions.items(): if new_function_infos['fct_orgs'] and \ old_functions[new_function]['fct_orgs'] != new_function_infos['fct_orgs']: # check that Plone group is empty for not selected fct_orgs for org_uid in org_uids: if org_uid in new_function_infos['fct_orgs']: continue removed_plonegroups.append( get_plone_group_id(org_uid, new_function)) elif new_function_infos['enabled'] is False: # check that Plone groups are all empty for org_uid in org_uids: removed_plonegroups.append( get_plone_group_id(org_uid, new_function)) # check that plonegroups and suffixes not used in MeetingConfigs removed_plonegroups = set(removed_plonegroups) tool = api.portal.get_tool('portal_plonemeeting') # advisers advisers_removed_plonegroups = [ REAL_ORG_UID_PATTERN.format(removed_plonegroup_id.split('_')[0]) for removed_plonegroup_id in removed_plonegroups if removed_plonegroup_id.endswith('_advisers') ] for cfg in tool.objectValues('MeetingConfig'): msg = _("can_not_delete_plone_group_meetingconfig", mapping={'cfg_title': safe_unicode(cfg.Title())}) # copyGroups if removed_plonegroups.intersection(cfg.getSelectableCopyGroups()): raise Invalid(msg) # advisers (selectableAdvisers/selectableAdviserUsers) if set(advisers_removed_plonegroups).intersection(cfg.getSelectableAdvisers()) or \ set(advisers_removed_plonegroups).intersection(cfg.getSelectableAdviserUsers()): raise Invalid(msg) # suffixes, values are like 'suffix_proposing_group_level1reviewers' composed_values_attributes = [ 'itemAnnexConfidentialVisibleFor', 'adviceAnnexConfidentialVisibleFor', 'meetingAnnexConfidentialVisibleFor', 'itemInternalNotesEditableBy' ] for composed_values_attr in composed_values_attributes: values = cfg.getField(composed_values_attr).getAccessor(cfg)() values = [ v for v in values for r in removed_suffixes if r in v ] if values: raise Invalid(msg) # itemWFValidationLevels, may be disabled if validation level also disabled # but not removed item_enabled_val_suffixes = get_item_validation_wf_suffixes(cfg) if set(really_removed_suffixes).intersection( item_enabled_val_suffixes): raise Invalid(msg) all_item_val_suffixes = get_item_validation_wf_suffixes( cfg, only_enabled=False) if set(removed_suffixes).intersection(all_item_val_suffixes): raise Invalid(msg) # check that plone_group not used in MeetingItems # need to be performant or may kill the instance when several items exist if removed_plonegroups: catalog = api.portal.get_tool('portal_catalog') # copy_groups brains = catalog.unrestrictedSearchResults( meta_type="MeetingItem", getCopyGroups=tuple(removed_plonegroups)) if not brains: brains = catalog.unrestrictedSearchResults( meta_type="MeetingItem", indexAdvisers=tuple(advisers_removed_plonegroups)) for brain in brains: item = brain.getObject() if item.isDefinedInTool(): msgid = "can_not_delete_plone_group_config_meetingitem" else: msgid = "can_not_delete_plone_group_meetingitem" msg = _(msgid, mapping={'item_url': item.absolute_url()}) raise Invalid(msg)
def run(self): member = self.portal.portal_membership.getAuthenticatedMember() if not member.has_role("Manager"): raise ValueError("You must be a Manager to access this script !") # Load all csv into memory cfg_groups = get_organizations(only_selected=False) for group in cfg_groups: self.grp_id_mapping[group.UID()] = group logger.info("Load {0}".format(self.f_group_mapping)) with io.open(self.f_group_mapping, "r") as csvfile: reader = csv.reader(csvfile) for row in reader: grp_id = row[1].strip() if grp_id in self.grp_id_mapping: self.groups[ row[0].strip()] = self.grp_id_mapping[grp_id].UID() else: self.groups[row[0].strip()] = self.default_group meetings = {} logger.info("Load {0}".format(self.f_meetings)) with io.open(self.f_meetings, "r") as csvfile: reader = csv.reader(csvfile) for row in reader: if reader.line_num == 1: # skip header line continue # Because numbers are not numbers but unicode chars... external_id = int(row[0].strip()) csv_type = safe_unicode(row[6].strip()).lower() if 'col' in csv_type: portal_type = self.college_cfg.getMeetingTypeName() elif 'cons' in csv_type: portal_type = self.council_cfg.getMeetingTypeName() else: continue meeting = CSVMeeting(external_id=external_id, date=row[1].strip(), created_on=row[2].strip(), started_on=row[3].strip(), ended_on=row[4].strip(), assembly=safe_unicode(row[5].strip()), portal_type=portal_type, annexes_dir=self.meeting_annex_dir_path) self.add_meeting_to_dict(meetings, meeting) self.load_items(self.f_items, meetings) # insert All self.disable_recurring_items() logger.info("Inserting Objects") try: for csv_meeting in meetings.values(): if csv_meeting.portal_type == self.college_cfg.getMeetingTypeName( ): self.insert_and_close_meeting(self.college_member_folder, csv_meeting) elif csv_meeting.portal_type == self.council_cfg.getMeetingTypeName( ): self.insert_and_close_meeting(self.council_member_folder, csv_meeting) else: raise NotImplementedError( u"Not managed meeting type '{}' for meeting id {}". format(csv_meeting.type, meeting.external_id)) finally: tool = api.portal.get_tool('portal_plonemeeting') self.re_enable_recurring_items() tool.invalidateAllCache() return self.meeting_counter, self.item_counter, self.errors
def detectContactPlonegroupChange(event): """ Manage our record changes """ if IRecordModifiedEvent.providedBy( event): # and event.record.interface == IContactPlonegroupConfig: changes = False # this can be called before plonegroup is installed and registry contains relevant keys try: registry_orgs = get_registry_organizations() except InvalidParameterError: registry_orgs = [] if event.record.fieldName == 'organizations' and registry_orgs: old_set = set(event.oldValue) new_set = set(event.newValue) # we detect a new organization add_set = new_set.difference(old_set) for orga_uid in add_set: orga = uuidToObject(orga_uid) for fct_dic in get_registry_functions(): enabled = fct_dic['enabled'] if enabled is False: continue fct_orgs = fct_dic['fct_orgs'] if fct_orgs and orga_uid not in fct_orgs: continue if addOrModifyGroup(orga, fct_dic['fct_id'], fct_dic['fct_title']): changes = True # we detect a removed organization. We dont do anything on exsiting groups if old_set.difference(new_set): changes = True elif event.record.fieldName == 'functions' and registry_orgs: old_functions = { dic['fct_id']: { 'fct_title': dic['fct_title'], 'fct_orgs': dic['fct_orgs'], 'enabled': dic['enabled'] } for dic in event.oldValue } old_set = set(old_functions.keys()) new_functions = { dic['fct_id']: { 'fct_title': dic['fct_title'], 'fct_orgs': dic['fct_orgs'], 'enabled': dic['enabled'] } for dic in event.newValue } new_set = set(new_functions.keys()) # we detect a new function add_set = new_set.difference(old_set) for new_id in add_set: new_title = new_functions[new_id]['fct_title'] new_orgs = new_functions[new_id]['fct_orgs'] enabled = new_functions[new_id]['enabled'] for orga_uid in registry_orgs: if new_orgs and orga_uid not in new_orgs: continue if enabled is False: continue orga = uuidToObject(orga_uid) if addOrModifyGroup(orga, new_id, new_title): changes = True # we detect a removed function # We may remove Plone groups as we checked before that every are empty removed_set = old_set.difference(new_set) for removed_id in removed_set: for orga_uid in get_organizations(only_selected=False, the_objects=False): plone_group_id = get_plone_group_id(orga_uid, removed_id) plone_group = api.group.get(plone_group_id) if plone_group: api.group.delete(plone_group_id) changes = True # we detect existing functions for which 'fct_orgs' changed for new_id, new_function_infos in new_functions.items(): new_title = new_function_infos['fct_title'] new_orgs = new_function_infos['fct_orgs'] enabled = new_function_infos['enabled'] if not new_orgs and enabled is True: # we have to make sure Plone groups are created for every selected organizations for orga_uid in registry_orgs: orga = uuidToObject(orga_uid) if addOrModifyGroup(orga, new_id, new_title): changes = True else: # fct_orgs changed, we remove every linked Plone groups # except ones defined in new_orgs for orga_uid in get_organizations(only_selected=False, the_objects=False): if enabled is True and orga_uid in new_orgs: # make sure Plone group is created or updated if suffix title changed orga = uuidToObject(orga_uid) if addOrModifyGroup(orga, new_id, new_title): changes = True else: # make sure Plone group is deleted plone_group_id = get_plone_group_id( orga_uid, new_id) plone_group = api.group.get(plone_group_id) if plone_group: api.group.delete(plone_group_id) changes = True if changes: invalidate_sopgv_cache() invalidate_sov_cache() invalidate_soev_cache() invalidate_ssoev_cache()
def validateSettings(data): if not data.organizations: raise Invalid(_(u"You must choose at least one organization !")) if len(data.organizations) == 1 and data.organizations[0] is None: raise Invalid( _(u"You must correct the organization error first !")) if not data.functions: raise Invalid(_(u"You must define at least one function !")) # only able to delete a function (suffix) if every linked Plone groups are empty stored_suffixes = get_all_suffixes() saved_suffixes = [func['fct_id'] for func in data.functions] removed_suffixes = list(set(stored_suffixes) - set(saved_suffixes)) for removed_suffix in removed_suffixes: # check that every organizations including not selected # linked suffixed Plone group is empty for org_uid in get_organizations(only_selected=False, the_objects=False): plone_group_id = get_plone_group_id(org_uid, removed_suffix) plone_group = api.group.get(plone_group_id) if plone_group and plone_group.getMemberIds(): raise Invalid( _(u"can_not_remove_function_every_plone_groups_not_empty", mapping={ 'removed_function': removed_suffix, 'plone_group_id': plone_group_id })) # only able to select orgs for an existing function (suffix) if # every linked Plone groups of not selected orgs are empty stored_functions = get_registry_functions() old_functions = { dic['fct_id']: { 'fct_title': dic['fct_title'], 'fct_orgs': dic['fct_orgs'], 'enabled': dic['enabled'] } for dic in stored_functions } new_functions = { dic['fct_id']: { 'fct_title': dic['fct_title'], 'fct_orgs': dic['fct_orgs'], 'enabled': dic['enabled'] } for dic in data.functions } for new_function, new_function_infos in new_functions.items(): if new_function_infos['fct_orgs'] and \ old_functions[new_function]['fct_orgs'] != new_function_infos['fct_orgs']: # check that Plone group is empty for not selected fct_orgs for org_uid in get_organizations(only_selected=False, the_objects=False): if org_uid in new_function_infos['fct_orgs']: continue plone_group_id = get_plone_group_id(org_uid, new_function) plone_group = api.group.get(plone_group_id) # use getGroupMembers to ignore '<not found>' users if plone_group and plone_group.getGroupMembers(): raise Invalid( _(u"can_not_select_function_orgs_every_other_plone_groups_not_empty", mapping={ 'function': new_function, 'plone_group_id': plone_group_id })) elif new_function_infos['enabled'] is False: # check that Plone groups are all empty for org_uid in get_organizations(only_selected=False, the_objects=False): plone_group_id = get_plone_group_id(org_uid, new_function) plone_group = api.group.get(plone_group_id) # use getGroupMembers to ignore '<not found>' users if plone_group and plone_group.getGroupMembers(): raise Invalid( _(u"can_not_disable_suffix_plone_groups_not_empty", mapping={ 'disabled_function': new_function, 'plone_group_id': plone_group_id }))
def test_pm_AskedAdvicesVocabulary(self): '''Test the "Products.PloneMeeting.vocabularies.askedadvicesvocabulary" vocabulary, especially because it is cached.''' self.changeUser('siteadmin') cfg = self.meetingConfig customAdvisers = [{ 'row_id': 'unique_id_000', 'org': self.developers_uid, 'gives_auto_advice_on': '', 'for_item_created_from': '2012/01/01', 'delay': '2', 'delay_label': '' }, { 'row_id': 'unique_id_123', 'org': self.vendors_uid, 'gives_auto_advice_on': '', 'for_item_created_from': '2012/01/01', 'delay': '5', 'delay_label': '' }, { 'row_id': 'unique_id_456', 'org': self.vendors_uid, 'gives_auto_advice_on': '', 'for_item_created_from': '2012/01/01', 'delay': '10', 'delay_label': '' }, { 'row_id': 'unique_id_789', 'org': self.vendors_uid, 'gives_auto_advice_on': '', 'for_item_created_from': '2012/01/01', 'delay': '20', 'delay_label': '' }] cfg.setCustomAdvisers(customAdvisers) pmFolder = self.getMeetingFolder() vocab = get_vocab( pmFolder, "Products.PloneMeeting.vocabularies.askedadvicesvocabulary", only_factory=True) # we have 4 delay-aware advisers and 2 adviser groups selectable as optional delayAdvisers = [ adviser for adviser in cfg.getCustomAdvisers() if adviser['delay'] ] self.assertEqual(len(delayAdvisers), 4) self.assertEqual(len(get_organizations(not_empty_suffix='advisers')), 2) # once get, it is cached, it includes customAdvisers and MeetingConfig.selectableAdvisers self.assertEqual(len(vocab(pmFolder)), 6) # if we select a new organization, then the cache is cleaned # add an organization new_org = self.create('organization', title='New organization', acronym='N.G.') new_org_uid = new_org.UID() cfg.setSelectableAdvisers(cfg.getSelectableAdvisers() + (new_org_uid, )) # cache was cleaned self.assertEqual(len(vocab(pmFolder)), 7) # edit an organization new_org_term_id = 'real_org_uid__{0}'.format(new_org_uid) self.assertEqual( vocab(pmFolder).by_token[new_org_term_id].title, 'New organization (Inactive)') new_org.title = u'Modified title' notify(ObjectModifiedEvent(new_org)) # cache was cleaned self.assertEqual( vocab(pmFolder).by_token[new_org_term_id].title, 'Modified title (Inactive)') # select the organization, cache is cleaned self._select_organization(new_org_uid) self.assertEqual( vocab(pmFolder).by_token[new_org_term_id].title, 'Modified title') # remove an organization # first need to unselect it self._select_organization(new_org_uid, remove=True) self.portal.restrictedTraverse('@@delete_givenuid')(new_org_uid) # cache was cleaned self.assertEqual(len(vocab(pmFolder)), 6) # if we add/remove/edit a customAdviser, then the cache is cleaned # add a customAdviser customAdvisers.append({ 'row_id': 'unique_id_999', 'org': self.vendors_uid, 'gives_auto_advice_on': '', 'for_item_created_from': '2012/01/01', 'delay': '11', 'delay_label': 'New delay' }) cfg.setCustomAdvisers(customAdvisers) cfg.at_post_edit_script() self.assertEqual(len(vocab(pmFolder)), 7) self.assertTrue( 'delay_row_id__unique_id_999' in vocab(pmFolder).by_token) # delay is displayed in customAdviser title self.assertTrue('11 day(s)' in vocab( pmFolder).by_token['delay_row_id__unique_id_999'].title) # edit a customAdviser customAdvisers[-1]['delay'] = '12' cfg.setCustomAdvisers(customAdvisers) cfg.at_post_edit_script() self.assertTrue('12 day(s)' in vocab( pmFolder).by_token['delay_row_id__unique_id_999'].title) # remove a customAdviser customAdvisers = customAdvisers[:-1] cfg.setCustomAdvisers(customAdvisers) cfg.at_post_edit_script() self.assertEqual(len(vocab(pmFolder)), 6) # power advisers are taken into account by the vocabulary cfg.setPowerAdvisersGroups([self.endUsers_uid]) cfg.at_post_edit_script() self.assertEqual(len(vocab(pmFolder)), 7)
return "PloneMeeting must be installed to run this script !" try: file = open(fname, "rb") reader = csv.DictReader(file) except Exception, msg: file.close() return "Error with file : %s" % msg.value out = [] acl = self.acl_users pms = api.portal.get_tool('portal_membership') pgr = api.portal.get_tool('portal_groups') registration = api.portal.get_tool('portal_registration') ORGANIZATIONS = get_organizations() for row in reader: row_id = normalizeString(row['username'], self) # add users if not exist if row_id not in [ud['userid'] for ud in acl.searchUsers()]: pms.addMember(row_id, row['password'], ('Member', ), []) member = pms.getMemberById(row_id) properties = {'fullname': row['fullname'], 'email': row['email']} failMessage = registration.testPropertiesValidity( properties, member) if failMessage is not None: raise BadRequest(failMessage) member.setMemberProperties(properties) out.append("User '%s' is added" % row_id) else:
def test_pm_Speed_get_full_title(self): '''Test organization.get_full_title.''' self.changeUser('pmManager') org = get_organizations()[0] # call get_full_title 1000 times self._check_get_full_title(org, times=1000)
def _get_organizations(self, times=1, caching=True): ''' ''' for time in range(times): get_organizations(not_empty_suffix='advisers', caching=caching)