Loading src/Entity/Access/GroupAccessControlHandler.php +6 −1 Changes for src/Entity/Access/GroupAccessControlHandler.php: 6 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -119,7 +119,12 @@ class GroupAccessControlHandler extends EntityAccessControlHandler implements En return $access->addCacheableDependency($cacheability); } // @todo To be consistent with the rest of the module, return forbidden. // The Group module's ideology is that if you want to do something to a // group, you need Group to explicitly allow access or else the result will // be forbidden. Having said that, if we do not support an operation yet, // it's probably nicer to return neutral here. This way, any module that // exposes new operations will work as intended AND NOT HAVE GROUP ACCESS // CHECKS until Group specifically implements said operations. return AccessResult::neutral(); } Loading src/Plugin/Group/RelationHandler/AccessControlInterface.php +13 −0 Changes for src/Plugin/Group/RelationHandler/AccessControlInterface.php: 13 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -12,6 +12,19 @@ use Drupal\group\Entity\GroupInterface; */ interface AccessControlInterface extends RelationHandlerInterface { /** * Checks whether an operation is supported for a given target. * * @param string $operation * The permission operation. Usually "create", "view", "update" or "delete". * @param string $target * The target of the operation. Can be 'relation' or 'entity'. * * @return bool * Whether the operation is supported. */ public function supportsOperation($operation, $target); /** * Checks access to an operation on the relation. * Loading src/Plugin/Group/RelationHandler/AccessControlTrait.php +36 −0 Changes for src/Plugin/Group/RelationHandler/AccessControlTrait.php: 36 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -4,11 +4,13 @@ namespace Drupal\group\Plugin\Group\RelationHandler; use Drupal\Core\Access\AccessResult; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Session\AccountInterface; use Drupal\group\Access\GroupAccessResult; use Drupal\group\Entity\GroupContentInterface; use Drupal\group\Entity\GroupInterface; use Drupal\group\Plugin\Group\Relation\GroupRelationTypeInterface; use Drupal\user\EntityOwnerInterface; /** * Trait for group relation permission providers. Loading @@ -23,6 +25,27 @@ trait AccessControlTrait { init as traitInit; } /** * The entity type the plugin handler is for. * * @var \Drupal\Core\Entity\EntityTypeInterface */ protected $entityType; /** * Whether the target entity type implements the EntityOwnerInterface. * * @var bool */ protected $implementsOwnerInterface; /** * Whether the target entity type implements the EntityPublishedInterface. * * @var bool */ protected $implementsPublishedInterface; /** * The plugin's permission provider. * Loading @@ -35,9 +58,22 @@ trait AccessControlTrait { */ public function init($plugin_id, GroupRelationTypeInterface $group_relation_type) { $this->traitInit($plugin_id, $group_relation_type); $this->entityType = $this->entityTypeManager()->getDefinition($group_relation_type->getEntityTypeId()); $this->implementsOwnerInterface = $this->entityType->entityClassImplements(EntityOwnerInterface::class); $this->implementsPublishedInterface = $this->entityType->entityClassImplements(EntityPublishedInterface::class); $this->permissionProvider = $this->groupRelationTypeManager()->getPermissionProvider($plugin_id); } /** * {@inheritdoc} */ public function supportsOperation($operation, $target) { if (!isset($this->parent)) { throw new \LogicException('Using AccessControlTrait without assigning a parent or overwriting the methods.'); } return $this->parent->supportsOperation($operation, $target); } /** * {@inheritdoc} */ Loading src/Plugin/Group/RelationHandler/PermissionProviderInterface.php +1 −1 Changes for src/Plugin/Group/RelationHandler/PermissionProviderInterface.php: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ interface PermissionProviderInterface extends RelationHandlerInterface { * Defaults to 'any'. * * @return string|false * The permission name or FALSE if it does not apply. * The permission name or FALSE if the combination is not supported. */ public function getPermission($operation, $target, $scope = 'any'); Loading src/Plugin/Group/RelationHandlerDefault/AccessControl.php +36 −5 Changes for src/Plugin/Group/RelationHandlerDefault/AccessControl.php: 36 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -4,7 +4,6 @@ namespace Drupal\group\Plugin\Group\RelationHandlerDefault; use Drupal\Core\Access\AccessResult; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Session\AccountInterface; use Drupal\group\Access\GroupAccessResult; Loading @@ -13,7 +12,6 @@ use Drupal\group\Entity\GroupInterface; use Drupal\group\Plugin\Group\RelationHandler\AccessControlInterface; use Drupal\group\Plugin\Group\RelationHandler\AccessControlTrait; use Drupal\group\Plugin\Group\Relation\GroupRelationTypeManagerInterface; use Drupal\user\EntityOwnerInterface; /** * Provides access control for group relations. Loading @@ -35,6 +33,30 @@ class AccessControl implements AccessControlInterface { $this->groupRelationTypeManager = $groupRelationTypeManager; } /** * {@inheritdoc} */ public function supportsOperation($operation, $target) { assert(in_array($target, ['relation', 'entity'], TRUE), '$target must be either "relation" or "entity"'); $permissions = [$this->permissionProvider->getPermission($operation, $target, 'any')]; // We know relations have owners, but need to check for the target entity. // Please note that we do not check for "view" vs "view unpublished" here // because you usually can't have the latter without the former so a regular // check vs the passed in operation should suffice for most use cases. if ($target === 'relation' || $this->implementsOwnerInterface) { $permissions[] = $this->permissionProvider->getPermission($operation, $target, 'own'); } foreach ($permissions as $permission) { if ($permission !== FALSE) { return TRUE; } } return FALSE; } /** * {@inheritdoc} */ Loading Loading @@ -81,6 +103,16 @@ class AccessControl implements AccessControlInterface { * {@inheritdoc} */ public function entityAccess(EntityInterface $entity, $operation, AccountInterface $account, $return_as_object = FALSE) { // The Group module's ideology is that if you want to do something to a // group's content, you need Group to explicitly allow access or else the // result will be forbidden. Having said that, if we do not support an // operation yet, it's probably nicer to return neutral here. This way, any // module that exposes new operations will work as intended AND NOT HAVE // GROUP ACCESS CHECKS until Group specifically implements said operations. if (!$this->supportsOperation($operation, 'entity')) { return AccessResult::neutral(); } /** @var \Drupal\group\Entity\Storage\GroupContentStorageInterface $storage */ $storage = $this->entityTypeManager()->getStorage('group_content'); $group_contents = $storage->loadByEntity($entity); Loading @@ -100,12 +132,11 @@ class AccessControl implements AccessControlInterface { // We only check unpublished vs published for "view" right now. If we ever // start supporting other operations, we need to remove the "view" check. $check_published = $operation === 'view' && $entity->getEntityType()->entityClassImplements(EntityPublishedInterface::class); $check_published = $operation === 'view' && $this->implementsPublishedInterface; // Check if the account is the owner and an owner permission is supported. $is_owner = FALSE; if ($entity->getEntityType()->entityClassImplements(EntityOwnerInterface::class)) { if ($this->implementsOwnerInterface) { $is_owner = $entity->getOwnerId() === $account->id(); } Loading Loading
src/Entity/Access/GroupAccessControlHandler.php +6 −1 Changes for src/Entity/Access/GroupAccessControlHandler.php: 6 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -119,7 +119,12 @@ class GroupAccessControlHandler extends EntityAccessControlHandler implements En return $access->addCacheableDependency($cacheability); } // @todo To be consistent with the rest of the module, return forbidden. // The Group module's ideology is that if you want to do something to a // group, you need Group to explicitly allow access or else the result will // be forbidden. Having said that, if we do not support an operation yet, // it's probably nicer to return neutral here. This way, any module that // exposes new operations will work as intended AND NOT HAVE GROUP ACCESS // CHECKS until Group specifically implements said operations. return AccessResult::neutral(); } Loading
src/Plugin/Group/RelationHandler/AccessControlInterface.php +13 −0 Changes for src/Plugin/Group/RelationHandler/AccessControlInterface.php: 13 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -12,6 +12,19 @@ use Drupal\group\Entity\GroupInterface; */ interface AccessControlInterface extends RelationHandlerInterface { /** * Checks whether an operation is supported for a given target. * * @param string $operation * The permission operation. Usually "create", "view", "update" or "delete". * @param string $target * The target of the operation. Can be 'relation' or 'entity'. * * @return bool * Whether the operation is supported. */ public function supportsOperation($operation, $target); /** * Checks access to an operation on the relation. * Loading
src/Plugin/Group/RelationHandler/AccessControlTrait.php +36 −0 Changes for src/Plugin/Group/RelationHandler/AccessControlTrait.php: 36 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -4,11 +4,13 @@ namespace Drupal\group\Plugin\Group\RelationHandler; use Drupal\Core\Access\AccessResult; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Session\AccountInterface; use Drupal\group\Access\GroupAccessResult; use Drupal\group\Entity\GroupContentInterface; use Drupal\group\Entity\GroupInterface; use Drupal\group\Plugin\Group\Relation\GroupRelationTypeInterface; use Drupal\user\EntityOwnerInterface; /** * Trait for group relation permission providers. Loading @@ -23,6 +25,27 @@ trait AccessControlTrait { init as traitInit; } /** * The entity type the plugin handler is for. * * @var \Drupal\Core\Entity\EntityTypeInterface */ protected $entityType; /** * Whether the target entity type implements the EntityOwnerInterface. * * @var bool */ protected $implementsOwnerInterface; /** * Whether the target entity type implements the EntityPublishedInterface. * * @var bool */ protected $implementsPublishedInterface; /** * The plugin's permission provider. * Loading @@ -35,9 +58,22 @@ trait AccessControlTrait { */ public function init($plugin_id, GroupRelationTypeInterface $group_relation_type) { $this->traitInit($plugin_id, $group_relation_type); $this->entityType = $this->entityTypeManager()->getDefinition($group_relation_type->getEntityTypeId()); $this->implementsOwnerInterface = $this->entityType->entityClassImplements(EntityOwnerInterface::class); $this->implementsPublishedInterface = $this->entityType->entityClassImplements(EntityPublishedInterface::class); $this->permissionProvider = $this->groupRelationTypeManager()->getPermissionProvider($plugin_id); } /** * {@inheritdoc} */ public function supportsOperation($operation, $target) { if (!isset($this->parent)) { throw new \LogicException('Using AccessControlTrait without assigning a parent or overwriting the methods.'); } return $this->parent->supportsOperation($operation, $target); } /** * {@inheritdoc} */ Loading
src/Plugin/Group/RelationHandler/PermissionProviderInterface.php +1 −1 Changes for src/Plugin/Group/RelationHandler/PermissionProviderInterface.php: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ interface PermissionProviderInterface extends RelationHandlerInterface { * Defaults to 'any'. * * @return string|false * The permission name or FALSE if it does not apply. * The permission name or FALSE if the combination is not supported. */ public function getPermission($operation, $target, $scope = 'any'); Loading
src/Plugin/Group/RelationHandlerDefault/AccessControl.php +36 −5 Changes for src/Plugin/Group/RelationHandlerDefault/AccessControl.php: 36 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -4,7 +4,6 @@ namespace Drupal\group\Plugin\Group\RelationHandlerDefault; use Drupal\Core\Access\AccessResult; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Session\AccountInterface; use Drupal\group\Access\GroupAccessResult; Loading @@ -13,7 +12,6 @@ use Drupal\group\Entity\GroupInterface; use Drupal\group\Plugin\Group\RelationHandler\AccessControlInterface; use Drupal\group\Plugin\Group\RelationHandler\AccessControlTrait; use Drupal\group\Plugin\Group\Relation\GroupRelationTypeManagerInterface; use Drupal\user\EntityOwnerInterface; /** * Provides access control for group relations. Loading @@ -35,6 +33,30 @@ class AccessControl implements AccessControlInterface { $this->groupRelationTypeManager = $groupRelationTypeManager; } /** * {@inheritdoc} */ public function supportsOperation($operation, $target) { assert(in_array($target, ['relation', 'entity'], TRUE), '$target must be either "relation" or "entity"'); $permissions = [$this->permissionProvider->getPermission($operation, $target, 'any')]; // We know relations have owners, but need to check for the target entity. // Please note that we do not check for "view" vs "view unpublished" here // because you usually can't have the latter without the former so a regular // check vs the passed in operation should suffice for most use cases. if ($target === 'relation' || $this->implementsOwnerInterface) { $permissions[] = $this->permissionProvider->getPermission($operation, $target, 'own'); } foreach ($permissions as $permission) { if ($permission !== FALSE) { return TRUE; } } return FALSE; } /** * {@inheritdoc} */ Loading Loading @@ -81,6 +103,16 @@ class AccessControl implements AccessControlInterface { * {@inheritdoc} */ public function entityAccess(EntityInterface $entity, $operation, AccountInterface $account, $return_as_object = FALSE) { // The Group module's ideology is that if you want to do something to a // group's content, you need Group to explicitly allow access or else the // result will be forbidden. Having said that, if we do not support an // operation yet, it's probably nicer to return neutral here. This way, any // module that exposes new operations will work as intended AND NOT HAVE // GROUP ACCESS CHECKS until Group specifically implements said operations. if (!$this->supportsOperation($operation, 'entity')) { return AccessResult::neutral(); } /** @var \Drupal\group\Entity\Storage\GroupContentStorageInterface $storage */ $storage = $this->entityTypeManager()->getStorage('group_content'); $group_contents = $storage->loadByEntity($entity); Loading @@ -100,12 +132,11 @@ class AccessControl implements AccessControlInterface { // We only check unpublished vs published for "view" right now. If we ever // start supporting other operations, we need to remove the "view" check. $check_published = $operation === 'view' && $entity->getEntityType()->entityClassImplements(EntityPublishedInterface::class); $check_published = $operation === 'view' && $this->implementsPublishedInterface; // Check if the account is the owner and an owner permission is supported. $is_owner = FALSE; if ($entity->getEntityType()->entityClassImplements(EntityOwnerInterface::class)) { if ($this->implementsOwnerInterface) { $is_owner = $entity->getOwnerId() === $account->id(); } Loading