Gizra / og

https://www.drupal.org/project/og

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Is access handler class meant to be working this way?

idimopoulos opened this issue · comments

Hello, this is possibly a question rather than an issue.

What happens with group content?

When I have a group content entity, e.g. $child, and I have defined a GroupContentOperationPermission e.g. do some stuff in my subscriber, I can properly call $child->access('do some stuff), and this will call the access handler, which will call the og_entity_access hook, which will call eventually \Drupal\og\OgAccess::userAccessEntityOperation and that will call \Drupal\og\OgAccess::userAccessGroupContentEntityOperation which will normally check all operations created, including the do some stuff

What happens in groups?

On the other side - this is where my problem lies - when it comes to groups, I have created a \Drupal\og\GroupPermission through a subscriber. For the $group group, I expect that calling $group->access('do some stuff') should have the same effect. However, it does not. After going through the og_entity_access and into the \Drupal\og\OgAccess::userAccessEntityOperation where the following check takes place:

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];

        // An entity can be a group and group content in the same time. If the
        // group returns a neutral result the user still might have access to
        // the permission in group content context. So if we get a neutral result
        // we will continue with the group content access check below.
        $result = $this->userAccess($entity, $permission, $user);   

In that part, the operation is indeed do some stuff but the self::OPERATION_GROUP_PERMISSION_MAPPING only contains the delete and update mappings and thus never reaches the ::userAccess method so it never succeeds.

Is that normal? am i missing something here? It is very easy to reproduce this using a test I guess but I wanted to make sure that I am not doing something wrong first.

Changing the above to

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.
      $permission = array_key_exists($operation, self::OPERATION_GROUP_PERMISSION_MAPPING)
        ? self::OPERATION_GROUP_PERMISSION_MAPPING[$operation]
        : $operation;

      // An entity can be a group and group content in the same time. If the
      // group returns a neutral result the user still might have access to
      // the permission in group content context. So if we get a neutral result
      // we will continue with the group content access check below.
      $result = $this->userAccess($entity, $permission, $user);
      if (!$result->isNeutral()) {
        return $result;
      }
    }

actually fixed my issue and it seems to me like it is normal since the mapping mainly creates a translation from the CRUD operations update and delete to update group and delete group respectively.

It seems you are mixing up permissions and CRUD operation access checks, it doesn't make sense to call $group->access('do some stuff'), the only operations that are supported by OG are update and delete. We don't consider view access (also not in the D7 version of OG if I am not mistaken), and create access is handled differently in core (through hook_entity_create_access()).

It looks to me that do some stuff is the name of a permission. If you want to check if a user has a certain group permission, then use OgAccess::userAccess() which allows to pass in a permission name.

It is still a bit weird to me however I created a test and managed to get it a bit straight. In my case, I had some very specific cases so the operation was the same as the permission name.
The test proved that it is indeed working fine. The ::userAccessEntity is the correct way to go. I have discussed this with @pfrenssen in chat as well and it seems that indeed, custom operations with custom permissions should have custom handling in code, either access hook or handler.
Maybe it should be mentioned somewhere though.