def save_related_job_templates(sender, instance, **kwargs): '''save_related_job_templates loops through all of the job templates that use an Inventory or Project that have had their Organization updated. This triggers the rebuilding of the RBAC hierarchy and ensures the proper access restrictions. ''' if sender not in (Project, Inventory): raise ValueError('This signal callback is only intended for use with Project or Inventory') if instance._prior_values_store.get('organization_id') != instance.organization_id: jtq = JobTemplate.objects.filter(**{sender.__name__.lower(): instance}) for jt in jtq: update_role_parentage_for_instance(jt)
def save_related_job_templates(sender, instance, **kwargs): '''save_related_job_templates loops through all of the job templates that use an Inventory that have had their Organization updated. This triggers the rebuilding of the RBAC hierarchy and ensures the proper access restrictions. ''' if sender is not Inventory: raise ValueError( 'This signal callback is only intended for use with Project or Inventory' ) update_fields = kwargs.get('update_fields', None) if ((update_fields and not ('organization' in update_fields or 'organization_id' in update_fields)) or kwargs.get('created', False)): return if instance._prior_values_store.get( 'organization_id') != instance.organization_id: jtq = JobTemplate.objects.filter(**{sender.__name__.lower(): instance}) for jt in jtq: parents_added, parents_removed = update_role_parentage_for_instance( jt) if parents_added or parents_removed: logger.info( 'Permissions on JT {} changed due to inventory {} organization change from {} to {}.' .format( jt.pk, instance.pk, instance._prior_values_store.get('organization_id'), instance.organization_id))
def rebuild_role_parentage(apps, schema_editor, models=None): """ This should be called in any migration when any parent_role entry is modified so that the cached parent fields will be updated. Ex: foo_role = ImplicitRoleField( parent_role=['bar_role'] # change to parent_role=['admin_role'] ) This is like rebuild_role_hierarchy, but that method updates ancestors, whereas this method updates parents. """ start = time() seen_models = set() model_ct = 0 noop_ct = 0 ContentType = apps.get_model('contenttypes', "ContentType") additions = set() removals = set() role_qs = Role.objects if models: # update_role_parentage_for_instance is expensive # if the models have been downselected, ignore those which are not in the list ct_ids = list( ContentType.objects.filter( model__in=[name.lower() for name in models]).values_list('id', flat=True)) role_qs = role_qs.filter(content_type__in=ct_ids) for role in role_qs.iterator(): if not role.object_id: continue model_tuple = (role.content_type_id, role.object_id) if model_tuple in seen_models: continue seen_models.add(model_tuple) # The GenericForeignKey does not work right in migrations # with the usage as role.content_object # so we do the lookup ourselves with current migration models ct = role.content_type app = ct.app_label ct_model = apps.get_model(app, ct.model) content_object = ct_model.objects.get(pk=role.object_id) parents_added, parents_removed = update_role_parentage_for_instance( content_object) additions.update(parents_added) removals.update(parents_removed) if parents_added: model_ct += 1 logger.debug('Added to parents of roles {} of {}'.format( parents_added, content_object)) if parents_removed: model_ct += 1 logger.debug('Removed from parents of roles {} of {}'.format( parents_removed, content_object)) else: noop_ct += 1 logger.debug('No changes to role parents for {} resources'.format(noop_ct)) logger.debug('Added parents to {} roles'.format(len(additions))) logger.debug('Removed parents from {} roles'.format(len(removals))) if model_ct: logger.info( 'Updated implicit parents of {} resources'.format(model_ct)) logger.info('Rebuild parentage completed in %f seconds' % (time() - start)) # this is ran because the ordinary signals for # Role.parents.add and Role.parents.remove not called in migration Role.rebuild_role_ancestor_list(list(additions), list(removals))
def test_update_parents_keeps_teams(team, project): project.update_role.parents.add(team.member_role) assert team.member_role in project.update_role # test prep sanity check update_role_parentage_for_instance(project) assert team.member_role in project.update_role # actual assertion