def role_delete(name: str) -> ResponseType: """ Show and process a form to delete the given role. :param name: The name of the role. :return: The response for this view. """ role = Role.load_from_name(name) if role is None: abort(404) # If this is the last role allowed to edit roles show an info text. if role.is_only_role_allowed_to_edit_roles(): deletion_not_possible_text = _('This role cannot be deleted because it is the only one that can edit roles.') return render_template('administration/role_delete.html', role=name, deletion_not_possible_text=deletion_not_possible_text) # Create (and possibly process) the delete form. delete_form = RoleDeleteForm(role) if delete_form.validate_on_submit(): try: new_role_id = delete_form.new_role.data new_role = Role.load_from_id(new_role_id) except AttributeError: # The new_role field might not exist because there are no users. new_role = None role.delete(new_role) flash(_('The role has been deleted.')) return redirect(url_for('.roles_list')) return render_template('administration/role_delete.html', role=name, delete_form=delete_form)
def role_delete(name: str) -> str: """ Show a form to delete the given role and process that form. :param name: The name of the role. :return: The HTML response. """ role = Role.load_from_name(name) if role is None: abort(404) # If this is the last role allowed to edit roles show an info text. if role.is_only_role_allowed_to_edit_roles(): deletion_not_possible_text = _('This role cannot be deleted because it is the only one that can edit roles.') return render_template('administration/role_delete.html', role=name, deletion_not_possible_text=deletion_not_possible_text) # Create (and possibly process) the delete form. delete_form = RoleDeleteForm(role) if delete_form.validate_on_submit(): try: new_role_id = delete_form.new_role.data new_role = Role.load_from_id(new_role_id) except AttributeError: # The new_role field might not exist because there are no users. new_role = None role.delete(new_role) flash(_('The role has been deleted.')) return redirect(url_for('.roles_list')) return render_template('administration/role_delete.html', role=name, delete_form=delete_form)
def test_role_permissions_post_only_role_to_edit_roles(self): """ Test updating the permissions of a role that is the only role allowed to edit roles. Unset the permission to edit roles. Expected result: The new permissions are set on the role, but the role keeps the permission to edit roles. """ role = self.create_role(Permission.EditRole) self.create_and_login_user(role=role) self.assertTrue(role.is_only_role_allowed_to_edit_roles()) new_permissions = Permission.EditRole | Permission.EditGlobalSettings data = self.post(f'/administration/role/{role.name}/permissions', data=dict( editglobalsettings=True, editrole=False, edituser=None, )) role = Role.load_from_name(role.name) self.assertEqual(new_permissions, role.permissions) self.assertIn('<h1>Edit Role “', data) self.assertIn( 'Define the permissions which the users to whom this role is assigned will have.', data) # The apostrophe is escaped... self.assertIn('The role's permissions have been updated.', data) self.assertNotIn('View the users who have this role assigned to them', data) self.assertNotIn('Permanently delete this role', data) self.assertNotIn('Edit the role\'s header data', data)
def role_permissions(name: str) -> ResponseType: """ Show and process a form to change a role's permissions. :param name: The name of the role. :return: The response for this view. """ role = Role.load_from_name(name) if role is None: abort(404) disabled_permissions = None if role.is_only_role_allowed_to_edit_roles(): disabled_permissions = Permission.EditRole permission_form = create_permission_form(PermissionForm, role.permissions, disabled_permissions=disabled_permissions) if permission_form.validate_on_submit(): role.permissions = permission_form.permissions db.session.commit() flash(_('The role\'s permissions have been updated.')) return redirect(url_for('.role_permissions', name=role.name)) return render_template('administration/role_permissions.html', role=name, permission_form=permission_form)
def test_delete_only_role_to_edit_roles(self): """ Test deleting a role that is the only one allowed to edit roles. Expected result: An error is raised. """ name = 'Administrator' permission = Permission.EditRole role = Role(name=name) role.permissions = permission db.session.add(role) db.session.commit() with self.assertRaises(DeletionPreconditionViolationError) as exception_cm: role.delete() self.assertIn('Cannot delete the only role with the permission to edit roles.', str(exception_cm.exception)) # Add another role with the required permission. Now, it is possible to delete the first role. other_role = Role(name='Guest') other_role.permissions = permission db.session.add(other_role) db.session.commit() role.delete() self.assertIsNone(Role.load_from_name(name))
def test_delete_same_role(self): """ Test deleting a role if the same role is given. Expected result: An error is raised. """ name = 'Administrator' role = Role(name=name) user = User('*****@*****.**', 'Jane Doe') user.role = role db.session.add(role) db.session.add(user) db.session.commit() with self.assertRaises(ValueError) as exception_cm: role.delete(role) loaded_role = Role.load_from_name(name) self.assertEqual( 'The new role must not be the role that will be deleted.', str(exception_cm.exception)) self.assertIsNotNone(loaded_role) self.assertEqual(loaded_role, user.role)
def test_delete_has_users_new_role(self): """ Test deleting a role if there are still users and a valid new role is given. Expected result: The role is deleted. The role is assigned to all users who had the old role (but not to others). """ # The role that will be deleted. name = 'Administrator' role = Role(name=name) user = User('*****@*****.**', 'Jane Doe') user.role = role db.session.add(role) db.session.add(user) # The new role for the user. new_role = Role(name='Guest') db.session.add(new_role) # Another role and user who will stay untouched. other_role = Role(name='User') other_user = User('*****@*****.**', 'John Doe') other_user.role = other_role db.session.add(other_role) db.session.add(other_user) db.session.commit() role.delete(new_role) loaded_role = Role.load_from_name(name) self.assertIsNone(loaded_role) self.assertEqual(new_role, user.role) self.assertEqual(other_role, other_user.role)
def test_delete_only_role_to_edit_roles(self): """ Test deleting a role that is the only one allowed to edit roles. Expected result: An error is raised. """ name = 'Administrator' permission = Permission.EditRole role = Role(name=name) role.permissions = permission db.session.add(role) db.session.commit() with self.assertRaises( DeletionPreconditionViolationError) as exception_cm: role.delete() self.assertIn( 'Cannot delete the only role with the permission to edit roles.', str(exception_cm.exception)) # Add another role with the required permission. Now, it is possible to delete the first role. other_role = Role(name='Guest') other_role.permissions = permission db.session.add(other_role) db.session.commit() role.delete() self.assertIsNone(Role.load_from_name(name))
def role_permissions(name: str) -> str: """ Show a form to a role's permissions. :param name: The name of the role. :return: The HTML response. """ role = Role.load_from_name(name) if role is None: abort(404) disabled_permissions = None if role.is_only_role_allowed_to_edit_roles(): disabled_permissions = Permission.EditRole permission_form = create_permission_form(PermissionForm, role.permissions, disabled_permissions=disabled_permissions) if permission_form.validate_on_submit(): role.permissions = permission_form.permissions db.session.commit() flash(_('The role\'s permissions have been updated.')) return redirect(url_for('.role_permissions', name=role.name)) return render_template('administration/role_permissions.html', role=name, permission_form=permission_form)
def test_load_from_name_failure(self): """ Test loading a non-existing role via its name. Expected result: Nothing is returned. """ loaded_role = Role.load_from_name('Administrator') self.assertIsNone(loaded_role)
def test_load_from_name_is_case_sensitive(self): """ Test that loading a role by its name is case sensitive. Expected result: The method returns the role if the name is the same in the same case, otherwise `None`. """ name = 'Administrator'.upper() role = Role(name=name) db.session.add(role) db.session.commit() loaded_role = Role.load_from_name(name) self.assertIsNotNone(loaded_role) self.assertEqual(name, loaded_role.name) loaded_role = Role.load_from_name(name.lower()) self.assertIsNone(loaded_role)
def test_delete_no_users_no_role(self): """ Test deleting a role if there are no users and no role is given. Expected result: The role is deleted. """ name = 'Administrator' role = Role(name=name) db.session.add(role) db.session.commit() role.delete() loaded_role = Role.load_from_name(name) self.assertIsNone(loaded_role)
def test_role_header_get_no_role(self): """ Test editing a role that does not exist. Expected result: An error 404 is returned. """ role = self.create_role(Permission.EditRole) self.create_and_login_user(role=role) non_existing_role = 'Guest' self.assertIsNone(Role.load_from_name(non_existing_role)) self.get(f'/administration/role/{non_existing_role}', expected_status=404)
def test_role_new_post_invalid_name(self): """ Test creating a new role with an invalid name. Expected result: The new-role page is shown and no role has been created. """ role = self.create_role(Permission.EditRole) self.create_and_login_user(role=role) name = Role.invalid_names[0] data = self.post('/administration/role/new', data=dict(name=name)) self.assertIn('Add a New Role', data) self.assertNotIn('The new role has been created.', data) self.assertIsNone(Role.load_from_name(name))
def test_load_from_name_success(self): """ Test loading an existing role via its name. Expected result: The role is returned. """ name = 'Administrator' role = Role(name=name) role_id = 1 db.session.add(role) db.session.commit() self.assertEqual(role_id, role.id) loaded_role = Role.load_from_name(name) self.assertIsNotNone(loaded_role) self.assertEqual(role_id, loaded_role.id) self.assertEqual(name, loaded_role.name)
def role_users(name: str) -> str: """ List all users to whom the given role is assigned. :param name: The name of the role. :return: The HTML response. """ role = Role.load_from_name(name) if role is None: abort(404) # Get a search term and the resulting query. If no search term is given, all users will be returned. search_form = SearchForm() user_query = User.get_search_query(query=role.users, search_term=search_form.search_term) # noinspection PyProtectedMember pagination = UserPagination(user_query.order_by(User.name, User._email)) return render_template('administration/role_users.html', role=name, pagination=pagination, search_form=search_form)
def role_users(name: str) -> str: """ Show a list of all users to whom the given role is assigned. :param name: The name of the role. :return: The response for this view. """ role = Role.load_from_name(name) if role is None: abort(404) # Get a search term and the resulting query. If no search term is given, all users will be returned. search_form = SearchForm() user_query = User.get_search_query(query=role.users, search_term=search_form.search_term) # noinspection PyProtectedMember pagination = UserPagination(user_query.order_by(User.name, User._email)) return render_template('administration/role_users.html', role=name, pagination=pagination, search_form=search_form)
def role_edit(name: str) -> str: """ Show a form to edit an existing role. :param name: The name of the role to edit. :return: The HTML response. """ role = Role.load_from_name(name) if role is None: abort(404) # Create (and possibly process) the header data form. header_form = RoleHeaderDataForm(obj=role) if header_form.validate_on_submit(): header_form.populate_obj(role) db.session.commit() flash(_('The role has been updated.')) return redirect(url_for('.role_edit', name=role.name)) return render_template('administration/role_header.html', role=name, header_form=header_form)
def __call__(self, form: Form, field: Field) -> None: """ Execute the validator. :param form: The form to which the field belongs. :param field: The field to which this validator is assigned. :raise ValidationError: In case the validation fails. """ # This validator does not require data. If there is no data everything is fine. name = field.data if not name: return # If the field's data has not changed no further check is needed. if field.object_data == name: return # If there already is a role with that name raise an error. role = Role.load_from_name(name) if role: raise ValidationError(self.message)
def role_edit(name: str) -> ResponseType: """ Show and process a form to edit an existing role. :param name: The name of the role. :return: The response for this view. """ role = Role.load_from_name(name) if role is None: abort(404) # Create (and possibly process) the header data form. header_form = RoleHeaderDataForm(obj=role) if header_form.validate_on_submit(): header_form.populate_obj(role) db.session.commit() flash(_('The role has been updated.')) return redirect(url_for('.role_edit', name=role.name)) return render_template('administration/role_header.html', role=name, header_form=header_form)
def test_delete_has_users_no_role(self): """ Test deleting a role if there are still users and no role is given. Expected result: An error is raised. """ name = 'Administrator' role = Role(name=name) user = User('*****@*****.**', 'Jane Doe') user.role = role db.session.add(role) db.session.add(user) db.session.commit() with self.assertRaises(ValueError) as exception_cm: role.delete() loaded_role = Role.load_from_name(name) self.assertIn('A new role must be given', str(exception_cm.exception)) self.assertIsNotNone(loaded_role) self.assertEqual(loaded_role, user.role)
def test_role_new_post_success(self): """ Test creating a new role. Expected result: The list of roles is shown and the new role has been created. """ role = self.create_role(Permission.EditRole, name='Administrator') self.create_and_login_user(role=role) name = 'Guest' permissions = Permission.EditRole | Permission.EditGlobalSettings data = self.post('/administration/role/new', data=dict(name=name, editrole=True, editglobalsettings=True)) self.assertIn('Roles', data) self.assertNotIn('Add a New Role', data) self.assertIn('The new role has been created.', data) role = Role.load_from_name(name) self.assertIsNotNone(role) self.assertEqual(permissions, role.permissions)