diff --git a/collabora_online.views.inc b/collabora_online.views.inc new file mode 100644 index 00000000..1e3d8302 --- /dev/null +++ b/collabora_online.views.inc @@ -0,0 +1,23 @@ + t('Link to view in Collabora Online'), + 'group' => t('Media'), + 'field' => [ + 'id' => 'media_collabora_preview', + ], + ]; + $data['media']['collabora_edit'] = [ + 'title' => t('Link to edit in Collabora Online'), + 'group' => t('Media'), + 'field' => [ + 'id' => 'media_collabora_edit', + ], + ]; +} diff --git a/config/schema/collabora_online.schema.yml b/config/schema/collabora_online.schema.yml index 963dd305..9b2093ea 100644 --- a/config/schema/collabora_online.schema.yml +++ b/config/schema/collabora_online.schema.yml @@ -24,3 +24,15 @@ collabora_online.settings: allowfullscreen: type: boolean label: 'Allow full-screen.' + +views.field.media_collabora_preview: + type: views_field + label: 'Collabora view link' + mapping: + text: + type: label + label: 'Text to display' + +views.field.media_collabora_edit: + type: views.field.media_collabora_preview + label: 'Collabora edit link' diff --git a/modules/collabora_online_group/collabora_online_group.install b/modules/collabora_online_group/collabora_online_group.install new file mode 100644 index 00000000..8ec5580b --- /dev/null +++ b/modules/collabora_online_group/collabora_online_group.install @@ -0,0 +1,56 @@ +moduleExists('views') || + !($view = View::load('group_media')) + ) { + return; + } + + // Load display and apply changes. + $display = &$view->getDisplay('default'); + if ($display === NULL) { + return; + } + + // Add new fields to the display. + $display['display_options']['fields'] += [ + 'collabora_preview' => [ + 'id' => 'collabora_preview', + 'table' => 'media', + 'field' => 'collabora_preview', + 'plugin_id' => 'media_collabora_preview', + 'label' => '', + 'exclude' => TRUE, + 'text' => t('View in Collabora Online'), + ], + ]; + $display['display_options']['fields'] += [ + 'collabora_edit' => [ + 'id' => 'collabora_edit', + 'table' => 'media', + 'field' => 'collabora_edit', + 'plugin_id' => 'media_collabora_edit', + 'label' => '', + 'exclude' => TRUE, + 'text' => t('Edit in Collabora Online'), + ], + ]; + // Add new fields as options for the dropbutton and move the element to the end. + $dropbutton = $display['display_options']['fields']['dropbutton']; + $dropbutton['fields'] += [ + 'collabora_preview' => 'collabora_preview', + 'collabora_edit' => 'collabora_edit', + ]; + unset($display['display_options']['fields']['dropbutton']); + $display['display_options']['fields']['dropbutton'] = $dropbutton; + + $view->save(); +} diff --git a/modules/collabora_online_group/tests/src/Functional/GroupMediaViewsTest.php b/modules/collabora_online_group/tests/src/Functional/GroupMediaViewsTest.php new file mode 100644 index 00000000..b574ba74 --- /dev/null +++ b/modules/collabora_online_group/tests/src/Functional/GroupMediaViewsTest.php @@ -0,0 +1,146 @@ +createGroupType(['id' => 'group_type_1']); + $this->createMediaType('file', [ + 'id' => 'document', + 'label' => 'Document', + ]); + $this->createGroupRole([ + 'group_type' => 'group_type_1', + 'scope' => PermissionScopeInterface::INSIDER_ID, + 'global_role' => RoleInterface::AUTHENTICATED_ID, + 'permissions' => [ + 'view group', + 'access group_media overview', + 'view group_media:document entity', + 'edit any group_media:document in collabora', + 'preview group_media:document in collabora', + ], + ]); + $this->createPluginRelation($group_type, 'group_media:document', [ + 'group_cardinality' => 0, + 'entity_cardinality' => 1, + 'use_creation_wizard' => FALSE, + ]); + + // Create content. + $group = $this->createGroup(['type' => 'group_type_1']); + for ($i = 0; $i < 3; $i++) { + $media = $this->createMediaEntity('document', [ + 'id' => 'media_' . $i, + 'name' => 'Media ' . $i, + ]); + $group->addRelationship($media, 'group_media:document'); + } + $user = $this->createUser([ + 'view the administration theme', + 'access administration pages', + 'access group overview', + ]); + $group->addMember($user); + + // Go to the page and check the links added to the view. + $this->drupalLogin($user); + $this->drupalGet("group/{$group->id()}/media"); + $assert_session = $this->assertSession(); + + // Check table header. + $table = $assert_session->elementExists('css', 'table'); + $table_header = $assert_session->elementExists('css', 'thead', $table); + $rows = $table_header->findAll('css', 'tr'); + $cols = $rows[0]->findAll('css', 'th'); + $this->assertEquals('Media name', $cols[0]->getText()); + $this->assertEquals('Bundle', $cols[1]->getText()); + $this->assertEquals('Status', $cols[2]->getText()); + $this->assertEquals('Publisher', $cols[3]->getText()); + // Support different versions of groupmedia. + $this->assertTrue(in_array($cols[4]->getText(), ['Operations', 'Dropbutton'])); + + // Check that rows contain new links for operations in Collabora. + $table_body = $assert_session->elementExists('css', 'tbody', $table); + $rows = $table_body->findAll('css', 'tr'); + $i = 0; + foreach (Media::loadMultiple() as $media) { + $cols = $rows[$i]->findAll('css', 'td'); + $this->assertEquals('Media ' . $i, $cols[0]->getText()); + $this->assertEquals('Document', $cols[1]->getText()); + $this->assertEquals('Yes', $cols[2]->getText()); + $this->assertEquals('Anonymous', $cols[3]->getText()); + $operation_links = $cols[4]->findAll('css', 'a'); + $this->assertEquals('View in Collabora Online', $operation_links[0]->getText()); + $this->assertEquals( + Url::fromRoute( + 'collabora-online.view', + [ + 'media' => $media->id() + ], + [ + 'query' => [ + 'destination' => "/group/{$group->id()}/media", + ] + ] + )->toString(), + $operation_links[0]->getAttribute('href') + ); + $this->assertEquals('Edit in Collabora Online', $operation_links[1]->getText()); + $this->assertEquals( + Url::fromRoute( + 'collabora-online.edit', + [ + 'media' => $media->id() + ], + [ + 'query' => [ + 'destination' => "/group/{$group->id()}/media", + ] + ] + )->toString(), + $operation_links[1]->getAttribute('href') + ); + $i++; + } + } + +} diff --git a/modules/collabora_online_group/tests/src/Functional/SmokeTest.php b/modules/collabora_online_group/tests/src/Functional/SmokeTest.php deleted file mode 100644 index 95a22e47..00000000 --- a/modules/collabora_online_group/tests/src/Functional/SmokeTest.php +++ /dev/null @@ -1,36 +0,0 @@ -drupalGet(''); - $this->assertSession()->statusCodeEquals(200); - } - -} diff --git a/modules/collabora_online_group/tests/src/Traits/GroupRelationTrait.php b/modules/collabora_online_group/tests/src/Traits/GroupRelationTrait.php index 807353bf..b66dc3d2 100644 --- a/modules/collabora_online_group/tests/src/Traits/GroupRelationTrait.php +++ b/modules/collabora_online_group/tests/src/Traits/GroupRelationTrait.php @@ -31,7 +31,7 @@ protected function createPluginRelation(GroupTypeInterface $group_type, string $ $entity_type_id = 'group_relationship_type'; // Fallback for older versions. - if ($this->entityTypeManager()->getDefinition($entity_type_id, FALSE) === NULL) { + if ($this->entityTypeManager()->getDefinition($entity_type_id, FALSE) === NULL) { $entity_type_id = 'group_content_type'; } diff --git a/src/Plugin/views/field/CollaboraEdit.php b/src/Plugin/views/field/CollaboraEdit.php new file mode 100644 index 00000000..92bc2bd7 --- /dev/null +++ b/src/Plugin/views/field/CollaboraEdit.php @@ -0,0 +1,42 @@ +getEntity($row); + + if ($entity === NULL) { + return NULL; + } + + return CoolUtils::getEditorUrl($entity, TRUE); + } + + /** + * {@inheritdoc} + */ + protected function getDefaultLabel(): TranslatableMarkup { + return $this->t('Edit in Collabora Online'); + } +} diff --git a/src/Plugin/views/field/CollaboraPreview.php b/src/Plugin/views/field/CollaboraPreview.php new file mode 100644 index 00000000..e93817f9 --- /dev/null +++ b/src/Plugin/views/field/CollaboraPreview.php @@ -0,0 +1,42 @@ +getEntity($row); + + if ($entity === NULL) { + return NULL; + } + + return CoolUtils::getEditorUrl($entity, FALSE); + } + + /** + * {@inheritdoc} + */ + protected function getDefaultLabel(): TranslatableMarkup { + return $this->t('View in Collabora Online'); + } +} diff --git a/tests/modules/collabora_online_test/config/optional/views.view.test_collabora_links.yml b/tests/modules/collabora_online_test/config/optional/views.view.test_collabora_links.yml new file mode 100644 index 00000000..7f79189b --- /dev/null +++ b/tests/modules/collabora_online_test/config/optional/views.view.test_collabora_links.yml @@ -0,0 +1,272 @@ +langcode: en +status: true +dependencies: + module: + - collabora_online + - media + - user +id: test_collabora_links +label: "Test collabora links" +module: views +description: "" +tag: "" +base_table: media_field_data +base_field: mid +display: + default: + id: default + display_title: Default + display_plugin: default + position: 0 + display_options: + fields: + name: + id: name + table: media_field_data + field: name + relationship: none + group_type: group + admin_label: "" + entity_type: media + entity_field: media + plugin_id: field + label: "" + exclude: false + alter: + alter_text: false + make_link: false + absolute: false + word_boundary: false + ellipsis: false + strip_tags: false + trim: false + html: false + element_type: "" + element_class: "" + element_label_type: "" + element_label_class: "" + element_label_colon: true + element_wrapper_type: "" + element_wrapper_class: "" + element_default_classes: true + empty: "" + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: true + group_column: value + group_columns: {} + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ", " + field_api_classes: false + collabora_preview: + id: collabora_preview + table: media + field: collabora_preview + relationship: none + group_type: group + admin_label: "" + entity_type: media + plugin_id: media_collabora_preview + label: "" + exclude: false + alter: + alter_text: false + text: "" + make_link: false + path: "" + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: "" + rel: "" + link_class: "" + prefix: "" + suffix: "" + target: "" + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: "" + more_link_path: "" + strip_tags: false + trim: false + preserve_tags: "" + html: false + element_type: "" + element_class: "" + element_label_type: "" + element_label_class: "" + element_label_colon: false + element_wrapper_type: "" + element_wrapper_class: "" + element_default_classes: true + empty: "" + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: "" + collabora_edit: + id: collabora_edit + table: media + field: collabora_edit + relationship: none + group_type: group + admin_label: "" + entity_type: media + plugin_id: media_collabora_edit + label: "" + exclude: false + alter: + alter_text: false + text: "" + make_link: false + path: "" + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: "" + rel: "" + link_class: "" + prefix: "" + suffix: "" + target: "" + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: "" + more_link_path: "" + strip_tags: false + trim: false + preserve_tags: "" + html: false + element_type: "" + element_class: "" + element_label_type: "" + element_label_class: "" + element_label_colon: false + element_wrapper_type: "" + element_wrapper_class: "" + element_default_classes: true + empty: "" + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: "" + pager: + type: mini + options: + offset: 0 + pagination_heading_level: h4 + items_per_page: 10 + total_pages: null + id: 0 + tags: + next: ›› + previous: ‹‹ + expose: + items_per_page: false + items_per_page_label: "Items per page" + items_per_page_options: "5, 10, 25, 50" + items_per_page_options_all: false + items_per_page_options_all_label: "- All -" + offset: false + offset_label: Offset + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: "Sort by" + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + access: + type: perm + options: + perm: "view media" + cache: + type: tag + options: {} + empty: {} + sorts: {} + arguments: {} + filters: + status: + id: status + table: media_field_data + field: status + entity_type: media + entity_field: status + plugin_id: boolean + value: "1" + group: 1 + expose: + operator: "" + style: + type: default + options: + grouping: {} + row_class: "" + default_row_class: true + uses_fields: false + row: + type: fields + options: + default_field_elements: true + inline: {} + separator: "" + hide_empty: false + query: + type: views_query + options: + query_comment: "" + disable_sql_rewrite: false + distinct: false + replica: false + query_tags: {} + relationships: {} + header: {} + footer: {} + display_extenders: {} + cache_metadata: + max-age: -1 + contexts: + - "languages:language_content" + - "languages:language_interface" + - url.query_args + - user.permissions + tags: {} + page_1: + id: page_1 + display_title: Page + display_plugin: page + position: 1 + display_options: + display_extenders: {} + path: test_collabora_links + cache_metadata: + max-age: -1 + contexts: + - "languages:language_content" + - "languages:language_interface" + - url.query_args + - user.permissions + tags: {} diff --git a/tests/src/Kernel/ViewsLinkFieldsTest.php b/tests/src/Kernel/ViewsLinkFieldsTest.php new file mode 100644 index 00000000..2aa9e7ef --- /dev/null +++ b/tests/src/Kernel/ViewsLinkFieldsTest.php @@ -0,0 +1,157 @@ +installEntitySchema('file'); + $this->installEntitySchema('media'); + $this->installEntitySchema('user'); + $this->installConfig(['user', 'views', 'collabora_online_test']); + $this->installSchema('file', ['file_usage']); + // Install user module to avoid user 1 permissions bypass. + \Drupal::moduleHandler()->loadInclude('user', 'install'); + user_install(); + + // Create two medias to check access with different scopes, 'any' and 'own'. + $this->createMediaEntity('document'); + $this->ownMedia = $this->createMediaEntity('document'); + } + + /** + * Tests link fields. + */ + public function testLinks(): void { + // User without permissions can't see links. + $this->doTestLinks( + [ + 'preview' => [FALSE, FALSE], + 'edit' => [FALSE, FALSE], + ], + $this->createUser([]) + ); + // User with 'Preview' permission can see preview link. + $this->doTestLinks( + [ + 'preview' => [TRUE, TRUE], + 'edit' => [FALSE, FALSE], + ], + $this->createUser([ + 'preview document in collabora' + ]) + ); + // User with 'Edit any' permission can see edit link. + $this->doTestLinks( + [ + 'preview' => [FALSE, FALSE], + 'edit' => [TRUE, TRUE], + ], + $this->createUser([ + 'edit any document in collabora' + ]) + ); + // User with 'Edit own' permission can see edit link for entities they own. + $this->doTestLinks( + [ + 'preview' => [FALSE, FALSE], + 'edit' => [FALSE, TRUE], + ], + $this->createUser([ + 'edit own document in collabora' + ]) + ); + } + + /** + * Tests that links behave as expected. + * + * @param array $expected_results + * An associative array of expected results keyed by operation. + * @param \Drupal\Core\Session\AccountInterface $account + * The user account to be used to run the test. + */ + protected function doTestLinks(array $expected_results, AccountInterface $account): void { + $this->setCurrentUser($account); + // Set the current user as the owner to check 'edit own' access. + $this->ownMedia->setOwnerId($account->id())->save(); + $view = Views::getView('test_collabora_links'); + $view->preview(); + + $info = [ + 'preview' => [ + 'label' => 'View in Collabora Online', + 'field_id' => 'collabora_preview', + 'route' => 'collabora-online.view' + ], + 'edit' => [ + 'label' => 'Edit in Collabora Online', + 'field_id' => 'collabora_edit', + 'route' => 'collabora-online.edit' + ], + ]; + + // Check each expected results for every media. + $i = 0; + foreach (Media::loadMultiple() as $media) { + foreach ($expected_results as $operation => $expected_result) { + $expected_link = ''; + // The operation array contains results for each of the entities. + if ($expected_result[$i]) { + $path = Url::fromRoute($info[$operation]['route'], ['media' => $media->id()])->toString(); + $expected_link = '' . $info[$operation]['label'] . ''; + } + // We check the output, whether it is a link or is empty (access denied). + $link = $view->style_plugin->getField($i, $info[$operation]['field_id']); + $this->assertEquals($expected_link, (string) $link); + } + $i++; + } + } + +}