Skip to content
This repository has been archived by the owner on Aug 18, 2024. It is now read-only.

Commit

Permalink
Merge branch '8.x-1.x' into feature/160-remove-complex-widget
Browse files Browse the repository at this point in the history
  • Loading branch information
MPParsley authored Aug 3, 2020
2 parents 9cc2202 + 8029b4b commit 1ea6272
Show file tree
Hide file tree
Showing 13 changed files with 174 additions and 283 deletions.
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ matrix:
env: TEST_SUITE=PHP_CodeSniffer
- php: 7.4
env: TEST_SUITE=PHP_CodeSniffer
allow_failures:
- php: 7.4

mysql:
database: og
Expand Down Expand Up @@ -71,6 +69,9 @@ before_script:
# Install Composer dependencies for core. Skip this for the coding standards test.
- test ${TEST_SUITE} == "PHP_CodeSniffer" || composer install --working-dir=$DRUPAL_DIR

# Update PHPUnit.
- test ${TEST_SUITE} == "PHP_CodeSniffer" || travis_retry composer update phpunit/phpunit symfony/phpunit-bridge phpspec/prophecy symfony/yaml --with-dependencies --working-dir=$DRUPAL_DIR

# Start a web server on port 8888 in the background.
- test ${TEST_SUITE} == "PHP_CodeSniffer" || nohup php -S localhost:8888 --docroot $DRUPAL_DIR > /dev/null 2>&1 &

Expand Down
2 changes: 1 addition & 1 deletion og.module
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ function og_entity_access(EntityInterface $entity, $operation, AccountInterface
}

/** @var \Drupal\Core\Access\AccessResult $access */
$access = \Drupal::service('og.access')->userAccessEntity($operation, $entity, $account);
$access = \Drupal::service('og.access')->userAccessEntityOperation($operation, $entity, $account);

$audience_fields = \Drupal::service('og.group_audience_helper')->getAllGroupAudienceFields($entity_type_id, $bundle_id);
if (count($audience_fields) === 1) {
Expand Down
7 changes: 1 addition & 6 deletions og.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,7 @@ services:
- { name: 'cache.context'}
og.access:
class: Drupal\og\OgAccess
arguments: ['@config.factory', '@current_user', '@module_handler', '@og.group_type_manager', '@og.permission_manager', '@og.membership_manager', '@og.group_audience_helper']
og.add_field:
class: Drupal\og\Command\OgAddFieldCommand
arguments: ['@entity_type.bundle.info', '@entity_type.repository', '@plugin.manager.og.fields']
tags:
- { name: drupal.command }
arguments: ['@config.factory', '@current_user', '@module_handler', '@og.group_type_manager', '@og.permission_manager', '@og.membership_manager']
og.context:
class: Drupal\og\ContextProvider\OgContext
arguments: ['@plugin.manager.og.group_resolver', '@config.factory']
Expand Down
2 changes: 1 addition & 1 deletion src/EventSubscriber/OgEventSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public function provideDefaultOgPermissions(PermissionEventInterface $event) {
new GroupPermission([
'name' => OgAccess::UPDATE_GROUP_PERMISSION,
'title' => $this->t('Edit group'),
'description' => $this->t('Edit the group. Note: This permission controls only node entity type groups.'),
'description' => $this->t('Edit the group entity.'),
'default roles' => [OgRoleInterface::ADMINISTRATOR],
]),
new GroupPermission([
Expand Down
4 changes: 1 addition & 3 deletions src/Og.php
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,6 @@ public static function isGroup($entity_type_id, $bundle_id) {
/**
* Check if the given entity type and bundle is a group content.
*
* This works by checking if the bundle has one or more group audience fields.
*
* @param string $entity_type_id
* The entity type.
* @param string $bundle_id
Expand All @@ -271,7 +269,7 @@ public static function isGroup($entity_type_id, $bundle_id) {
* True or false if the given entity is group content.
*/
public static function isGroupContent($entity_type_id, $bundle_id) {
return \Drupal::service('og.group_audience_helper')->hasGroupAudienceField($entity_type_id, $bundle_id);
return \Drupal::service('og.group_type_manager')->isGroupContent($entity_type_id, $bundle_id);
}

/**
Expand Down
126 changes: 82 additions & 44 deletions src/OgAccess.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

namespace Drupal\og;

use Drupal\Core\Access\AccessResult;
Expand Down Expand Up @@ -32,6 +34,13 @@ class OgAccess implements OgAccessInterface {
*/
const UPDATE_GROUP_PERMISSION = 'update group';

/**
* Maps entity operations performed on groups to group level permissions.
*/
const OPERATION_GROUP_PERMISSION_MAPPING = [
'update' => self::UPDATE_GROUP_PERMISSION,
];

/**
* The config factory.
*
Expand Down Expand Up @@ -75,14 +84,7 @@ class OgAccess implements OgAccessInterface {
protected $membershipManager;

/**
* The OG group audience helper.
*
* @var \Drupal\og\OgGroupAudienceHelperInterface
*/
protected $groupAudienceHelper;

/**
* Constructs an OgManager service.
* Constructs the OgAccess service.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
Expand All @@ -96,23 +98,20 @@ class OgAccess implements OgAccessInterface {
* The permission manager.
* @param \Drupal\og\MembershipManagerInterface $membership_manager
* The group membership manager.
* @param \Drupal\og\OgGroupAudienceHelperInterface $group_audience_helper
* The OG group audience helper.
*/
public function __construct(ConfigFactoryInterface $config_factory, AccountProxyInterface $account_proxy, ModuleHandlerInterface $module_handler, GroupTypeManagerInterface $group_manager, PermissionManagerInterface $permission_manager, MembershipManagerInterface $membership_manager, OgGroupAudienceHelperInterface $group_audience_helper) {
public function __construct(ConfigFactoryInterface $config_factory, AccountProxyInterface $account_proxy, ModuleHandlerInterface $module_handler, GroupTypeManagerInterface $group_manager, PermissionManagerInterface $permission_manager, MembershipManagerInterface $membership_manager) {
$this->configFactory = $config_factory;
$this->accountProxy = $account_proxy;
$this->moduleHandler = $module_handler;
$this->groupTypeManager = $group_manager;
$this->permissionManager = $permission_manager;
$this->membershipManager = $membership_manager;
$this->groupAudienceHelper = $group_audience_helper;
}

/**
* {@inheritdoc}
*/
public function userAccess(EntityInterface $group, $operation, AccountInterface $user = NULL, $skip_alter = FALSE): AccessResultInterface {
public function userAccess(EntityInterface $group, string $permission, AccountInterface $user = NULL, bool $skip_alter = FALSE): AccessResultInterface {
$group_type_id = $group->getEntityTypeId();
$bundle = $group->bundle();
// As Og::isGroup depends on this config, we retrieve it here and set it as
Expand Down Expand Up @@ -151,14 +150,6 @@ public function userAccess(EntityInterface $group, $operation, AccountInterface
return $user_access->addCacheableDependency($cacheable_metadata);
}

// Update group special permission. At this point, the operation should have
// already been handled by Og. If the operation is simply 'edit'
// (or 'update' for content entities), it is referring to the current group,
// so we have to map it to the special permission.
if (in_array($operation, ['update', 'edit'])) {
$operation = OgAccess::UPDATE_GROUP_PERMISSION;
}

if ($config->get('group_manager_full_access') && $user->isAuthenticated() && $group instanceof EntityOwnerInterface) {
$cacheable_metadata->addCacheableDependency($group);
if ($group->getOwnerId() == $user->id()) {
Expand Down Expand Up @@ -188,10 +179,10 @@ public function userAccess(EntityInterface $group, $operation, AccountInterface

$permissions = array_unique($permissions);

if (!$skip_alter && !in_array($operation, $permissions)) {
if (!$skip_alter && !in_array($permission, $permissions)) {
// Let modules alter the permissions.
$context = [
'operation' => $operation,
'permission' => $permission,
'group' => $group,
'user' => $user,
];
Expand All @@ -202,7 +193,7 @@ public function userAccess(EntityInterface $group, $operation, AccountInterface
// permissions.
// @todo It should be possible for modules to alter the permissions even if
// the user is a group admin, UID 1 or has 'administer group' permission.
if ($user_is_group_admin || in_array($operation, $permissions)) {
if ($user_is_group_admin || in_array($permission, $permissions)) {
// User is a group admin, and we do not ignore this special permission
// that grants access to all the group permissions.
return AccessResult::allowed()->addCacheableDependency($cacheable_metadata);
Expand All @@ -214,30 +205,29 @@ public function userAccess(EntityInterface $group, $operation, AccountInterface
/**
* {@inheritdoc}
*/
public function userAccessEntity($operation, EntityInterface $entity, AccountInterface $user = NULL): AccessResultInterface {
public function userAccessEntity(string $permission, EntityInterface $entity, AccountInterface $user = NULL): AccessResultInterface {
$result = AccessResult::neutral();

$entity_type = $entity->getEntityType();
$entity_type_id = $entity_type->id();
$bundle = $entity->bundle();

if ($this->groupTypeManager->isGroup($entity_type_id, $bundle)) {
$user_access = $this->userAccess($entity, $operation, $user);
$user_access = $this->userAccess($entity, $permission, $user);
if ($user_access->isAllowed()) {
return $user_access;
}
else {
// An entity can be a group and group content in the same time. The
// group didn't allow access, but the user still might have access to
// the permission in group content context. So instead of retuning a
// the permission in group content context. So instead of returning a
// deny here, we set the result, that might change if an access is
// found.
$result = AccessResult::forbidden()->inheritCacheability($user_access);
}
}

$is_group_content = $this->groupAudienceHelper->hasGroupAudienceField($entity_type_id, $bundle);
if ($is_group_content) {
if ($this->groupTypeManager->isGroupContent($entity_type_id, $bundle)) {
$cache_tags = $entity_type->getListCacheTags();

// The entity might be a user or a non-user entity.
Expand All @@ -247,17 +237,7 @@ public function userAccessEntity($operation, EntityInterface $entity, AccountInt
$forbidden = AccessResult::forbidden()->addCacheTags($cache_tags);
foreach ($groups as $entity_groups) {
foreach ($entity_groups as $group) {
// Check if the operation matches a group content entity operation
// such as 'create article content'.
$operation_access = $this->userAccessGroupContentEntityOperation($operation, $group, $entity, $user);

if ($operation_access->isAllowed()) {
return $operation_access->addCacheTags($cache_tags);
}

// Check if the operation matches a group level operation such as
// 'subscribe without approval'.
$user_access = $this->userAccess($group, $operation, $user);
$user_access = $this->userAccess($group, $permission, $user);
if ($user_access->isAllowed()) {
return $user_access->addCacheTags($cache_tags);
}
Expand All @@ -271,15 +251,73 @@ public function userAccessEntity($operation, EntityInterface $entity, AccountInt
$result->addCacheTags($cache_tags);
}

// Either the user didn't have permission, or the entity might be an
// orphaned group content.
// Either the user didn't have permission, or the entity might be orphaned
// group content.
return $result;
}

/**
* {@inheritdoc}
*/
public function userAccessEntityOperation(string $operation, EntityInterface $entity, AccountInterface $user = NULL): AccessResultInterface {
$result = AccessResult::neutral();

$entity_type = $entity->getEntityType();
$entity_type_id = $entity_type->id();
$bundle = $entity->bundle();

if ($this->groupTypeManager->isGroup($entity_type_id, $bundle)) {
// We are performing an entity operation on a group entity. Map the
// operation to the corresponding group level permission.
if (array_key_exists($operation, self::OPERATION_GROUP_PERMISSION_MAPPING)) {
$permission = self::OPERATION_GROUP_PERMISSION_MAPPING[$operation];

$user_access = $this->userAccess($entity, $permission, $user);
if ($user_access->isAllowed()) {
return $user_access;
}
else {
// An entity can be a group and group content in the same time. The
// group permission check didn't allow access, but the user still
// might have access to perform the operation in group content
// context. So instead of returning a deny here, we set the result,
// that might change if an access is found.
$result = AccessResult::forbidden()->inheritCacheability($user_access);
}
}
}

if ($this->groupTypeManager->isGroupContent($entity_type_id, $bundle)) {
$cache_tags = $entity_type->getListCacheTags();

// The entity might be a user or a non-user entity.
$groups = $entity instanceof UserInterface ? $this->membershipManager->getUserGroups($entity->id()) : $this->membershipManager->getGroups($entity);

if ($groups) {
$forbidden = AccessResult::forbidden()->addCacheTags($cache_tags);
foreach ($groups as $entity_groups) {
foreach ($entity_groups as $group) {
$operation_access = $this->userAccessGroupContentEntityOperation($operation, $group, $entity, $user);
if ($operation_access->isAllowed()) {
return $operation_access->addCacheTags($cache_tags);
}
}
}
return $forbidden;
}

$result->addCacheTags($cache_tags);
}

// Either the user didn't have permission, or the entity might be orphaned
// group content.
return $result;
}

/**
* {@inheritdoc}
*/
public function userAccessGroupContentEntityOperation($operation, EntityInterface $group_entity, EntityInterface $group_content_entity, AccountInterface $user = NULL): AccessResultInterface {
public function userAccessGroupContentEntityOperation(string $operation, EntityInterface $group_entity, EntityInterface $group_content_entity, AccountInterface $user = NULL): AccessResultInterface {
// Default to the current user.
$user = $user ?: $this->accountProxy->getAccount();

Expand Down Expand Up @@ -329,7 +367,7 @@ public function userAccessGroupContentEntityOperation($operation, EntityInterfac
* {@inheritdoc}
*/
public function reset(): void {
trigger_error('OgAccessInterface::reset() is deprecated in og:8.1.0-alpha6 and is removed from og:8.1.0-beta1. The static cache has been removed and this no longer server any purpose. See https://github.com/Gizra/og/issues/654', E_USER_DEPRECATED);
trigger_error('OgAccessInterface::reset() is deprecated in og:8.1.0-alpha6 and is removed from og:8.1.0-beta1. The static cache has been removed and this method no longer serves any purpose. Any calls to this method can safely be removed. See https://github.com/Gizra/og/issues/654', E_USER_DEPRECATED);
}

}
Loading

0 comments on commit 1ea6272

Please sign in to comment.