def _locate_all_auto_traits(): """Extract all automatically assigned traits from cereconf. cereconf.AFFILIATE_TRAITS contains a mapping for translating role ids in source data to trait descriptions for all automatically awarded traits. This function processes this mapping and returns a sequence of all auto traits. @rtype: sequence @return: A sequence of trait codes for all automatically awarded traits. The actual trait assignment (from role ids) happens in L{import_HR_person.py}. This script takes the traits and assigns group membersships based on them. """ # IVR 2008-01-17 FIXME: This is a copy of a similar function from # import_HR_person.py. Duplication is bad. # Collect all known auto traits. if not hasattr(cereconf, "AFFILIATE_TRAITS"): return set() auto_traits = set() for trait_code_str in cereconf.AFFILIATE_TRAITS.itervalues(): try: trait = constants.EntityTrait(trait_code_str) int(trait) except Errors.NotFoundError: logger.error("Trait <%s> is defined in cereconf.AFFILIATE_TRAITS, " "but it is unknown i Cerebrum (code)", trait_code_str) continue # Check that the trait is actually associated with a person (and not # something else. AFFILIATE_TRAITS is supposed to "cover" person # objects ONLY!) if trait.entity_type != constants.entity_person: logger.error("Trait <%s> from AFFILIATE_TRAITS is associated with " "<%s>, but we allow person traits only", trait, trait.entity_type) continue auto_traits.add(int(trait)) return auto_traits
def get_target_by_external_id(ext_id): # This does not have to be person, but cereconf.CLASS_ENTITY is # insufficient. We need EntityExternalId here. en = Factory.get("Person")(self.db) # first, locate the entity_id candidates = en.list_external_ids(external_id=ext_id) only_ids = set([int(x["entity_id"]) for x in candidates]) if len(only_ids) < 1: raise CerebrumError("No entity with external id=%s" % ext_id) if len(only_ids) > 1: raise CerebrumError("Too many targets with external id=%s" "[entity_ids=%s]" % (ext_id, only_ids)) return get_target_entity(only_ids.pop())
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Cerebrum; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. from Cerebrum.Entity import Entity from Cerebrum.Constants import _ChangeTypeCode, _get_code from Cerebrum import Errors from Cerebrum.Utils import NotSet from EntityTraitConstants import _EntityTraitCode try: set() except: from Cerebrum.extlib.sets import Set as set __version__ = "1.1" @_ChangeTypeCode.formatter('trait') def format_cl_trait(co, val): return _get_code(co.EntityTrait, val, '<unknown>') class EntityTrait(Entity): """Mixin class which adds generic traits to an entity.""" def clear(self):
# # You should have received a copy of the GNU General Public License # along with Cerebrum; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. import time import cerebrum_path import cereconf from Cerebrum import Constants from Cerebrum.Utils import Factory from Cerebrum.modules.bofhd.errors import CerebrumError from Cerebrum import Errors import xmlrpclib from mx import DateTime try: set() except NameError: from Cerebrum.extlib.sets import Set as set class _BofhdRequestOpCode(Constants._CerebrumCode): "Mappings stored in the auth_role_op_code table" _lookup_table = '[:table schema=cerebrum name=bofhd_request_code]' class _AuthRoleOpCode(Constants._CerebrumCode): "Mappings stored in the auth_role_op_code table" _lookup_table = '[:table schema=cerebrum name=auth_op_code]' class Constants(Constants.Constants):
def synchronise_groups(groups_from_cerebrum, groups_from_data): """Synchronise current in-memory representation of groups with the db. The groups (through the rules) are built in-memory. This function synchronises the in-memory data structure with Cerebrum. For each group, read the membership info, compare it with groups_from_data, adjust the information, write_db() on the group. NB! L{groups_from_cerebrum} is modified by this function. @type groups_from_cerebrum: dict @param: Cf. L{find_all_auto_groups}. @type groups_from_data: dict @param: Cf. L{populate_groups_from_rule}. @rtype: type(groups_from_cerebrum) @return: Modified L{groups_from_cerebrum}. """ group = Factory.get("Group")(database) for group_id, membership_info in groups_from_data.iteritems(): try: group.clear() group.find(group_id) gname = group.group_name except Errors.NotFoundError: logger.warn("group_id=%s disappeared from Cerebrum.", group_id) continue # select just the entity_ids (we don't care about entity_type) group_members = set(int(x["member_id"]) for x in group.search_members(group_id=group.entity_id)) # now, synch the union members. sync'ing means making sure that the # members of group are exactly the ones in memberset. # those that are not in 'group_members', should be added add_count = 0 to_add = list() for member_type, members in membership_info.iteritems(): to_add = members.difference(group_members) add_count += len(to_add) add_members(group, to_add) # those that are in 'group_members', but not in membership_info, # should be removed. to_remove = group_members.copy() for member_type, members in membership_info.iteritems(): to_remove = to_remove.difference(members) remove_members(group, to_remove) if gname not in groups_from_cerebrum: logger.debug("New group id=%s, name=%s", group_id, gname) else: del groups_from_cerebrum[gname] logger.debug("Existing group id=%s, name=%s", group_id, gname) if to_remove or to_add: logger.debug("Updated group id=%s, name=%s; added=%d, removed=%d", group_id, gname, add_count, len(to_remove)) else: logger.debug("No changes to group id=%s, name=%s", group_id, gname) # It's harmless when no changes are made, and placing it here makes # the code simpler. group.write_db() return groups_from_cerebrum
def populate_groups_from_rule(person_generator, row2groups, current_groups, new_groups): """Sweep all the people from generator and assign group memberships. There may be several rules for building all of the groups. For each rule, this functions assigns proper memberships to new_groups. Once we have finished processing the rules, we can synchronize the in-memory data structure with the database. @type person_generator: Generator (or a function returning a sequence) of db_rows. @param person_generator: Next db-row 'source' to process. Calling this yields something we can iterate across. The items in the sequence should be db_rows (or something which emulates them, like a dict) @type row2groups: callable @param row2groups: Function that converts a row returned by L{person_generator} to a list of memberships. Calling row2groups on any row D returned by L{person_generator} returns a list of triples (x, y, z) (cf. L{employee2groups} for the precise description of their meanings). @type current_groups: dict @param current_groups: Cf. L{find_all_auto_groups}. @type new_groups: dict @param new_groups: A dictionary mapping group_ids to membership info. Each membership info is a dictionary, mapping entity types to member ids. All group_ids referenced refer to groups existing in Cerebrum (i.e. we are guaranteed (at least at some isolation level) that all group_ids in this dict exist in Cerebrum. An example of this dictionary would be:: {1: {<entity person>: set([10, 11, 12, 13]), <entity group>: set([20, 21, 22])}} ... meaning that group with id=1 has two types of members: people (with ids 10-13) and other groups (ids 20, 21, 22). Note that it is unlikely that a group would have *both* people and groups as members. It is either one or the other, but not both. """ count = 0 for person in person_generator(): memberships = row2groups(person, current_groups) for member_id, member_type, group_id in memberships: # all known memberships for group_id d = new_groups.setdefault(group_id, dict()) member_type = int(member_type) # Add the member to the membership set of the right type. # Typically, any given group would have either all members as # people or as groups. d.setdefault(member_type, set()).add(member_id) count += 1 logger.debug("After processing rule, we have %d groups", len(new_groups)) logger.debug("... and <= %d members", count)