diff --git a/README.md b/README.md index 40f45d29..e91a5bea 100644 --- a/README.md +++ b/README.md @@ -197,24 +197,30 @@ Collabora is used within Drupal. Most of the time this permission is not needed, if the Collabora instance is configured from outside of Drupal. -For each media type, the module introduces two permissions: -- (media type): Edit any media file in Collabora Users with this - permission are allowed to edit documents attached to a media entity - of the given type, using the Collabora Online editor. -- (media type): Preview media file in Collabora Users with this - permission are allowed to preview documents attached to a media - entity of the given type, using the Collabora Online editor in - preview/readonly mode. - -In the current version, preview and edit access with the Collabora -Online editor are checked independently of the publishing status of -the respective media, and independently of the regular view or edit -access on that media entity. - -For a consistent experience, it is recommended that a role with the -edit permission should also be granted the preview permission, and -that a user with any of the Collabora media permissions should also be -granted permissions to view the respective media entity in Drupal. +For each media type, the module introduces four permissions: +- "(media type): Edit any media file in Collabora" + Users with this permission are allowed to edit documents attached + to a media entity of the given type, using the Collabora Online + editor. +- "(media type): Edit own media file in Collabora" + Users with this permission are allowed to edit documents attached + to a media entity of the given type, using the Collabora Online + editor, if they are the owner/author of that media entity. +- "(media type): Preview published media file in Collabora" + Users with this permission are allowed to preview documents attached + to a published media entity of the given type, using the Collabora + Online editor in preview/readonly mode. +- "(media type): Preview own unpublished media file in Collabora" + Users with this permission are allowed to preview documents attached + to an unpublished media entity of the given type, using the Collabora Online + editor in preview/readonly mode. + +In the current version of this module, the 'administer media' permission +from Drupal core grants access to all media operations, including the use +of the Collabora Online editor for preview and edit. + +For a consistent experience, it is recommended that a role with edit +permissions should also be granted respective preview permissions. Developers can use entity access hooks to alter which users may edit or preview media files in Collabora. This would allow to grant access diff --git a/collabora_online.module b/collabora_online.module index 61662aad..580bd641 100644 --- a/collabora_online.module +++ b/collabora_online.module @@ -123,24 +123,59 @@ function collabora_online_entity_operation(EntityInterface $entity) { * Checks access for the new media operations provided by this module. */ function collabora_online_media_access(MediaInterface $media, string $operation, AccountInterface $account): AccessResultInterface { - $type = $media->bundle(); switch ($operation) { case 'preview in collabora': - return AccessResult::allowedIfHasPermission($account, "preview $type in collabora"); + $type = $media->bundle(); + if ($media->isPublished()) { + return AccessResult::allowedIfHasPermission($account, "preview $type in collabora") + ->addCacheableDependency($media); + } + $preview_own_permission = "preview own unpublished $type in collabora"; + if (!$account->hasPermission($preview_own_permission)) { + return AccessResult::neutral() + ->cachePerPermissions() + ->addCacheableDependency($media) + ->setReason("The user does not have the '$preview_own_permission' permission."); + } + // Use '==' because Drupal sometimes loads integers as strings. + $is_owner = ($account->id() && $account->id() == $media->getOwnerId()); + if ($is_owner) { + $access_result = AccessResult::allowed(); + } + else { + $access_result = AccessResult::neutral() + ->setReason("The user has the '$preview_own_permission' permission, but is not the owner of the media item."); + } + return $access_result + ->cachePerPermissions() + ->cachePerUser() + ->addCacheableDependency($media); case 'edit in collabora': + $type = $media->bundle(); if ($account->hasPermission("edit any $type in collabora")) { - return AccessResult::allowed()->cachePerPermissions(); + return AccessResult::allowed() + ->cachePerPermissions(); } - if ($account->hasPermission("edit own $type in collabora")) { - // Use '==' because Drupal sometimes loads integers as strings. - $is_owner = ($account->id() && $account->id() == $media->getOwnerId()); - return AccessResult::allowedIf($is_owner) + $edit_own_permission = "edit own $type in collabora"; + if (!$account->hasPermission($edit_own_permission)) { + return AccessResult::neutral() ->cachePerPermissions() - ->cachePerUser() - ->addCacheableDependency($media); + ->setReason("The user does not have the '$edit_own_permission' permission."); + } + // Use '==' because Drupal sometimes loads integers as strings. + $is_owner = ($account->id() && $account->id() == $media->getOwnerId()); + if (!$is_owner) { + $access_result = AccessResult::neutral() + ->setReason("The user has the '$edit_own_permission' permission, but is not the owner of the media item."); + } + else { + $access_result = AccessResult::allowed(); } - return AccessResult::neutral()->cachePerPermissions(); + return $access_result + ->cachePerPermissions() + ->cachePerUser() + ->addCacheableDependency($media); default: return AccessResult::neutral(); diff --git a/src/CollaboraMediaPermissions.php b/src/CollaboraMediaPermissions.php index 956948d5..2eecaf31 100644 --- a/src/CollaboraMediaPermissions.php +++ b/src/CollaboraMediaPermissions.php @@ -77,7 +77,10 @@ protected function buildPermissions(MediaTypeInterface $type) { return [ "preview $type_id in collabora" => [ - 'title' => $this->t('%type_name: Preview media file in Collabora', $type_params), + 'title' => $this->t('%type_name: Preview published media file in Collabora', $type_params), + ], + "preview own unpublished $type_id in collabora" => [ + 'title' => $this->t('%type_name: Preview own unpublished media file in Collabora', $type_params), ], "edit own $type_id in collabora" => [ 'title' => $this->t('%type_name: Edit own media file in Collabora', $type_params), diff --git a/tests/src/Functional/PermissionTest.php b/tests/src/Functional/PermissionTest.php index 4023bc1a..2c1f2f29 100644 --- a/tests/src/Functional/PermissionTest.php +++ b/tests/src/Functional/PermissionTest.php @@ -80,8 +80,12 @@ static function (array $permission) { 'title' => 'Public wiki: Edit own media file in Collabora', 'dependencies' => ['config' => ['media.type.public_wiki']], ], + 'preview own unpublished public_wiki in collabora' => [ + 'title' => 'Public wiki: Preview own unpublished media file in Collabora', + 'dependencies' => ['config' => ['media.type.public_wiki']], + ], 'preview public_wiki in collabora' => [ - 'title' => 'Public wiki: Preview media file in Collabora', + 'title' => 'Public wiki: Preview published media file in Collabora', 'dependencies' => ['config' => ['media.type.public_wiki']], ], ], $permissions); diff --git a/tests/src/Kernel/CollaboraMediaAccessTest.php b/tests/src/Kernel/CollaboraMediaAccessTest.php index a9368250..befcb806 100644 --- a/tests/src/Kernel/CollaboraMediaAccessTest.php +++ b/tests/src/Kernel/CollaboraMediaAccessTest.php @@ -86,12 +86,16 @@ public function testCollaboraMediaAccess(): void { // Permissions for 'book' do not grant access to 'document'. 'Bookworm' => $this->createUser([ 'preview book in collabora', + 'preview own unpublished book in collabora', 'edit any book in collabora', 'edit own book in collabora', ]), 'Previewer' => $this->createUser([ 'preview document in collabora', ]), + 'Sean (preview own)' => $this->createUser([ + 'preview own unpublished document in collabora', + ]), 'Editor' => $this->createUser([ 'edit any document in collabora', ]), @@ -105,8 +109,11 @@ public function testCollaboraMediaAccess(): void { /** @var \Drupal\media\MediaInterface[] $media_entities */ $media_entities = [ - 'published document' => $this->createMediaEntity('document'), - 'unpublished document' => $this->createMediaEntity('document', [ + "Sean's published document" => $this->createMediaEntity('document', [ + 'uid' => $accounts['Sean (preview own)']->id(), + ]), + "Sean's unpublished document" => $this->createMediaEntity('document', [ + 'uid' => $accounts['Sean (preview own)']->id(), 'status' => 0, ]), "Kelly's published document" => $this->createMediaEntity('document', [ @@ -125,14 +132,15 @@ public function testCollaboraMediaAccess(): void { 'media permissions only' => [], 'Bookworm' => [], 'Previewer' => [ - "published document" => ['preview in collabora'], - "unpublished document" => ['preview in collabora'], + "Sean's published document" => ['preview in collabora'], "Kelly's published document" => ['preview in collabora'], - "Kelly's unpublished document" => ['preview in collabora'], + ], + 'Sean (preview own)' => [ + "Sean's unpublished document" => ['preview in collabora'], ], 'Editor' => [ - "published document" => ['edit in collabora'], - "unpublished document" => ['edit in collabora'], + "Sean's published document" => ['edit in collabora'], + "Sean's unpublished document" => ['edit in collabora'], "Kelly's published document" => ['edit in collabora'], "Kelly's unpublished document" => ['edit in collabora'], ], @@ -141,8 +149,8 @@ public function testCollaboraMediaAccess(): void { "Kelly's unpublished document" => ['edit in collabora'], ], 'Media admin' => [ - "published document" => ['preview in collabora', 'edit in collabora'], - "unpublished document" => ['preview in collabora', 'edit in collabora'], + "Sean's published document" => ['preview in collabora', 'edit in collabora'], + "Sean's unpublished document" => ['preview in collabora', 'edit in collabora'], "Kelly's published document" => ['preview in collabora', 'edit in collabora'], "Kelly's unpublished document" => ['preview in collabora', 'edit in collabora'], ], @@ -162,14 +170,15 @@ public function testCollaboraMediaAccess(): void { 'media permissions only' => [], 'Bookworm' => [], 'Previewer' => [ - "/cool/view/", - "/cool/view/", + "/cool/view/", "/cool/view/", - "/cool/view/", + ], + 'Sean (preview own)' => [ + "/cool/view/", ], 'Editor' => [ - "/cool/edit/", - "/cool/edit/", + "/cool/edit/", + "/cool/edit/", "/cool/edit/", "/cool/edit/", ], @@ -178,10 +187,10 @@ public function testCollaboraMediaAccess(): void { "/cool/edit/", ], 'Media admin' => [ - "/cool/view/", - "/cool/edit/", - "/cool/view/", - "/cool/edit/", + "/cool/view/", + "/cool/edit/", + "/cool/view/", + "/cool/edit/", "/cool/view/", "/cool/edit/", "/cool/view/", @@ -202,6 +211,7 @@ public function testCollaboraMediaAccess(): void { */ public function testAnonymousOwnAccess(): void { user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, [ + 'preview own unpublished document in collabora', 'edit own document in collabora', ]); @@ -253,9 +263,9 @@ public function testAnonymousOwnAccess(): void { [ 'anonymous' => [ "published document" => ['preview in collabora', 'edit in collabora'], - "unpublished document" => ['preview in collabora', 'edit in collabora'], + "unpublished document" => ['edit in collabora'], "Emilia's published document" => ['preview in collabora', 'edit in collabora'], - "Emilia's unpublished document" => ['preview in collabora', 'edit in collabora'], + "Emilia's unpublished document" => ['edit in collabora'], ], 'Emilia' => [], ], diff --git a/tests/src/Kernel/PermissionTest.php b/tests/src/Kernel/PermissionTest.php index b8004b1e..20f9739a 100644 --- a/tests/src/Kernel/PermissionTest.php +++ b/tests/src/Kernel/PermissionTest.php @@ -96,8 +96,12 @@ static function (array $permission) { 'title' => 'Public wiki: Edit own media file in Collabora', 'dependencies' => ['config' => ['media.type.public_wiki']], ], + 'preview own unpublished public_wiki in collabora' => [ + 'title' => 'Public wiki: Preview own unpublished media file in Collabora', + 'dependencies' => ['config' => ['media.type.public_wiki']], + ], 'preview public_wiki in collabora' => [ - 'title' => 'Public wiki: Preview media file in Collabora', + 'title' => 'Public wiki: Preview published media file in Collabora', 'dependencies' => ['config' => ['media.type.public_wiki']], ], ], $permissions);