class AddRoleToPermissionStateChange(BaseStateChange): """State change to add a role to a permission.""" descriptive_text = { "verb": "add", "default_string": "role to permission", "detail_string": "role {role_name} to permission", "preposition": "for" } section = "Permissions" allowable_targets = [PermissionsItem] settable_classes = ["all_models"] role_name = field_utils.RoleField(label="Role to add", required=True) def validate(self, actor, target): community_owner = target.get_owner() if not community_owner.roles.is_role(self.role_name): raise ValidationError( f"{self.role_name} is not a role and so can't be set on permission" ) def implement(self, actor, target, **kwargs): target.add_role_to_permission(role=self.role_name) target.save() return target
class RemoveRoleFromPermissionStateChange(BaseStateChange): """State change to remove a role from a permission.""" descriptive_text = { "verb": "remove", "default_string": "role from permission", "detail_string": "role {role_name} from permission", "preposition": "for" } section = "Permissions" linked_filters = ["RoleMatchesFilter"] allowable_targets = [PermissionsItem] settable_classes = ["all_models"] role_name = field_utils.RoleField(label="Role to remove", required=True) def validate(self, actor, target): if not target.roles.role_name_in_list(self.role_name): raise ValidationError( f"{self.role_name} isn't a role on this permission so can't be removed" ) def implement(self, actor, target, **kwargs): target.remove_role_from_permission(role=self.role_name) target.save() return target
class RoleMatchesFilter(Filter): descriptive_name = "the role's name is a specific value" configured_name = "the role's name is '{role_name}'" linked = True role_name = field_utils.RoleField(label="Role to match", required=True) def check(self, *, action, **kwargs): return action.change.role_name == self.role_name, f"the role name does not match {self.role_name}"
class RemovePeopleFromRoleStateChange(BaseStateChange): """State change to remove people from role in Community.""" descriptive_text = { "verb": "remove", "default_string": "people from role", "detail_string": "people {people_to_remove} from role '{role_name}'", "preposition": "in" } section = "Community" allowable_targets = ["all_community_models"] role_name = field_utils.RoleField(label="Role to remove people from", required=True) people_to_remove = field_utils.ActorListField(label="People to remove from role", required=True) def is_conditionally_foundational(self, action): """If role_name is owner or governor role, should should be treated as a conditional change.""" if self.role_name in action.target.roles.get_owners()["roles"]: return True if self.role_name in action.target.roles.get_governors()["roles"]: return True return False def validate(self, actor, target): """When removing people from a role, we must check that doing so does not leave us without any owners.""" if self.role_name not in target.roles.get_owners()["roles"]: return # this isn't an owner role if len(self.people_to_remove) < len(target.roles.get_users_given_role(self.role_name)): return # removing these users will not result in empty role if len(target.roles.get_owners()["actors"]) > 0: return # community has individual actor owners so it doesn't need roles for role in target.roles.get_owners()["roles"]: if role == self.role_name: continue actors = target.roles.get_users_given_role(role) if len(actors) > 0: return # there are other owner roles with actors specified raise ValidationError("Cannot remove everyone from this role as " + "doing so would leave the community without an owner") def implement(self, actor, target, **kwargs): target.roles.remove_people_from_role(self.role_name, self.people_to_remove) target.save() return target
class RemoveRoleStateChange(BaseStateChange): """State change to remove role from Community.""" descriptive_text = { "verb": "remove", "default_string": "role from community", "detail_string": "role {role_name}", "preposition": "from" } section = "Community" allowable_targets = ["all_community_models"] role_name = field_utils.RoleField(label="Role to remove from community", required=True) def role_in_permissions(self, permission, actor): """Checks for role in permission and returns True if it exists. Checks in permissions which are nested on this permission as well.""" role_references = [] if permission.has_role(role=self.role_name): role_references.append(permission) client = Client(actor=actor, target=permission) for permission in client.PermissionResource.get_all_permissions(): role_references += self.role_in_permissions(permission, actor) return role_references def validate(self, actor, target): """A role cannot be deleted without removing it from the permissions it's referenced in, and without removing it from owner and governor roles if it is there.""" role_references = [] client = Client(actor=actor, target=target) for permission in client.PermissionResource.get_all_permissions(): role_references += self.role_in_permissions(permission, actor) if len(role_references) > 0: permission_string = ", ".join([str(permission.pk) for permission in role_references]) raise ValidationError(f"Role cannot be deleted until it is removed from permissions: {permission_string}") if self.role_name in target.roles.get_owners()["roles"]: raise ValidationError("Cannot remove role with ownership privileges") if self.role_name in target.roles.get_governors()["roles"]: raise ValidationError("Cannot remove role with governorship privileges") def implement(self, actor, target, **kwargs): target.roles.remove_role(self.role_name) target.save() return target
class AddPeopleToRoleStateChange(BaseStateChange): """State change to add people to role in Community.""" descriptive_text = { "verb": "add", "default_string": "people to role", "detail_string": "people {people_to_add} to role '{role_name}'", "preposition": "in" } section = "Community" allowable_targets = ["all_community_models"] role_name = field_utils.RoleField(label="Role to add people to", required=True) people_to_add = field_utils.ActorListField(label="People to add to role", required=True) linked_filters = ["RoleMatchesFilter"] def is_conditionally_foundational(self, action): """If role_name is owner or governor role, should should be treated as a conditional change.""" if self.role_name in action.target.roles.get_owners()["roles"]: return True if self.role_name in action.target.roles.get_governors()["roles"]: return True return False def validate(self, actor, target): if not isinstance(self.role_name, str): raise ValidationError(f"Role must be type str, not {str(type(self.role_name))}") if not target.roles.is_role(self.role_name): raise ValidationError(f"Role {self.role_name} does not exist") people_already_in_role = [] for person in self.people_to_add: if target.roles.has_specific_role(self.role_name, person): people_already_in_role.append(str(person)) if people_already_in_role: raise ValidationError(f"Users {list_to_text(people_already_in_role)} already in role {self.role_name}") def implement(self, actor, target, **kwargs): target.roles.add_people_to_role(self.role_name, self.people_to_add) target.save() return target
class AddRoleStateChange(BaseStateChange): """State change to add role to Community.""" descriptive_text = { "verb": "add", "default_string": "role to community", "detail_string": "role {role_name} to community", } section = "Community" allowable_targets = ["all_community_models"] role_name = field_utils.RoleField(label="Role to add to community", required=True) def validate(self, actor, target): if self.role_name in ["members", "governors", "owners"]: raise ValidationError("Role name cannot be one of protected names: members, governors, owners.") if target.roles.is_role(self.role_name): raise ValidationError("The role " + self.role_name + " already exists.") def implement(self, actor, target, **kwargs): target.roles.add_role(self.role_name) target.save() return target