clean install

This commit is contained in:
2024-12-10 15:08:16 +01:00
commit e14eb2d8fd
31193 changed files with 3555714 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
<?php
namespace Drupal\role_delegation\Access;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Routing\Access\AccessInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\role_delegation\PermissionGenerator;
/**
* Checks access for displaying configuration edit user pages.
*/
class RoleDelegationAccessCheck implements AccessInterface {
/**
* The permission generator service.
*
* @var \Drupal\role_delegation\PermissionGenerator
*/
protected $permissionGenerator;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* The Role Delegation access check.
*
* @param \Drupal\role_delegation\PermissionGenerator $permission_generator
* The role delegation service.
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
*/
public function __construct(PermissionGenerator $permission_generator, AccountInterface $current_user) {
$this->permissionGenerator = $permission_generator;
$this->currentUser = $current_user;
}
/**
* Custom access check for the /user/%/roles page.
*
* @param \Drupal\Core\Session\AccountInterface|null $account
* Run access checks for this account.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
public function access(AccountInterface $account = NULL): AccessResultInterface {
if ($account === NULL) {
$account = $this->currentUser;
}
// No need for this access when the current user has the 'administer users'
// permission. Roles can be edited on the user edit page.
if ($account->hasPermission('administer users')) {
return AccessResult::neutral()->cachePerPermissions();
}
// If the user has any of the "assign custom role" permissions then we give
// them access to the form.
foreach ($this->permissionGenerator->rolePermissions() as $perm => $title) {
if ($account->hasPermission($perm)) {
return AccessResult::allowed()->cachePerPermissions();
}
}
// If the user can administer all permissions then they can also view the
// roles page.
return AccessResult::allowedIfHasPermission($account, 'assign all roles');
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace Drupal\role_delegation;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
/**
* Helper Service that loads all assignable roles for the given user.
*/
class DelegatableRoles implements DelegatableRolesInterface {
use StringTranslationTrait;
/**
* A value used to indicate that nothing has been submitted.
*
* @var array
*/
public static $emptyFieldValue = ['__role_delegation_empty_field_value__'];
/**
* {@inheritdoc}
*/
public function getAssignableRoles(AccountInterface $account): array {
$assignable_roles = [];
foreach ($this->getAllRoles() as $role) {
if ($account->hasPermission('assign all roles') || $account->hasPermission(sprintf('assign %s role', $role->id()))) {
$assignable_roles[$role->id()] = $role->label();
}
}
return $assignable_roles;
}
/**
* {@inheritdoc}
*/
public function getAllRoles(): array {
$all_roles = Role::loadMultiple();
unset($all_roles[RoleInterface::ANONYMOUS_ID], $all_roles[RoleInterface::AUTHENTICATED_ID]);
return $all_roles;
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace Drupal\role_delegation;
use Drupal\Core\Session\AccountInterface;
/**
* Interface for the delegatable roles service.
*/
interface DelegatableRolesInterface {
/**
* Gets the roles a user is allowed to assing.
*
* @param \Drupal\Core\Session\AccountInterface $account
* The account for which you want to know which roles they can assign.
*
* @return array
* An array of roles with machine names as keys and labels as values.
*/
public function getAssignableRoles(AccountInterface $account): array;
/**
* Gets all roles apart from anonymous and authenticated.
*
* @return \Drupal\user\RoleInterface[]
* An array of role objects.
*/
public function getAllRoles(): array;
}

View File

@@ -0,0 +1,115 @@
<?php
namespace Drupal\role_delegation\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\role_delegation\DelegatableRolesInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Configure book settings for this site.
*/
class RoleDelegationSettingsForm extends FormBase {
/**
* The current user viewing the form.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* The role delegation service.
*
* @var \Drupal\role_delegation\DelegatableRolesInterface
*/
protected $delegatableRoles;
/**
* The roles page setting form.
*
* @param \Drupal\role_delegation\DelegatableRolesInterface $delegatable_roles
* The role delegation service.
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user viewing the form.
*/
public function __construct(DelegatableRolesInterface $delegatable_roles, AccountInterface $current_user) {
$this->delegatableRoles = $delegatable_roles;
$this->currentUser = $current_user;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('delegatable_roles'),
$container->get('current_user')
);
}
/**
* {@inheritdoc}
*/
public function getFormId(): string {
return 'role_delegation_role_assign_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, AccountInterface $user = NULL): array {
if (!$user instanceof AccountInterface) {
return $form;
}
$current_roles = $user->getRoles(TRUE);
$current_roles = array_combine($current_roles, $current_roles);
$form['account']['role_change'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Roles'),
'#options' => $this->delegatableRoles->getAssignableRoles($this->currentUser),
'#default_value' => $current_roles,
'#description' => $this->t('Change roles assigned to user.'),
];
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Save'),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state): void {
/** @var \Drupal\user\UserInterface $account */
$account = $form_state->getBuildInfo()['args'][0];
// Make sure this functionality works when single_user_role is enabled.
// This module can change the role_change form element to a select or
// radio buttons, which will return an single value instead of the default
// checkboxes.
$assigned_roles = is_array($form_state->getValue('role_change')) ? $form_state->getValue('role_change') : [$form_state->getValue('role_change') => $form_state->getValue('role_change')];
$assignable_roles = $this->delegatableRoles->getAssignableRoles($this->currentUser);
$roles = [];
foreach ($assignable_roles as $rid => $assignable_role) {
$roles[$rid] = isset($assigned_roles[$rid]) && !empty($assigned_roles[$rid]) ? $rid : 0;
}
foreach ($roles as $rid => $value) {
empty($value) === TRUE ? $account->removeRole($rid) : $account->addRole($rid);
}
$account->save();
$this->messenger()->addStatus($this->t('The roles have been updated.'));
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Drupal\role_delegation;
use Drupal\Core\StringTranslation\StringTranslationTrait;
/**
* The PermissionGenerator class.
*/
class PermissionGenerator {
use StringTranslationTrait;
/**
* The delegatable role service for getting all the roles.
*
* @var \Drupal\role_delegation\DelegatableRolesInterface
*/
protected $delegatableRoles;
/**
* Construct a new permission generator.
*
* @param \Drupal\role_delegation\DelegatableRolesInterface $delegatable_roles
* The delegatable roles service.
*/
public function __construct(DelegatableRolesInterface $delegatable_roles) {
$this->delegatableRoles = $delegatable_roles;
}
/**
* Returns an array of permissions to assign specific roles.
*
* @return array
* An array of permissions in the correct format for permission_callbacks.
*/
public function rolePermissions(): array {
$permissions = [];
foreach ($this->delegatableRoles->getAllRoles() as $rid => $role) {
$permissions[sprintf('assign %s role', $rid)] = [
'title' => $this->t('Assign %role role', ['%role' => $role->label()]),
];
}
return $permissions;
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace Drupal\role_delegation\Plugin\Action;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\role_delegation\Access\RoleDelegationAccessCheck;
use Drupal\user\Plugin\Action\AddRoleUser;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Alternate action plugin for 'user_add_role_action'.
*
* This plugin makes sure the add role action also works without
* the 'administer users' permission.
*
* @see \Drupal\user\Plugin\Action\AddRoleUser
*/
class RoleDelegationAddRoleUser extends AddRoleUser {
/**
* The role delegation access checker.
*
* @var \Drupal\role_delegation\Access\RoleDelegationAccessCheck
*/
protected $roleDelegationAccessCheck;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeInterface $entity_type, RoleDelegationAccessCheck $roleDelegationAccessCheck) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type);
$this->roleDelegationAccessCheck = $roleDelegationAccessCheck;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager')->getDefinition('user_role'),
$container->get('access_check.role_delegation')
);
}
/**
* {@inheritdoc}
*/
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
$access = parent::access($object, $account, $return_as_object);
// If access == true, the user already has the administer users permission.
if ($access === TRUE) {
return $access;
}
// Check if the user has access to add the role to the user.
return $this->roleDelegationAccessCheck->access($account);
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace Drupal\role_delegation\Plugin\Action;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\role_delegation\Access\RoleDelegationAccessCheck;
use Drupal\user\Plugin\Action\RemoveRoleUser;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Alternate action plugin for 'user_remove_role_action'.
*
* This plugin makes sure the remove role action also works without
* the 'administer users' permission.
*
* @see \Drupal\user\Plugin\Action\RemoveRoleUser
*/
class RoleDelegationRemoveRoleUser extends RemoveRoleUser {
/**
* The role delegation access checker.
*
* @var \Drupal\role_delegation\Access\RoleDelegationAccessCheck
*/
protected $roleDelegationAccessCheck;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeInterface $entity_type, RoleDelegationAccessCheck $roleDelegationAccessCheck) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type);
$this->roleDelegationAccessCheck = $roleDelegationAccessCheck;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager')->getDefinition('user_role'),
$container->get('access_check.role_delegation')
);
}
/**
* {@inheritdoc}
*/
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
$access = parent::access($object, $account, $return_as_object);
// If access == true, the user already has the administer users permission.
if ($access === TRUE) {
return $access;
}
// Check if the user has access to remove the role from the user.
return $this->roleDelegationAccessCheck->access($account);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Drupal\role_delegation\Plugin\EntityReferenceSelection;
use Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection;
use Drupal\role_delegation\DelegatableRoles;
/**
* Entity reference implementation for the role_change field.
*
* @EntityReferenceSelection(
* id = "role_change:user_role",
* label = @Translation("Role change"),
* entity_types = {"user_role"},
* group = "role_change",
* weight = 0,
* )
*/
class RoleChangeSelection extends DefaultSelection {
/**
* {@inheritdoc}
*/
public function validateReferenceableEntities(array $ids): array {
$result = parent::validateReferenceableEntities($ids);
if ($ids) {
$result = array_merge($result, DelegatableRoles::$emptyFieldValue);
}
return $result;
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace Drupal\role_delegation\Plugin\views\field;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Routing\ResettableStackedRouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\user\Plugin\views\field\UserBulkForm;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\ViewExecutable;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines a user operations bulk form element.
*
* @ViewsField("role_delegation_user_bulk_form")
*/
class RoleDelegationUserBulkForm extends UserBulkForm {
/**
* The currently logged in user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, LanguageManagerInterface $language_manager, MessengerInterface $messenger, EntityRepositoryInterface $entity_repository, ResettableStackedRouteMatchInterface $route_match, AccountInterface $currentUser) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $language_manager, $messenger, $entity_repository, $route_match);
$this->currentUser = $currentUser;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager'),
$container->get('language_manager'),
$container->get('messenger'),
$container->get('entity.repository'),
$container->get('current_route_match'),
$container->get('current_user'),
);
}
/**
* {@inheritdoc}
*/
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
parent::init($view, $display, $options);
$entity_type = $this->getEntityType();
// Filter the actions to only include those for this entity type.
/** @var \Drupal\system\ActionConfigEntityInterface[] $actions */
$actions = $this->actionStorage->loadMultiple();
$this->actions = array_filter($actions, function ($action) use ($entity_type) {
$plugin_definition = $action->getPluginDefinition();
if ('user' === $action->getType() && in_array($plugin_definition['id'], [
'user_add_role_action',
'user_remove_role_action',
])) {
$collections = $action->getPluginCollections();
$collection = reset($collections);
$configuration = $collection->getConfiguration();
return $this->currentUser->hasPermission('assign all roles') || $this->currentUser->hasPermission(sprintf('assign %s role', $configuration['rid']));
}
else {
return $action->getType() == $entity_type;
}
});
}
}