diff --git a/modules/gmedia/config/optional/views.view.group_media.yml b/modules/gmedia/config/optional/views.view.group_media.yml new file mode 100644 index 0000000..0c4fd10 --- /dev/null +++ b/modules/gmedia/config/optional/views.view.group_media.yml @@ -0,0 +1,841 @@ +langcode: en +status: true +dependencies: + module: + - group + - media +id: group_media +label: 'Group media' +module: views +description: '' +tag: '' +base_table: media_field_data +base_field: mid +core: 8.x +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: group_permission + options: + group_permission: 'access group_media overview' + cache: + type: tag + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + query_tags: { } + 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 + pager: + type: mini + options: + items_per_page: 50 + offset: 0 + id: 0 + total_pages: null + 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 + tags: + previous: ‹‹ + next: ›› + style: + type: table + row: + type: fields + fields: + name: + id: name + table: media_field_data + field: name + entity_type: media + entity_field: media + alter: + alter_text: false + make_link: false + absolute: false + trim: false + word_boundary: false + ellipsis: false + strip_tags: false + html: false + hide_empty: false + empty_zero: false + settings: + link_to_entity: true + plugin_id: field + relationship: none + group_type: group + admin_label: '' + label: Name + exclude: 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_alter_empty: true + click_sort_column: value + type: string + 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 + bundle: + id: bundle + table: media_field_data + field: bundle + relationship: none + group_type: group + admin_label: '' + label: 'Media type' + 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: 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: target_id + type: entity_reference_label + settings: + link: false + group_column: target_id + 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 + entity_type: media + entity_field: bundle + plugin_id: field + status: + id: status + table: media_field_data + field: status + relationship: none + group_type: group + admin_label: '' + label: Status + 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: 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: boolean + settings: + format: custom + format_custom_true: Published + format_custom_false: Unpublished + 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 + entity_type: media + entity_field: status + plugin_id: field + changed: + id: changed + table: media_field_data + field: changed + relationship: none + group_type: group + admin_label: '' + label: Updated + 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: 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: timestamp + settings: + date_format: medium + custom_date_format: '' + timezone: '' + 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 + entity_type: media + entity_field: changed + plugin_id: field + view_group_content: + id: view_group_content + table: group_content + field: view_group_content + relationship: group_content + group_type: group + admin_label: '' + label: 'Link to Group content' + exclude: true + 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: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: 'View relation' + output_url_as_text: false + absolute: false + entity_type: group_content + plugin_id: entity_link + edit_group_content: + id: edit_group_content + table: group_content + field: edit_group_content + relationship: group_content + group_type: group + admin_label: '' + label: 'Link to edit Group content' + exclude: true + 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: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: 'Edit relation' + output_url_as_text: false + absolute: false + entity_type: group_content + plugin_id: entity_link_edit + delete_group_content: + id: delete_group_content + table: group_content + field: delete_group_content + relationship: group_content + group_type: group + admin_label: '' + label: 'Link to delete Group content' + exclude: true + 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: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: 'Delete relation' + output_url_as_text: false + absolute: false + entity_type: group_content + plugin_id: entity_link_delete + edit_media: + id: edit_media + table: media + field: edit_media + relationship: none + group_type: group + admin_label: '' + label: 'Link to edit Media' + exclude: true + 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: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: 'Edit media' + output_url_as_text: false + absolute: false + entity_type: media + plugin_id: entity_link_edit + delete_media: + id: delete_media + table: media + field: delete_media + relationship: none + group_type: group + admin_label: '' + label: 'Link to delete Media' + exclude: true + 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: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: 'Delete node' + output_url_as_text: false + absolute: false + entity_type: media + plugin_id: entity_link_delete + dropbutton: + id: dropbutton + table: views + field: dropbutton + relationship: none + group_type: group + admin_label: '' + label: Operations + 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: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + fields: + view_group_content: view_group_content + edit_group_content: edit_group_content + delete_group_content: delete_group_content + edit_media: edit_media + delete_media: delete_media + name: '0' + bundle: '0' + status: '0' + changed: '0' + destination: true + plugin_id: dropbutton + filters: + status: + id: status + table: media_field_data + field: status + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: '1' + group: 1 + exposed: true + expose: + operator_id: '' + label: Published + description: null + use_operator: false + operator: status_op + identifier: status + required: true + remember: false + multiple: false + remember_roles: + authenticated: authenticated + is_grouped: true + group_info: + label: 'Published status' + description: '' + identifier: status + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: + 1: + title: Published + operator: '=' + value: '1' + 2: + title: Unpublished + operator: '=' + value: '0' + plugin_id: boolean + entity_type: media + entity_field: status + bundle: + id: bundle + table: media_field_data + field: bundle + relationship: none + group_type: group + admin_label: '' + operator: in + value: { } + group: 1 + exposed: true + expose: + operator_id: bundle_op + label: Type + description: '' + use_operator: false + operator: bundle_op + identifier: bundle + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + reduce: false + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: media + entity_field: bundle + plugin_id: bundle + sorts: { } + title: 'Group media' + header: { } + footer: { } + empty: + area_text_custom: + id: area_text_custom + table: views + field: area_text_custom + relationship: none + group_type: group + admin_label: '' + empty: true + tokenize: false + content: 'No content available.' + plugin_id: text_custom + relationships: + group_content: + id: group_content + table: media_field_data + field: group_content + relationship: none + group_type: group + admin_label: 'Content relation' + required: true + group_content_plugins: + 'group_media:audio': '0' + 'group_media:file': '0' + 'group_media:image': '0' + 'group_media:remote_video': '0' + 'group_media:video': '0' + entity_type: media + plugin_id: group_content_to_entity_reverse + arguments: + gid: + id: gid + table: group_content_field_data + field: gid + relationship: group_content + group_type: group + admin_label: '' + default_action: 'access denied' + exception: + value: all + title_enable: false + title: All + title_enable: true + title: '{{ arguments.gid|placeholder }} media' + default_argument_type: fixed + default_argument_options: + argument: '' + default_argument_skip_url: false + summary_options: + base_path: '' + count: true + items_per_page: 25 + override: false + summary: + sort_order: asc + number_of_records: 0 + format: default_summary + specify_validation: true + validate: + type: 'entity:group' + fail: 'not found' + validate_options: + operation: view + multiple: 0 + bundles: { } + access: false + break_phrase: false + not: false + entity_type: group_content + entity_field: gid + plugin_id: group_id + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - route.group + - url + - url.query_args + - user.group_permissions + tags: { } + page_1: + display_plugin: page + id: page_1 + display_title: Page + position: 1 + display_options: + display_extenders: { } + path: group/%group/media + menu: + type: tab + title: Media + description: '' + expanded: false + parent: '' + weight: 30 + context: '0' + menu_name: main + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - route.group + - url + - url.query_args + - user.group_permissions + tags: { } diff --git a/modules/gmedia/gmedia.group.permissions.yml b/modules/gmedia/gmedia.group.permissions.yml new file mode 100644 index 0000000..dd6921f --- /dev/null +++ b/modules/gmedia/gmedia.group.permissions.yml @@ -0,0 +1,3 @@ +access group_media overview: + title: 'Access group media overview' + description: 'Access the overview of all group media items, regardless of bundle' diff --git a/modules/gmedia/gmedia.info.yml b/modules/gmedia/gmedia.info.yml new file mode 100644 index 0000000..487cd50 --- /dev/null +++ b/modules/gmedia/gmedia.info.yml @@ -0,0 +1,9 @@ +name: 'Group Media' +description: 'Enables Group functionality for media items' +package: 'Group' +type: 'module' +version: 1.0 +core_version_requirement: ^8.8 || ^9 +dependencies: + - 'media' + - 'group' diff --git a/modules/gmedia/gmedia.links.action.yml b/modules/gmedia/gmedia.links.action.yml new file mode 100644 index 0000000..d200a22 --- /dev/null +++ b/modules/gmedia/gmedia.links.action.yml @@ -0,0 +1,11 @@ +group_content.group_media_add_page: + route_name: 'entity.group_content.group_media_add_page' + title: 'Add media item to group' + appears_on: + - 'view.group_media.page_1' + +group_content.group_media_relate_page: + route_name: 'entity.group_content.group_media_relate_page' + title: 'Relate media item to group' + appears_on: + - 'view.group_media.page_1' diff --git a/modules/gmedia/gmedia.module b/modules/gmedia/gmedia.module new file mode 100644 index 0000000..556a27a --- /dev/null +++ b/modules/gmedia/gmedia.module @@ -0,0 +1,94 @@ +clearCachedDefinitions(); +} + +/** + * Implements hook_media_access(). + * + * When trying to view, update or delete a media item it suffices to have the + * right to do so in only one group the media item belongs to. If you wish + * to prevent any such action on your own terms, implement hook_media_access() + * in your module. + */ +function gmedia_media_access(EntityInterface $media, $op, AccountInterface $account) { + // We do not care about create access as we have our own wizard for that. Any + // operation aside from 'view', 'update' and 'delete' is also unsupported. + if (!in_array($op, ['view', 'update', 'delete']) || !$media->id()) { + return AccessResult::neutral(); + } + + $plugin_id = 'group_media:' . $media->bundle(); + + // Only act if there are group content types for this media type. + $group_content_types = GroupContentType::loadByContentPluginId($plugin_id); + if (empty($group_content_types)) { + return AccessResult::neutral(); + } + + // Load all the group content for this media item. + $group_contents = \Drupal::entityTypeManager() + ->getStorage('group_content') + ->loadByProperties([ + 'type' => array_keys($group_content_types), + 'entity_id' => $media->id(), + ]); + + // If the media item does not belong to any group, we have nothing to say. + if (empty($group_contents)) { + return AccessResult::neutral(); + } + + /** @var \Drupal\group\Entity\GroupInterface[] $groups */ + $groups = []; + foreach ($group_contents as $group_content) { + /** @var \Drupal\group\Entity\GroupContentInterface $group_content */ + $group = $group_content->getGroup(); + $groups[$group->id()] = $group; + } + + // From this point on you need group to allow you to perform the requested + // operation. If you are not granted access for a media item belonging to + // a group, you should be denied access instead. + switch ($op) { + case 'view': + $is_published = $media->isPublished(); + + foreach ($groups as $group) { + if ((!$is_published && $group->hasPermission("view unpublished $plugin_id entity", $account)) || + ($is_published && $group->hasPermission("view $plugin_id entity", $account))) { + return AccessResult::allowed(); + } + } + break; + + case 'update': + case 'delete': + foreach ($groups as $group) { + if ($group->hasPermission( "$op any $plugin_id entity", $account)) { + return AccessResult::allowed(); + } + elseif ($account->id() == $media->getOwnerId() && $group->hasPermission("$op own $plugin_id entity", $account)) { + return AccessResult::allowed(); + } + } + break; + } + + return AccessResult::forbidden(); +} diff --git a/modules/gmedia/gmedia.routing.yml b/modules/gmedia/gmedia.routing.yml new file mode 100644 index 0000000..47f500e --- /dev/null +++ b/modules/gmedia/gmedia.routing.yml @@ -0,0 +1,2 @@ +route_callbacks: + - '\Drupal\gmedia\Routing\GroupMediaRouteProvider::getRoutes' diff --git a/modules/gmedia/gmedia.services.yml b/modules/gmedia/gmedia.services.yml new file mode 100644 index 0000000..d839a91 --- /dev/null +++ b/modules/gmedia/gmedia.services.yml @@ -0,0 +1,5 @@ +services: + access_check.gmedia.admin: + class: Drupal\gmedia\Access\GroupMediaAdminAccessCheck + tags: + - { name: access_check, applies_to: _group_media_admin_access } diff --git a/modules/gmedia/src/Access/GroupMediaAdminAccessCheck.php b/modules/gmedia/src/Access/GroupMediaAdminAccessCheck.php new file mode 100644 index 0000000..fb55c32 --- /dev/null +++ b/modules/gmedia/src/Access/GroupMediaAdminAccessCheck.php @@ -0,0 +1,52 @@ +getRequirement('_group_media_admin_access') === 'TRUE'; + + // We can only get the group content type ID if the plugin is installed. + if (!$group->getGroupType()->hasContentPlugin("group_media:$media_type")) { + return AccessResult::neutral(); + } + + // Determine whether the user can manipulate items of the provided type. + $access = FALSE; + foreach (['create', 'edit', 'delete'] as $op) { + $permission = "$op $media_type item"; + $access = $access || $group->hasPermission($permission, $account); + } + + // Only allow access if the user can manipulate group items of the provided + // type or if he doesn't need access to do so. + return AccessResult::allowedIf($access xor !$needs_access); + } + +} diff --git a/modules/gmedia/src/Controller/GroupMediaController.php b/modules/gmedia/src/Controller/GroupMediaController.php new file mode 100644 index 0000000..537579a --- /dev/null +++ b/modules/gmedia/src/Controller/GroupMediaController.php @@ -0,0 +1,114 @@ +pluginManager = $plugin_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.group_content_enabler'), + $container->get('user.private_tempstore'), + $container->get('entity_type.manager'), + $container->get('entity.form_builder'), + $container->get('renderer') + ); + } + + /** + * {@inheritdoc} + */ + public function addPage(GroupInterface $group, $create_mode = FALSE) { + $build = parent::addPage($group, $create_mode); + + // Do not interfere with redirects. + if (!is_array($build)) { + return $build; + } + + // Overwrite the label and description for all of the displayed bundles. + $storage_handler = $this->entityTypeManager->getStorage('media_type'); + foreach ($this->addPageBundles($group, $create_mode) as $plugin_id => $bundle_name) { + if (!empty($build['#bundles'][$bundle_name])) { + $plugin = $group->getGroupType()->getContentPlugin($plugin_id); + $bundle_label = $storage_handler->load($plugin->getEntityBundle())->label(); + + $t_args = ['%media_type' => $bundle_label]; + $description = $create_mode + ? $this->t('Create a media of type %media_type in the group.', $t_args) + : $this->t('Add an existing media of type %media_type to the group.', $t_args); + + $build['#bundles'][$bundle_name]['label'] = $bundle_label; + $build['#bundles'][$bundle_name]['description'] = $description; + } + } + + return $build; + } + + /** + * {@inheritdoc} + */ + protected function addPageBundles(GroupInterface $group, $create_mode) { + $bundles = []; + + // Retrieve all group_media plugins for the group's type. + $plugin_ids = $this->pluginManager->getInstalledIds($group->getGroupType()); + foreach ($plugin_ids as $key => $plugin_id) { + if (strpos($plugin_id, 'group_media:') !== 0) { + unset($plugin_ids[$key]); + } + } + + // Retrieve all of the responsible group content types, keyed by plugin ID. + $storage = $this->entityTypeManager->getStorage('group_content_type'); + $properties = ['group_type' => $group->bundle(), 'content_plugin' => $plugin_ids]; + foreach ($storage->loadByProperties($properties) as $bundle => $group_content_type) { + /** @var \Drupal\group\Entity\GroupContentTypeInterface $group_content_type */ + $bundles[$group_content_type->getContentPluginId()] = $bundle; + } + + return $bundles; + } + +} diff --git a/modules/gmedia/src/Plugin/GroupConfigEnabler/GroupMediaType.php b/modules/gmedia/src/Plugin/GroupConfigEnabler/GroupMediaType.php new file mode 100644 index 0000000..b34214a --- /dev/null +++ b/modules/gmedia/src/Plugin/GroupConfigEnabler/GroupMediaType.php @@ -0,0 +1,18 @@ +getEntityBundle()); + } + + /** + * {@inheritdoc} + */ + public function getGroupOperations(GroupInterface $group) { + $account = \Drupal::currentUser(); + $plugin_id = $this->getPluginId(); + $type = $this->getEntityBundle(); + $operations = []; + + if ($group->hasPermission("create $plugin_id entity", $account)) { + $route_params = ['group' => $group->id(), 'plugin_id' => $plugin_id]; + $operations["gmedia-create-$type"] = [ + 'title' => $this->t('Create @type', ['@type' => $this->getMediaType()->label()]), + 'url' => new Url('entity.group_content.create_form', $route_params), + 'weight' => 30, + ]; + } + + return $operations; + } + + /** + * {@inheritdoc} + */ + protected function getTargetEntityPermissions() { + $permissions = parent::getTargetEntityPermissions(); + $plugin_id = $this->getPluginId(); + + // Add a 'view unpublished' permission by re-using most of the 'view' one. + $original = $permissions["view $plugin_id entity"]; + $permissions["view unpublished $plugin_id entity"] = [ + 'title' => str_replace('View ', 'View unpublished ', $original['title']), + ] + $original; + + return $permissions; + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + $config = parent::defaultConfiguration(); + $config['entity_cardinality'] = 1; + return $config; + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $form = parent::buildConfigurationForm($form, $form_state); + + // Disable the entity cardinality field as the functionality of this module + // relies on a cardinality of 1. We don't just hide it, though, to keep a UI + // that's consistent with other content enabler plugins. + $info = $this->t("This field has been disabled by the plugin to guarantee the functionality that's expected of it."); + $form['entity_cardinality']['#disabled'] = TRUE; + $form['entity_cardinality']['#description'] .= '
' . $info . ''; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function calculateDependencies() { + $dependencies = parent::calculateDependencies(); + $dependencies['config'][] = 'media.type.' . $this->getEntityBundle(); + return $dependencies; + } + +} diff --git a/modules/gmedia/src/Plugin/GroupContentEnabler/GroupMediaDeriver.php b/modules/gmedia/src/Plugin/GroupContentEnabler/GroupMediaDeriver.php new file mode 100644 index 0000000..200e4a3 --- /dev/null +++ b/modules/gmedia/src/Plugin/GroupContentEnabler/GroupMediaDeriver.php @@ -0,0 +1,27 @@ + $media_type) { + $label = $media_type->label(); + + $this->derivatives[$name] = [ + 'entity_bundle' => $name, + 'label' => t('Group media (@type)', ['@type' => $label]), + 'description' => t('Adds %type content to groups both publicly and privately.', ['%type' => $label]), + ] + $base_plugin_definition; + } + + return $this->derivatives; + } + +} diff --git a/modules/gmedia/src/Routing/GroupMediaRouteProvider.php b/modules/gmedia/src/Routing/GroupMediaRouteProvider.php new file mode 100644 index 0000000..b552e5a --- /dev/null +++ b/modules/gmedia/src/Routing/GroupMediaRouteProvider.php @@ -0,0 +1,57 @@ + $media_type) { + $plugin_id = "group_media:$name"; + + $plugin_ids[] = $plugin_id; + $permissions_add[] = "create $plugin_id content"; + $permissions_create[] = "create $plugin_id entity"; + } + + // If there are no media types yet, we cannot have any plugin IDs and should + // therefore exit early because we cannot have any routes for them either. + if (empty($plugin_ids)) { + return $routes; + } + + $routes['entity.group_content.group_media_relate_page'] = new Route('group/{group}/media/add'); + $routes['entity.group_content.group_media_relate_page'] + ->setDefaults([ + '_title' => 'Relate media', + '_controller' => '\Drupal\gmedia\Controller\GroupMediaController::addPage', + ]) + ->setRequirement('_group_permission', implode('+', $permissions_add)) + ->setRequirement('_group_installed_content', implode('+', $plugin_ids)) + ->setOption('_group_operation_route', TRUE); + + $routes['entity.group_content.group_media_add_page'] = new Route('group/{group}/media/create'); + $routes['entity.group_content.group_media_add_page'] + ->setDefaults([ + '_title' => 'Create media', + '_controller' => '\Drupal\gmedia\Controller\GroupMediaController::addPage', + 'create_mode' => TRUE, + ]) + ->setRequirement('_group_permission', implode('+', $permissions_create)) + ->setRequirement('_group_installed_content', implode('+', $plugin_ids)) + ->setOption('_group_operation_route', TRUE); + + return $routes; + } + +}