From b0ef6a4919bec6b2202ba30940ab2bf6b996bd67 Mon Sep 17 00:00:00 2001 From: Camille Liccia Date: Fri, 16 Nov 2018 15:46:32 +0100 Subject: [PATCH] Issue #741333: Add Block_content entity support for group. --- .../gblock_content.group.permissions.yml | 3 + modules/gblock_content/gblock_content.info.yml | 9 ++ .../gblock_content/gblock_content.links.action.yml | 5 + modules/gblock_content/gblock_content.module | 81 +++++++++++++++ modules/gblock_content/gblock_content.routing.yml | 2 + modules/gblock_content/gblock_content.services.yml | 5 + .../Access/GroupBlockContentAdminAccessCheck.php | 52 ++++++++++ .../src/Controller/GroupBlockContentController.php | 114 +++++++++++++++++++++ .../GroupConfigEnabler/GroupBlockContentType.php | 18 ++++ .../GroupContentEnabler/GroupBlockContent.php | 108 +++++++++++++++++++ .../GroupBlockContentDeriver.php | 27 +++++ .../src/Routing/GroupBlockContentRouteProvider.php | 57 +++++++++++ 12 files changed, 481 insertions(+) create mode 100644 modules/gblock_content/gblock_content.group.permissions.yml create mode 100644 modules/gblock_content/gblock_content.info.yml create mode 100644 modules/gblock_content/gblock_content.links.action.yml create mode 100644 modules/gblock_content/gblock_content.module create mode 100644 modules/gblock_content/gblock_content.routing.yml create mode 100644 modules/gblock_content/gblock_content.services.yml create mode 100644 modules/gblock_content/src/Access/GroupBlockContentAdminAccessCheck.php create mode 100644 modules/gblock_content/src/Controller/GroupBlockContentController.php create mode 100644 modules/gblock_content/src/Plugin/GroupConfigEnabler/GroupBlockContentType.php create mode 100644 modules/gblock_content/src/Plugin/GroupContentEnabler/GroupBlockContent.php create mode 100644 modules/gblock_content/src/Plugin/GroupContentEnabler/GroupBlockContentDeriver.php create mode 100644 modules/gblock_content/src/Routing/GroupBlockContentRouteProvider.php diff --git a/modules/gblock_content/gblock_content.group.permissions.yml b/modules/gblock_content/gblock_content.group.permissions.yml new file mode 100644 index 0000000..b03fa18 --- /dev/null +++ b/modules/gblock_content/gblock_content.group.permissions.yml @@ -0,0 +1,3 @@ +access group_block_content overview: + title: 'Access group block content overview' + description: 'Access the overview of all group block content items, regardless of bundle' diff --git a/modules/gblock_content/gblock_content.info.yml b/modules/gblock_content/gblock_content.info.yml new file mode 100644 index 0000000..fca5256 --- /dev/null +++ b/modules/gblock_content/gblock_content.info.yml @@ -0,0 +1,9 @@ +name: 'Group Block content' +description: 'Enables Group functionality for block content items' +package: 'Group' +type: 'module' +version: 1.0 +core_version_requirement: ^8 || ^9 +dependencies: + - 'block_content' + - 'group' diff --git a/modules/gblock_content/gblock_content.links.action.yml b/modules/gblock_content/gblock_content.links.action.yml new file mode 100644 index 0000000..560512f --- /dev/null +++ b/modules/gblock_content/gblock_content.links.action.yml @@ -0,0 +1,5 @@ +entity.block_content_item.group_add_form: + route_name: entity.block_content_item.group_add_form + title: 'Add Block content item to group' + appears_on: + - entity.block_content_item.group_overview_form diff --git a/modules/gblock_content/gblock_content.module b/modules/gblock_content/gblock_content.module new file mode 100644 index 0000000..ad6a0a9 --- /dev/null +++ b/modules/gblock_content/gblock_content.module @@ -0,0 +1,81 @@ +bundle(); + + // Only act if there are group content types for this node type. + $group_content_types = GroupContentType::loadByContentPluginId($plugin_id); + if (empty($group_content_types)) { + return AccessResult::neutral(); + } + + // Load all the group content for this node. + $group_contents = \Drupal::entityTypeManager() + ->getStorage('group_content') + ->loadByProperties([ + 'type' => array_keys($group_content_types), + 'entity_id' => $block_content->id(), + ]); + + // If the block content 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 block content item belonging to a group, + // you should be denied access instead. + switch ($op) { + case 'view': + foreach ($groups as $group) { + if ($group->hasPermission("view " . $block_content->bundle() . " item", $account) || + $group->hasPermission("view " . $plugin_id . " entity", $account)) { + return AccessResult::allowed(); + } + } + break; + + case 'update': + case 'delete': + foreach ($groups as $group) { + if ($group->hasPermission("edit " . $block_content->bundle() . " item", $account) || + $group->hasPermission("update any " . $plugin_id . " entity", $account)) { + return AccessResult::allowed(); + } + } + break; + } + + return AccessResult::forbidden(); +} diff --git a/modules/gblock_content/gblock_content.routing.yml b/modules/gblock_content/gblock_content.routing.yml new file mode 100644 index 0000000..9a06152 --- /dev/null +++ b/modules/gblock_content/gblock_content.routing.yml @@ -0,0 +1,2 @@ +route_callbacks: + - '\Drupal\gblock_content\Routing\GroupBlockContentRouteProvider::getRoutes' diff --git a/modules/gblock_content/gblock_content.services.yml b/modules/gblock_content/gblock_content.services.yml new file mode 100644 index 0000000..9132643 --- /dev/null +++ b/modules/gblock_content/gblock_content.services.yml @@ -0,0 +1,5 @@ +services: + access_check.gblock_content.admin: + class: Drupal\gblock_content\Access\GroupBlockContentAdminAccessCheck + tags: + - { name: access_check, applies_to: _group_block_content_admin_access } diff --git a/modules/gblock_content/src/Access/GroupBlockContentAdminAccessCheck.php b/modules/gblock_content/src/Access/GroupBlockContentAdminAccessCheck.php new file mode 100644 index 0000000..6093eb6 --- /dev/null +++ b/modules/gblock_content/src/Access/GroupBlockContentAdminAccessCheck.php @@ -0,0 +1,52 @@ +getRequirement('_group_block_content_admin_access') === 'TRUE'; + + // We can only get the group content type ID if the plugin is installed. + if (!$group->getGroupType()->hasContentPlugin("group_block_content:$block_content_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 $block_content_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/gblock_content/src/Controller/GroupBlockContentController.php b/modules/gblock_content/src/Controller/GroupBlockContentController.php new file mode 100644 index 0000000..886ab1b --- /dev/null +++ b/modules/gblock_content/src/Controller/GroupBlockContentController.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('block_content_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 = ['%block_content_type' => $bundle_label]; + $description = $create_mode + ? $this->t('Create a block content of type %block_content_type in the group.', $t_args) + : $this->t('Add an existing block content of type %block_content_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_block_content 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_block_content:') !== 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/gblock_content/src/Plugin/GroupConfigEnabler/GroupBlockContentType.php b/modules/gblock_content/src/Plugin/GroupConfigEnabler/GroupBlockContentType.php new file mode 100644 index 0000000..e18d06f --- /dev/null +++ b/modules/gblock_content/src/Plugin/GroupConfigEnabler/GroupBlockContentType.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["gblock_content-create-$type"] = [ + 'title' => $this->t('Create @type', ['@type' => $this->getBlockContentType()->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'][] = 'block_content.type.' . $this->getEntityBundle(); + return $dependencies; + } + +} diff --git a/modules/gblock_content/src/Plugin/GroupContentEnabler/GroupBlockContentDeriver.php b/modules/gblock_content/src/Plugin/GroupContentEnabler/GroupBlockContentDeriver.php new file mode 100644 index 0000000..ca30185 --- /dev/null +++ b/modules/gblock_content/src/Plugin/GroupContentEnabler/GroupBlockContentDeriver.php @@ -0,0 +1,27 @@ + $block_content_type) { + $label = $block_content_type->label(); + + $this->derivatives[$name] = [ + 'entity_bundle' => $name, + 'label' => t('Group block content (@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/gblock_content/src/Routing/GroupBlockContentRouteProvider.php b/modules/gblock_content/src/Routing/GroupBlockContentRouteProvider.php new file mode 100644 index 0000000..61a1f43 --- /dev/null +++ b/modules/gblock_content/src/Routing/GroupBlockContentRouteProvider.php @@ -0,0 +1,57 @@ + $block_content_type) { + $plugin_id = "group_block_content:$name"; + + $plugin_ids[] = $plugin_id; + $permissions_add[] = "create $plugin_id content"; + $permissions_create[] = "create $plugin_id entity"; + } + + // If there are no block_content 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_block_content_relate_page'] = new Route('group/{group}/block_content/add'); + $routes['entity.group_content.group_block_content_relate_page'] + ->setDefaults([ + '_title' => 'Relate block content', + '_controller' => '\Drupal\gblock_content\Controller\GroupBlockContentController::addPage', + ]) + ->setRequirement('_group_permission', implode('+', $permissions_add)) + ->setRequirement('_group_installed_content', implode('+', $plugin_ids)) + ->setOption('_group_operation_route', TRUE); + + $routes['entity.group_content.group_block_content_add_page'] = new Route('group/{group}/block_content/create'); + $routes['entity.group_content.group_block_content_add_page'] + ->setDefaults([ + '_title' => 'Create block content', + '_controller' => '\Drupal\gblock_content\Controller\GroupBlockContentController::addPage', + 'create_mode' => TRUE, + ]) + ->setRequirement('_group_permission', implode('+', $permissions_create)) + ->setRequirement('_group_installed_content', implode('+', $plugin_ids)) + ->setOption('_group_operation_route', TRUE); + + return $routes; + } + +} -- 2.7.4