From de32a81cd984e25a4375edfaf6d3bd1bab0b8ae5 Mon Sep 17 00:00:00 2001
From: Pavel Ruban <job.pavelruban@gmail.com>
Date: Wed, 16 Apr 2025 01:42:15 +0000
Subject: [PATCH 1/6] Issue #3519161: Fix routes conflict with grequest, fix
 access checks plugin name issues in entity link and menu local task alter,
 fix missing gnode request form class.

# Conflicts:
#	gnode_request.routing.yml
---
 gnode_request.module                          | 12 ++-
 src/Entity/Form/GroupNodeRequestForm.php      | 90 +++++++++++++++++++
 .../views/field/MembershipEntityLink.php      | 18 ++--
 3 files changed, 112 insertions(+), 8 deletions(-)
 create mode 100644 src/Entity/Form/GroupNodeRequestForm.php

diff --git a/gnode_request.module b/gnode_request.module
index 67fbc7d..e70be6a 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/src/Entity/Form/GroupNodeRequestForm.php b/src/Entity/Form/GroupNodeRequestForm.php
new file mode 100644
index 0000000..f7b28db
--- /dev/null
+++ b/src/Entity/Form/GroupNodeRequestForm.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace Drupal\gnode_request\Entity\Form;
+
+use Drupal\Component\Datetime\TimeInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\gnode_request\GnodeRequestManager;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a form for requesting a group membership.
+ */
+class GroupNodeRequestForm extends GroupRelationshipBaseForm {
+
+  /**
+   * Membership request manager.
+   *
+   * @var \Drupal\gnode_request\GnodeRequestManager
+   */
+  protected $gnodeRequestManager;
+
+  /**
+   * Constructs a request membership form.
+   *
+   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
+   *   The entity repository service.
+   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
+   *   The entity type bundle service.
+   * @param \Drupal\Component\Datetime\TimeInterface $time
+   *   The time service.
+   * @param \Drupal\gnode_request\GnodeRequestManager $gnode_request_manager
+   *   Membership request manager.
+ */
+  public function __construct(EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info, TimeInterface $time, GnodeRequestManager $gnode_request_manager) {
+    parent::__construct($entity_repository, $entity_type_bundle_info, $time);
+    $this->gnodeRequestManager = $gnode_request_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('entity.repository'),
+      $container->get('entity_type.bundle.info'),
+      $container->get('datetime.time'),
+      $container->get('gnode_request.gnode_request_manager')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function actions(array $form, FormStateInterface $form_state) {
+    $actions = parent::actions($form, $form_state);
+    $actions['submit']['#value'] = $this->t('Request group membership');
+    $actions['cancel'] = [
+      '#type' => 'link',
+      '#title' => $this->t('Cancel'),
+      '#url' => $this->getCancelUrl(),
+    ];
+
+    return $actions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    $form = parent::buildForm($form, $form_state);
+    $form['#attached']['library'][] = 'core/drupal.form';
+    // Make field not accessible, because we set it programmatically.
+    $form['entity_id']['#access'] = FALSE;
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    $return = parent::save($form, $form_state);
+
+    $this->messenger()->addMessage($this->t('Your request is waiting for approval'));
+    $form_state->setRedirectUrl($this->getCancelUrl());
+    return $return;
+  }
+
+}
diff --git a/src/Plugin/views/field/MembershipEntityLink.php b/src/Plugin/views/field/MembershipEntityLink.php
index 2657756..9a62d30 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();
-- 
GitLab


From cd56bb99e5e6a34a597b0c26c57c66850bf90109 Mon Sep 17 00:00:00 2001
From: ekes <ekes@iskra.net>
Date: Wed, 16 Apr 2025 17:28:58 +0200
Subject: [PATCH 2/6] D11 compatibility.

---
 config/optional/views.view.group_pending_nodes.yml       | 1 -
 .../Validation/Constraint/GroupNodeRequestValidator.php  | 9 +--------
 tests/src/Kernel/GroupNodeRequestAccessTest.php          | 2 +-
 tests/src/Kernel/GroupNodeRequestConfigTest.php          | 1 -
 4 files changed, 2 insertions(+), 11 deletions(-)

diff --git a/config/optional/views.view.group_pending_nodes.yml b/config/optional/views.view.group_pending_nodes.yml
index 926098e..f8181b2 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/src/Plugin/Validation/Constraint/GroupNodeRequestValidator.php b/src/Plugin/Validation/Constraint/GroupNodeRequestValidator.php
index 64ac29b..7657f31 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/tests/src/Kernel/GroupNodeRequestAccessTest.php b/tests/src/Kernel/GroupNodeRequestAccessTest.php
index 556a364..351ac53 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 dca262d..7f3cce7 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',
-- 
GitLab


From c0bb15bf86c6c5206c2b8952283cedf39f2172b8 Mon Sep 17 00:00:00 2001
From: ekes <ekes@iskra.net>
Date: Fri, 18 Apr 2025 14:15:05 +0200
Subject: [PATCH 3/6] Restrict access to group content by group.

---
 gnode_request.routing.yml                        |  2 ++
 .../src/Functional/GroupNodeRequestFormTest.php  | 16 ++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/gnode_request.routing.yml b/gnode_request.routing.yml
index 18505ab..1f6957e 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/tests/src/Functional/GroupNodeRequestFormTest.php b/tests/src/Functional/GroupNodeRequestFormTest.php
index 62fe424..12d2119 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);
 
-- 
GitLab


From 5ef85a1c5cf2a4b4f436822a6f614b27a47b8c34 Mon Sep 17 00:00:00 2001
From: ekes <ekes@iskra.net>
Date: Fri, 18 Apr 2025 14:15:54 +0200
Subject: [PATCH 4/6] Differentiate workflow from grequest modules.

---
 gnode_request.workflows.yml                                 | 6 +++---
 .../Group/RelationHandler/GroupNodeRequestPostInstall.php   | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/gnode_request.workflows.yml b/gnode_request.workflows.yml
index 41b3e24..eac3f1b 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/GroupNodeRequestPostInstall.php b/src/Plugin/Group/RelationHandler/GroupNodeRequestPostInstall.php
index 0ebfe9e..b66d0b1 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();
-- 
GitLab


From 5e8c35b862a26c7c47ae0474a9744390c9449e5a Mon Sep 17 00:00:00 2001
From: ekes <ekes@iskra.net>
Date: Fri, 18 Apr 2025 14:16:24 +0200
Subject: [PATCH 5/6] Differentiate views field from grequest action.

---
 src/Plugin/views/field/ApproveMembership.php | 2 +-
 src/Plugin/views/field/RejectMembership.php  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Plugin/views/field/ApproveMembership.php b/src/Plugin/views/field/ApproveMembership.php
index a7e696a..faad34b 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/RejectMembership.php b/src/Plugin/views/field/RejectMembership.php
index c30ea9f..d162bdf 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');
   }
 
 }
-- 
GitLab


From 9b0c868fd48f18a69a8667be022bb0f52bae909f Mon Sep 17 00:00:00 2001
From: ekes <ekes@iskra.net>
Date: Fri, 18 Apr 2025 15:40:49 +0200
Subject: [PATCH 6/6] Remove form to request membership.

An existing node can be added with the create default create
relationship form.

The location where this would be useful would be a view field, but this
would then want to be in a list of nodes not in a group. The form
requiring the group that it is to go into.
---
 src/Entity/Form/GroupNodeRequestForm.php      |  90 -------------
 .../GroupNodeRequestOperationProvider.php     |  80 -----------
 src/Plugin/views/field/RequestMembership.php  | 126 ------------------
 3 files changed, 296 deletions(-)
 delete mode 100644 src/Entity/Form/GroupNodeRequestForm.php
 delete mode 100644 src/Plugin/Group/RelationHandler/GroupNodeRequestOperationProvider.php
 delete mode 100644 src/Plugin/views/field/RequestMembership.php

diff --git a/src/Entity/Form/GroupNodeRequestForm.php b/src/Entity/Form/GroupNodeRequestForm.php
deleted file mode 100644
index f7b28db..0000000
--- a/src/Entity/Form/GroupNodeRequestForm.php
+++ /dev/null
@@ -1,90 +0,0 @@
-<?php
-
-namespace Drupal\gnode_request\Entity\Form;
-
-use Drupal\Component\Datetime\TimeInterface;
-use Drupal\Core\Entity\EntityRepositoryInterface;
-use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\gnode_request\GnodeRequestManager;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Provides a form for requesting a group membership.
- */
-class GroupNodeRequestForm extends GroupRelationshipBaseForm {
-
-  /**
-   * Membership request manager.
-   *
-   * @var \Drupal\gnode_request\GnodeRequestManager
-   */
-  protected $gnodeRequestManager;
-
-  /**
-   * Constructs a request membership form.
-   *
-   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
-   *   The entity repository service.
-   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
-   *   The entity type bundle service.
-   * @param \Drupal\Component\Datetime\TimeInterface $time
-   *   The time service.
-   * @param \Drupal\gnode_request\GnodeRequestManager $gnode_request_manager
-   *   Membership request manager.
- */
-  public function __construct(EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info, TimeInterface $time, GnodeRequestManager $gnode_request_manager) {
-    parent::__construct($entity_repository, $entity_type_bundle_info, $time);
-    $this->gnodeRequestManager = $gnode_request_manager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('entity.repository'),
-      $container->get('entity_type.bundle.info'),
-      $container->get('datetime.time'),
-      $container->get('gnode_request.gnode_request_manager')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function actions(array $form, FormStateInterface $form_state) {
-    $actions = parent::actions($form, $form_state);
-    $actions['submit']['#value'] = $this->t('Request group membership');
-    $actions['cancel'] = [
-      '#type' => 'link',
-      '#title' => $this->t('Cancel'),
-      '#url' => $this->getCancelUrl(),
-    ];
-
-    return $actions;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, FormStateInterface $form_state) {
-    $form = parent::buildForm($form, $form_state);
-    $form['#attached']['library'][] = 'core/drupal.form';
-    // Make field not accessible, because we set it programmatically.
-    $form['entity_id']['#access'] = FALSE;
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function save(array $form, FormStateInterface $form_state) {
-    $return = parent::save($form, $form_state);
-
-    $this->messenger()->addMessage($this->t('Your request is waiting for approval'));
-    $form_state->setRedirectUrl($this->getCancelUrl());
-    return $return;
-  }
-
-}
diff --git a/src/Plugin/Group/RelationHandler/GroupNodeRequestOperationProvider.php b/src/Plugin/Group/RelationHandler/GroupNodeRequestOperationProvider.php
deleted file mode 100644
index f04cd23..0000000
--- 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/views/field/RequestMembership.php b/src/Plugin/views/field/RequestMembership.php
deleted file mode 100644
index 00d1b14..0000000
--- 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;
-  }
-
-}
-- 
GitLab