Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check group content entity operation access #217

Merged
merged 98 commits into from
Aug 6, 2016

Conversation

pfrenssen
Copy link
Collaborator

This is a followup for #192. Now that we can assign default roles to users which are populated with a set of default permissions for doing CRUD operations on group content, we should use these when checking access.

This PR will e.g. allow members to edit nodes in a group if they have the OG permission "edit any node_type node".

@pfrenssen
Copy link
Collaborator Author

This builds on #192 so it contains all that code. The actual implementation is in the last commit 6aca08c.

This still needs tests.

}

// @todo Also deal with the use case that CRUD operations are granted to
// non-members.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the moment to get OG permissions we get them from the OgMembership object. It's probably a good idea to make some specific helper methods to retrieve the set of OG permissions for group content for a particular user, whether they are member or not.

@pfrenssen pfrenssen self-assigned this May 27, 2016
@pfrenssen pfrenssen changed the title Check group content crud access WIP: Check group content crud access Jun 2, 2016
return [
[FALSE, $default_permissions],
[TRUE, $default_permissions + $group_content_permissions],
];
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed that this test is wrong, we should use array_merge() instead of the array union operator + for indexed arrays. If I fix this the test fails. The group content permissions are not added :(

@pfrenssen
Copy link
Collaborator Author

I'm using static methods because I'm following the established pattern, but this is now going to break the unit tests again, since I am statically calling the PermissionManager service. This is going to require some trickery again to make the tests pass :(

@pfrenssen
Copy link
Collaborator Author

I have converted OgAccess into a service in #226. This solves the problem with the unit tests.

Merging this was a bit awkward, I'm going to rebase this branch on top of #226 so that the commit progression is more logical.

@pfrenssen pfrenssen force-pushed the check-group-content-crud-access branch from 49f1561 to 78fbae2 Compare June 9, 2016 13:55
@amitaibu
Copy link
Owner

This will require a re-roll

@pfrenssen
Copy link
Collaborator Author

Picking this back up, will first merge in latest changes and try to get a green test run, then I'll have a look to make a list of what still needs to be done here.

@pfrenssen
Copy link
Collaborator Author

I am thinking how we can best provide the entity operation permissions.

We have two types of permissions:

  1. "Group level permissions", such as 'subscribe without approval' and 'manage users'. These are currently provided by the PermissionEvent subscribers.
  2. "Entity operation level permissions" on group content, so that we can allow members to create and edit group content.

In D7 we only supplied a hard coded set of permissions for the Node module, but in D8's everything-is-an-entity world we should extend this to all entities. A good example use case is the OG Menu module, in which each menu is group content type of the custom OgMenuInstance entity. In order to allow certain group roles to create or edit OG Menus we need know that OG Menu exposes this entity type, and that it supports certain operations on it.

In core we don't have this information currently (ref. #222). We need to retrieve it somehow, through a hook or event listener.

I am now thinking of extending the current PermissionEvent to handle both the group level and entity operation level permissions. This seems better from a DX perspective, so that modules don't need to implement two subscribers to declare a set of permissions.

The problem with the entity operation permissions in Drupal is that there is no formal framework, and the permissions are based on human language. A good example is the basic 'edit own article content' permission - neither the operation ('update') or the entity type ('node') are even mentioned in the permission, it's impossile to parse the needed information out of it.

So we need to be able to associate a permission with an operation, and with an entity type and bundle. We also need to distinguish between a user having permission to operate on their own content, or on all content: ('edit own article content' vs 'edit any article content'). We also need the machine name and the title.

It seems like it would be a good idea to use a class for this, so something like the 'edit any article content' can be provided in the permission subscriber using a new method like setEntityOperationPermission():

  public function provideDefaultOgPermissions(PermissionEventInterface $event) {
    $permission = new EntityOperationPermission();
    $permission
      ->setName('edit any article content')
      ->setTitle(t('Article: edit any content'))
      ->setDescription(t('Allows to edit any node of type article'))
      ->setEntityType('node')
      ->setBundle('article')
      ->setOwnership('any')
      ->setOperation('update');
    $event->setEntityOperationPermission($permission);

    // Here is an example of a normal group-level permission being set in the
    // same event subscriber.
    $event->setPermissions([
      'administer group' => [
        'title' => t('Administer group'),
        'description' => t('Manage group members and content in the group.'),
        'default roles' => [OgRoleInterface::ADMINISTRATOR],
        'restrict access' => TRUE,
      ],
    ]);
  }

For basic CRUD operations we can supply all permissions out of the box with generic wording such as update own $bundle_id $entity_type_id. We can then allow modules to alter this if the generic wording is not to their liking.

@pfrenssen
Copy link
Collaborator Author

On second thought, I'm going to use an array structure for the moment to pass the data, to be consistent with the group level permissions. This would make it a lot less work to implement. We can later on still make an object to store the permissions.

If we do it like this we don't even need two separate methods, we can pass everything in the same method, and distinguish between the two if the 'operation' key is present.

So the example implementation above would instead look like this:

  public function provideDefaultOgPermissions(PermissionEventInterface $event) {
    $event->setPermissions([
      // Example entity operation type permission.
      'edit any article content' => [
        'title' => t('Article: edit any content'),
        'description' => t('Allows to edit any node of type article'),
        'entity type' => 'node',
        'bundle' => 'article',
        'ownership' => 'any',
        'operation' => 'update',
      ],

      // Example group-level type permission.
      'administer group' => [
        'title' => t('Administer group'),
        'description' => t('Manage group members and content in the group.'),
        'default roles' => [OgRoleInterface::ADMINISTRATOR],
        'restrict access' => TRUE,
      ],
    ]);
  }

@amitaibu
Copy link
Owner

This should be split into two methods. One is declaring the permissions that might be used. And the second is the permissions associated with a certain role.

(As you could have a role with no permissions at all)

@amitaibu
Copy link
Owner

Also my thoughts for providing default roles is that we maybe should pass a partially applied OgRole instead of the array.

And when we create the roles we just need to fill in the group type and bundle/group I'd

@pfrenssen
Copy link
Collaborator Author

I'm ready with this! I have addressed all the remarks (I think :) )

* @return \Drupal\og\OgRoleInterface|null
* The OG role object, or NULL if a matching role was not found.
*/
public static function getRole($entity_type_id, $bundle, $role_name) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As indicated in another comment getRole should still remain (although we can move it to OgRole itself ) as You may want to set the role's permissions before any group as actually created

Also, just as a heads up, the entire OgRole will still undergo changes, once we'll have to introduce the concept of OgRolePerBundle and OgRolePerGroup (as we have in OG7)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK will restore it! I will make a followup to move it to OgRole, because it will need some discussion about the correct naming of the function. Burying this in here will cause it to be missed by everyone who is involved in OG atm.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Followup: #292

@amitaibu
Copy link
Owner

amitaibu commented Aug 5, 2016

Thanks for keeping up the good work!

Made comments about the "dummy non-member memberships" (dnmm in short 😜).
(Also it will need a re-roll)

@pfrenssen
Copy link
Collaborator Author

Addressed the remarks, rerolled, and tests are green :)

OgMembershipInterface::STATE_BLOCKED,
];
if ($membership = Og::getMembership($group, $user, $states)) {
// Blocked users don't have any permissions.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@amitaibu amitaibu merged commit 371abcb into 8.x-1.x Aug 6, 2016
@amitaibu amitaibu deleted the check-group-content-crud-access branch August 6, 2016 10:35
@amitaibu
Copy link
Owner

amitaibu commented Aug 6, 2016

Wonderful, thanks!

@pfrenssen
Copy link
Collaborator Author

Woohoo!! Thanks a lot!!

amitaibu added a commit that referenced this pull request Nov 23, 2016
Clear static caches after a group or group content entity is deleted
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants