diff --git a/config/optional/views.view.group_pending_nodes.yml b/config/optional/views.view.group_pending_nodes.yml index 926098e0a8c8f663a3c3cfc60ee5b6a975fc7897..f8181b2bb27953308e641507e8bda1f422328418 100644 --- a/config/optional/views.view.group_pending_nodes.yml +++ b/config/optional/views.view.group_pending_nodes.yml @@ -520,7 +520,6 @@ display: default_argument_type: fixed default_argument_options: argument: '3' - default_argument_skip_url: false summary_options: base_path: '' count: true diff --git a/gnode_request.module b/gnode_request.module index 67fbc7d2947f722b5b451e42aa6bc0649bcf40ad..e70be6a91abb8513324410ef2dc11cca7f41ffe3 100644 --- a/gnode_request.module +++ b/gnode_request.module @@ -17,7 +17,8 @@ function gnode_request_entity_type_build(array &$entity_types) { ->setFormClass('group-node-approve', 'Drupal\gnode_request\Entity\Form\GroupNodeApproveForm') ->setLinkTemplate('group-node-approve', '/group/{group}/content/{group_relationship}/approve-node') ->setFormClass('group-node-reject', 'Drupal\gnode_request\Entity\Form\GroupNodeRejectForm') - ->setLinkTemplate('group-node-reject', '/group/{group}/content/{group_relationship}/reject-node'); + ->setLinkTemplate('group-node-reject', '/group/{group}/content/{group_relationship}/reject-node') + ->setFormClass('group-request-node', 'Drupal\gnode_request\Entity\Form\GroupNodeRequestForm'); } /** @@ -27,7 +28,14 @@ function gnode_request_menu_local_tasks_alter(&$data, $route_name) { $route_matcher = \Drupal::service('current_route_match'); $group = $route_matcher->getParameter('group'); - if ($group instanceof GroupInterface && !$group->getGroupType()->hasPlugin('group_node_request')) { + if ($group instanceof GroupInterface) { + foreach ($group->getGroupType()->getInstalledPlugins()->getIterator() as $plugin) { + // Plugin group_node_request isn't a case, every bundle has own plugin id, e.g. group_node_request:booking. + if ($plugin->getBaseId() === 'group_node_request') { + return; + } + } + unset($data['tabs'][0]['views_view:view.group_pending_nodes.page_1']); } } diff --git a/gnode_request.routing.yml b/gnode_request.routing.yml index 18505ab5b07299f23a2818e43706991530c5418e..1f6957e730c87696abbeb295b74e1b69a28d561d 100644 --- a/gnode_request.routing.yml +++ b/gnode_request.routing.yml @@ -3,6 +3,7 @@ entity.group_relationship.group_approve_node: defaults: _controller: '\Drupal\gnode_request\Controller\GroupNodeRequestController::approveMembership' requirements: + _group_owns_content: 'TRUE' _group_permission: 'administer group node requests' _pending_group_node_request: 'TRUE' options: @@ -17,6 +18,7 @@ entity.group_relationship.group_reject_node: defaults: _controller: '\Drupal\gnode_request\Controller\GroupNodeRequestController::rejectMembership' requirements: + _group_owns_content: 'TRUE' _group_permission: 'administer group node requests' _pending_group_node_request: 'TRUE' options: diff --git a/gnode_request.workflows.yml b/gnode_request.workflows.yml index 41b3e240ae9098f7e10308037827ca09c2e5c449..eac3f1b272bf63ae926d5f52643b7a967a67ba2b 100644 --- a/gnode_request.workflows.yml +++ b/gnode_request.workflows.yml @@ -1,6 +1,6 @@ -request: - id: request - label: 'Group membership request' +gnode_request: + id: gnode_request + label: 'Group node request' group: group_node_request states: new: diff --git a/src/Plugin/Group/RelationHandler/GroupNodeRequestOperationProvider.php b/src/Plugin/Group/RelationHandler/GroupNodeRequestOperationProvider.php deleted file mode 100644 index f04cd23abea655b0891e5ee57cb3e859779d2131..0000000000000000000000000000000000000000 --- a/src/Plugin/Group/RelationHandler/GroupNodeRequestOperationProvider.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php - -namespace Drupal\gnode_request\Plugin\Group\RelationHandler; - -use Drupal\Core\Session\AccountProxyInterface; -use Drupal\Core\StringTranslation\TranslationInterface; -use Drupal\group\Entity\GroupInterface; -use Drupal\group\Plugin\Group\RelationHandler\OperationProviderInterface; -use Drupal\group\Plugin\Group\RelationHandler\OperationProviderTrait; - -/** - * Provides operations for the group_node_request relation plugin. - * - * @todo DELETE? - */ -class GroupNodeRequestOperationProvider implements OperationProviderInterface { - - use OperationProviderTrait; - - /** - * Constructs a new GroupNodeRequestOperationProvider. - * - * @param \Drupal\group\Plugin\Group\RelationHandler\OperationProviderInterface $parent - * The default operation provider. - * @param \Drupal\Core\Session\AccountProxyInterface $current_user - * The current user. - * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation - * The string translation service. - */ - public function __construct(OperationProviderInterface $parent, AccountProxyInterface $current_user, TranslationInterface $string_translation) { - $this->parent = $parent; - $this->currentUser = $current_user; - $this->stringTranslation = $string_translation; - } - - /** - * {@inheritdoc} - */ - public function getGroupOperations(GroupInterface $group) { - $operations = $this->parent->getGroupOperations($group); - - $url = $group->toUrl('group-request-node'); - if ($url->access($this->currentUser())) { - $entity_instances = $this->getRelationships($group); - if (count($entity_instances) == 0) { - $operations['group-request-node'] = [ - 'title' => $this->t('Request group node membership'), - 'url' => $url, - 'weight' => 99, - ]; - } - } - - // @todo With the new VariationCache, we can use the above context. - $operations['#cache']['contexts'] = ['user']; - - return $operations; - } - - /** - * Get relationship for the current plugin in the given group. - * - * @param \Drupal\group\Entity\GroupInterface $group - * Group. - * - * @return array|\Drupal\group\Entity\GroupRelationshipInterface[] - * List of group relationships. - */ - protected function getRelationships(GroupInterface $group) { - // We can use loadByEntityAndGroup, but for this we need load user entity. - // @see https://www.drupal.org/project/group/issues/3310605 - $properties = [ - 'entity_id' => $this->currentUser()->id(), - 'plugin_id' => $this->pluginId, - 'gid' => $group->id(), - ]; - return $this->entityTypeManager()->getStorage('group_relationship')->loadByProperties($properties); - } - -} diff --git a/src/Plugin/Group/RelationHandler/GroupNodeRequestPostInstall.php b/src/Plugin/Group/RelationHandler/GroupNodeRequestPostInstall.php index 0ebfe9ef17b77fe0845f9e338cca83bc537bbf14..b66d0b1b512b7c9018ba7b3214ea8714fd9de894 100644 --- a/src/Plugin/Group/RelationHandler/GroupNodeRequestPostInstall.php +++ b/src/Plugin/Group/RelationHandler/GroupNodeRequestPostInstall.php @@ -74,7 +74,7 @@ class GroupNodeRequestPostInstall implements PostInstallInterface { 'label' => $this->t('Request status'), 'required' => TRUE, 'settings' => [ - 'workflow' => 'request', + 'workflow' => 'gnode_request', 'workflow_callback' => '', ], ])->save(); diff --git a/src/Plugin/Validation/Constraint/GroupNodeRequestValidator.php b/src/Plugin/Validation/Constraint/GroupNodeRequestValidator.php index 64ac29b6376b12403f278d804978e9ffe33d7f8f..7657f314c0255775579b3111047c3cbfc92ce20b 100644 --- a/src/Plugin/Validation/Constraint/GroupNodeRequestValidator.php +++ b/src/Plugin/Validation/Constraint/GroupNodeRequestValidator.php @@ -11,17 +11,10 @@ use Symfony\Component\Validator\ConstraintValidator; */ class GroupNodeRequestValidator extends ConstraintValidator { - /** - * Type-hinting in parent Symfony class is off, let's fix that. - * - * @var \Symfony\Component\Validator\Context\ExecutionContextInterface - */ - protected $context; - /** * {@inheritdoc} */ - public function validate($group_relationship, Constraint $constraint) { + public function validate($group_relationship, Constraint $constraint): void { assert($group_relationship instanceof GroupRelationshipInterface); assert($constraint instanceof GroupNodeRequest); diff --git a/src/Plugin/views/field/ApproveMembership.php b/src/Plugin/views/field/ApproveMembership.php index a7e696a92aa00ea3c81b7a174e5fd22ac2d05b93..faad34b672497071f1be498999e6596a80a8340b 100644 --- a/src/Plugin/views/field/ApproveMembership.php +++ b/src/Plugin/views/field/ApproveMembership.php @@ -22,7 +22,7 @@ class ApproveMembership extends MembershipEntityLink { * {@inheritdoc} */ protected function getDefaultLabel() { - return $this->t('Approve membership'); + return $this->t('Approve'); } } diff --git a/src/Plugin/views/field/MembershipEntityLink.php b/src/Plugin/views/field/MembershipEntityLink.php index 265775628840455b841fab1e9eb368a909f37cb3..9a62d30d26f623571e3b4ec1035ef1d780bad10e 100644 --- a/src/Plugin/views/field/MembershipEntityLink.php +++ b/src/Plugin/views/field/MembershipEntityLink.php @@ -15,9 +15,11 @@ abstract class MembershipEntityLink extends EntityLink { * {@inheritdoc} */ protected function renderLink(ResultRow $row) { - $plugin_id = 'group_node_request'; + $base_plugin_id = 'group_node_request'; + /** @var \Drupal\group\Entity\GroupRelationship $group_relationship */ $group_relationship = $row->_entity; + $plugin_id = $group_relationship->getPlugin()->getPluginId(); $group = $group_relationship->getGroup(); $link = NULL; @@ -25,15 +27,19 @@ abstract class MembershipEntityLink extends EntityLink { if (!$group->getGroupType()->hasPlugin($plugin_id)) { return $link; } + // Check if current group relationship is type of group_node_request. - if ($group_relationship->getPluginId() !== $plugin_id) { + if ($group_relationship->getPlugin()->getBaseId() !== $base_plugin_id) { return $link; } - $user = $group_relationship->getEntity(); - - if (!empty($group->getMember($user))) { - $link = $this->t('Already member'); + $node = $group_relationship->getEntity(); + // Check if group already have the node as a member. + $nodes = $group->getRelatedEntities(str_replace('_request', '', $group_relationship->getPluginId())); + if (array_filter($nodes, function ($n) use ($node) { + return $node->id() === $n->id(); + })) { + $link = $this->t('Already in group'); } elseif ($group_relationship->get(GroupNodeRequest::STATUS_FIELD)->value === GroupNodeRequest::REQUEST_PENDING && $group->hasPermission('administer group node requests', $this->currentUser)) { $this->options['alter']['query'] = $this->getDestinationArray(); diff --git a/src/Plugin/views/field/RejectMembership.php b/src/Plugin/views/field/RejectMembership.php index c30ea9f1aedc9a47a61c3f09b8c56efe2573f25a..d162bdfd52d1d014746d8061c4c6487a311e9b59 100644 --- a/src/Plugin/views/field/RejectMembership.php +++ b/src/Plugin/views/field/RejectMembership.php @@ -22,7 +22,7 @@ class RejectMembership extends MembershipEntityLink { * {@inheritdoc} */ protected function getDefaultLabel() { - return $this->t('Reject membership'); + return $this->t('Reject'); } } diff --git a/src/Plugin/views/field/RequestMembership.php b/src/Plugin/views/field/RequestMembership.php deleted file mode 100644 index 00d1b1438e58d045a47ac07bc8ebe91901acbc78..0000000000000000000000000000000000000000 --- a/src/Plugin/views/field/RequestMembership.php +++ /dev/null @@ -1,126 +0,0 @@ -<?php - -namespace Drupal\gnode_request\Plugin\views\field; - -use Drupal\Core\Entity\EntityTypeManagerInterface; -use Drupal\Core\Session\AccountInterface; -use Drupal\gnode_request\Plugin\Group\Relation\GroupNodeRequest; -use Drupal\group\Entity\GroupInterface; -use Drupal\views\Plugin\views\field\FieldPluginBase; -use Drupal\views\ResultRow; -use Symfony\Component\DependencyInjection\ContainerInterface; - -/** - * Provides request membership link. - * - * @ingroup views_field_handlers - * - * @ViewsField("group_request_membership") - */ -final class RequestMembership extends FieldPluginBase { - - /** - * The current user. - * - * @var \Drupal\Core\Session\AccountInterface - */ - protected $currentUser; - - /** - * The entity type manager. - * - * @var \Drupal\Core\Entity\EntityTypeManagerInterface - */ - protected $entityTypeManager; - - /** - * RequestMembership constructor. - * - * @param array $configuration - * A configuration array containing information about the plugin instance. - * @param string $plugin_id - * The plugin_id for the plugin instance. - * @param mixed $plugin_definition - * The plugin implementation definition. - * @param \Drupal\Core\Session\AccountInterface $current_user - * The current user. - * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager - * The entity type manager. - */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager) { - parent::__construct($configuration, $plugin_id, $plugin_definition); - $this->currentUser = $current_user; - $this->entityTypeManager = $entity_type_manager; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static( - $configuration, - $plugin_id, - $plugin_definition, - $container->get('current_user'), - $container->get('entity_type.manager') - ); - } - - /** - * {@inheritdoc} - */ - public function usesGroupBy() { - return FALSE; - } - - /** - * {@inheritdoc} - */ - public function query() { - // Intentionally override query to do nothing. - } - - /** - * {@inheritdoc} - * - * @throws \Drupal\Core\Entity\EntityMalformedException - */ - public function render(ResultRow $values) { - /** @var \Drupal\group\Entity\Group $group */ - $group = $values->_entity; - if (!($group instanceof GroupInterface) && !empty($values->_relationship_entities['gid'])) { - $group = $values->_relationship_entities['gid']; - } - - $build = NULL; - if (empty($group) || !$group->getGroupType()->hasPlugin('group_node_request')) { - return $build; - } - - $user = $this->entityTypeManager->getStorage('user')->load($this->currentUser->id()); - if (empty($user)) { - return $build; - } - $membership_requests = $group->getRelationshipsByEntity($user, 'group_node_request'); - if (!empty($group->getMember($this->currentUser))) { - $build['#markup'] = $this->t('Already member'); - } - elseif (empty($membership_requests)) { - $link = $group->toLink($this->t('Request Membership'), 'group-request-node'); - if($link->getUrl()->access($this->currentUser)){ - $build = $link->toString(); - } - } - else { - $membership_request = reset($membership_requests); - if ($membership_request->get(GroupNodeRequest::STATUS_FIELD)->value == GroupNodeRequest::REQUEST_PENDING) { - $build['#markup'] = $this->t('Pending membership request'); - } - else { - $build['#markup'] = $this->t('Rejected membership request'); - } - } - return $build; - } - -} diff --git a/tests/src/Functional/GroupNodeRequestFormTest.php b/tests/src/Functional/GroupNodeRequestFormTest.php index 62fe42455b50a267eb09bedbb267c0c512bafcde..12d21196a5cd2b5aed415655d4c9163d300d0c04 100644 --- a/tests/src/Functional/GroupNodeRequestFormTest.php +++ b/tests/src/Functional/GroupNodeRequestFormTest.php @@ -59,10 +59,13 @@ class GroupNodeRequestFormTest extends GroupBrowserTestBase { */ protected function setUp(): void { parent::setUp(); + $this->group = $this->createGroup(['type' => 'default']); + $this->group2 = $this->createGroup(['type' => 'default']); $group_type = $this->group->getGroupType(); $this->groupContentType = $this->createContentType(['type' => 'page']); $this->otherContentType = $this->createContentType(); + $plugin_id = 'group_node_request:page'; $this->gnodeRequestManager = $this->container->get('gnode_request.gnode_request_manager'); @@ -132,10 +135,17 @@ class GroupNodeRequestFormTest extends GroupBrowserTestBase { $group_node_request = $this->gnodeRequestManager->create($this->group, $node); $group_node_request->save(); + $this->drupalGet("/group/{$this->group->id()}/content/{$group_node_request->id()}/approve-node"); + $this->assertSession()->statusCodeEquals(403); + $manager_account = $this->createUser(); $this->group->addMember($manager_account); + $this->group2->addMember($manager_account); $this->drupalLogin($manager_account); + $this->drupalGet("/group/{$this->group2->id()}/content/{$group_node_request->id()}/approve-node"); + $this->assertSession()->statusCodeEquals(403); + $this->drupalGet("/group/{$this->group->id()}/content/{$group_node_request->id()}/approve-node"); $this->assertSession()->statusCodeEquals(200); @@ -166,10 +176,16 @@ class GroupNodeRequestFormTest extends GroupBrowserTestBase { $group_node_request = $this->gnodeRequestManager->create($this->group, $node); $group_node_request->save(); + $this->drupalGet("/group/{$this->group->id()}/content/{$group_node_request->id()}/reject-node"); + $this->assertSession()->statusCodeEquals(403); + $manager_account = $this->createUser(); $this->group->addMember($manager_account); $this->drupalLogin($manager_account); + $this->drupalGet("/group/{$this->group->id()}/content/{$group_node_request->id()}/reject-node"); + $this->assertSession()->statusCodeEquals(403); + $this->drupalGet("/group/{$this->group->id()}/content/{$group_node_request->id()}/reject-node"); $this->assertSession()->statusCodeEquals(200); diff --git a/tests/src/Kernel/GroupNodeRequestAccessTest.php b/tests/src/Kernel/GroupNodeRequestAccessTest.php index 556a36488117c89a1b42fade33529e4eec1bfc6e..351ac53c44af4388e5bc46f390e0c69cf92d9cf0 100644 --- a/tests/src/Kernel/GroupNodeRequestAccessTest.php +++ b/tests/src/Kernel/GroupNodeRequestAccessTest.php @@ -103,7 +103,7 @@ class GroupNodeRequestAccessTest extends GroupKernelTestBase { $storage->save($storage->createFromPlugin($this->groupTypeB, 'group_node_request:page')); $storage->save($storage->createFromPlugin($this->groupTypeB, 'group_node_request:article')); - $this->setCurrentUser($this->createUser([], $this->permissions)); + $this->setCurrentUser($this->createUser($this->permissions)); } /** diff --git a/tests/src/Kernel/GroupNodeRequestConfigTest.php b/tests/src/Kernel/GroupNodeRequestConfigTest.php index dca262d9db710779756dedc45a118f6e4c8d5770..7f3cce75748614d90b0455b4899b9e7a39c23642 100644 --- a/tests/src/Kernel/GroupNodeRequestConfigTest.php +++ b/tests/src/Kernel/GroupNodeRequestConfigTest.php @@ -21,7 +21,6 @@ class GroupNodeRequestConfigTest extends EntityKernelTestBase { 'group', 'options', 'entity', - 'variationcache', 'flexible_permissions', 'state_machine', 'gnode_request',