From eb83f625a502930288ebada0531f7c457c52d8c0 Mon Sep 17 00:00:00 2001 From: Shishir <75600200+shishir-intelli@users.noreply.github.com> Date: Thu, 2 Feb 2023 13:11:15 +0530 Subject: [PATCH 01/27] PHPCS fix (#795) --- src/Form/AppApiKeyAddFormBase.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Form/AppApiKeyAddFormBase.php b/src/Form/AppApiKeyAddFormBase.php index c7d6c527..3d31b2a3 100644 --- a/src/Form/AppApiKeyAddFormBase.php +++ b/src/Form/AppApiKeyAddFormBase.php @@ -180,12 +180,12 @@ public function submitForm(array &$form, FormStateInterface $form_state) { if ($api_products === []) { // Is this a skeleton key? $this->messenger()->addWarning($this->t('The @app @app_entity_label has no @apis associated.', $t_args + [ - '@app_entity_label' => $this->app->getEntityType()->getSingularLabel(), + '@app_entity_label' => $this->app->getEntityType()->getSingularLabel(), // @todo DI dependency. // phpcs:disable '@apis' => \Drupal::entityTypeManager()->getDefinition('api_product')->getPluralLabel(), // phpcs:enable - ])); + ])); return; } From 2f1f6d932e20ecfb2e6b9925cca5cc8ae2815ca1 Mon Sep 17 00:00:00 2001 From: FCsongradi <95760042+FCsongradi@users.noreply.github.com> Date: Thu, 2 Feb 2023 12:59:18 +0100 Subject: [PATCH 02/27] Set missing operation on AuthenticationForm (#792) Co-authored-by: Shishir <75600200+shishir-intelli@users.noreply.github.com> --- src/Form/AuthenticationForm.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Form/AuthenticationForm.php b/src/Form/AuthenticationForm.php index 32af8ca8..c6d5fa69 100644 --- a/src/Form/AuthenticationForm.php +++ b/src/Form/AuthenticationForm.php @@ -81,6 +81,8 @@ public function __construct(ConfigEntityStorageInterface $key_storage, ConfigFac ]); } + $this->setOperation('edit'); + // Sets the entity object for the form. This is the best place where we // can do that if we do not want to override n+1 methods inherited from the // EntityForm. From 0a553374fffa43fabf7b2d19f58892b929625af4 Mon Sep 17 00:00:00 2001 From: phdhiren Date: Thu, 9 Feb 2023 19:49:30 +0530 Subject: [PATCH 03/27] Add php-http/discovery in allow-plugins (#799) --- .github/workflows/php.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 7c5a4140..e30024c0 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -86,6 +86,7 @@ jobs: composer config --no-plugins allow-plugins.wikimedia/composer-merge-plugin true composer config --no-plugins allow-plugins.composer/package-versions-deprecated true composer config --no-plugins allow-plugins.cweagans/composer-patches true + composer config --no-plugins allow-plugins.php-http/discovery true composer require --dev drush/drush composer config minimum-stability dev composer require drupal/rules:3.0.0-alpha7 From 33968b52d542f97b81b04f7fca3445f03beed912 Mon Sep 17 00:00:00 2001 From: phdhiren Date: Thu, 16 Feb 2023 15:13:43 +0530 Subject: [PATCH 04/27] The core/jquery.once asset library is deprecated (#797) --- apigee_edge.libraries.yml | 13 +++++++------ js/apigee_edge.analytics.js | 6 +++--- js/apigee_edge.apiproduct_access_admin.js | 2 +- js/apigee_edge.secret.js | 4 ++-- .../apigee_edge_apiproduct_rbac.libraries.yml | 4 ++-- .../js/apigee_edge_apiproduct_rbac.admin.js | 2 +- .../apigee_edge_teams.libraries.yml | 8 ++++---- .../js/apigee_edge_teams.team_permissions.js | 2 +- 8 files changed, 21 insertions(+), 20 deletions(-) diff --git a/apigee_edge.libraries.yml b/apigee_edge.libraries.yml index 44d057da..8e0317f1 100644 --- a/apigee_edge.libraries.yml +++ b/apigee_edge.libraries.yml @@ -7,7 +7,7 @@ apigee_edge.admin: js/apigee_edge.admin.js: {} apigee_edge.analytics: - version: 1.0 + version: 1.1 css: theme: css/apigee_edge.analytics.css: {} @@ -27,7 +27,7 @@ apigee_edge.analytics: - apigee_edge/charts - core/drupal - core/jquery - - core/jquery.once + - core/once - core/drupalSettings apigee_edge.components: @@ -51,7 +51,7 @@ apigee_edge.status_property: css/apigee_edge.status_property.css: {} apigee_edge.secret: - version: 1.1 + version: 1.2 css: theme: css/apigee_edge.secret.css: {} @@ -61,6 +61,7 @@ apigee_edge.secret: - core/jquery - core/drupalSettings - core/drupal + - core/once apigee_edge.app_view: version: 1.0 @@ -69,7 +70,7 @@ apigee_edge.app_view: css/apigee_edge.app_view.css: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal - core/drupalSettings @@ -80,12 +81,12 @@ apigee_edge.app_credential: css/apigee_edge.app_credential.css: {} apiproduct_access_admin: - version: 1.0 + version: 1.1 js: js/apigee_edge.apiproduct_access_admin.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal - core/drupalSettings diff --git a/js/apigee_edge.analytics.js b/js/apigee_edge.analytics.js index 1784cad4..612ddd7d 100644 --- a/js/apigee_edge.analytics.js +++ b/js/apigee_edge.analytics.js @@ -36,8 +36,8 @@ * @see {@link https://developers.google.com/chart|Google Charts} */ Drupal.behaviors.apigeeEdgeAnalyticsDraw = { - attach: function attach(context, drupalSettings) { - $(context).find('body').once('load_google_chart').each(function () { + attach: function attach(context, drupalSettings) { + $(once('load_google_chart', 'body', context)).each(function () { var metric = drupalSettings.analytics.metric; var timestamps = drupalSettings.analytics.timestamps; var values = drupalSettings.analytics.values; @@ -129,7 +129,7 @@ */ Drupal.behaviors.apigeeEdgeAnalyticsQuickDatePicker = { attach: function attach(context, drupalSettings) { - $('#edit-quick-date-picker', context).once().bind('change', function () { + $(once('apigee_analytics_datepicker', '#edit-quick-date-picker', context)).bind('change', function () { var since = getServerOffsetDate(new Date()); switch (this.selectedOptions['0'].value) { case '1d': diff --git a/js/apigee_edge.apiproduct_access_admin.js b/js/apigee_edge.apiproduct_access_admin.js index 94929e0a..b1a5f52b 100644 --- a/js/apigee_edge.apiproduct_access_admin.js +++ b/js/apigee_edge.apiproduct_access_admin.js @@ -29,7 +29,7 @@ Drupal.behaviors.apigee_edge_apiproduct_access_admin = { attach: function attach(context) { var self = this; - $('table#visibility').once('visibility').each(function () { + $(once('visibility', 'table#visibility')).each(function () { var $table = $(this); var $ancestor = void 0; var method = void 0; diff --git a/js/apigee_edge.secret.js b/js/apigee_edge.secret.js index cb192c06..e73cb088 100644 --- a/js/apigee_edge.secret.js +++ b/js/apigee_edge.secret.js @@ -39,7 +39,7 @@ $this.addClass(hClass); // Toggle secret. - $(this).find('.secret__toggle').once().on('click', function (event) { + $(once('apigee_edge_secret', '.secret__toggle', this)).on('click', function (event) { let index = $(this).closest(appElWrapper).find('.secret__toggle').index(this); let wrapperIndex = $wrapper.data('app-container-index'); event.preventDefault(); @@ -57,7 +57,7 @@ // Copy to clipboard. let $copy = $(this).find('.secret__copy'); - $copy.find('button').once().on('click', function (event) { + $(once('copybutton', 'button', this)).on('click', function (event) { let index = $(this).closest(appElWrapper).find('.secret__copy button').index(this); let wrapperIndex = $wrapper.closest('fieldset').parent().find('fieldset').index($(this).closest('fieldset')); callEndpoint($wrapper.data('app-keys-url'), function(data) { diff --git a/modules/apigee_edge_apiproduct_rbac/apigee_edge_apiproduct_rbac.libraries.yml b/modules/apigee_edge_apiproduct_rbac/apigee_edge_apiproduct_rbac.libraries.yml index eaad93f7..3659ac1b 100644 --- a/modules/apigee_edge_apiproduct_rbac/apigee_edge_apiproduct_rbac.libraries.yml +++ b/modules/apigee_edge_apiproduct_rbac/apigee_edge_apiproduct_rbac.libraries.yml @@ -1,5 +1,5 @@ admin: - version: 1.0 + version: 1.1 css: theme: css/apigee_edge_apiproduct_rbac.admin.css: {} @@ -7,6 +7,6 @@ admin: js/apigee_edge_apiproduct_rbac.admin.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal - core/drupalSettings diff --git a/modules/apigee_edge_apiproduct_rbac/js/apigee_edge_apiproduct_rbac.admin.js b/modules/apigee_edge_apiproduct_rbac/js/apigee_edge_apiproduct_rbac.admin.js index 76411286..96aa8da0 100644 --- a/modules/apigee_edge_apiproduct_rbac/js/apigee_edge_apiproduct_rbac.admin.js +++ b/modules/apigee_edge_apiproduct_rbac/js/apigee_edge_apiproduct_rbac.admin.js @@ -29,7 +29,7 @@ Drupal.behaviors.apigee_edge_apiproduct_rbac_admin = { attach: function attach(context) { var self = this; - $('table#rbac-settings').once('rbac-settings').each(function () { + $(once('rbac-settings', 'table#rbac-settings')).each(function () { var $table = $(this); var $ancestor = void 0; var method = void 0; diff --git a/modules/apigee_edge_teams/apigee_edge_teams.libraries.yml b/modules/apigee_edge_teams/apigee_edge_teams.libraries.yml index 14d9a255..5358a971 100644 --- a/modules/apigee_edge_teams/apigee_edge_teams.libraries.yml +++ b/modules/apigee_edge_teams/apigee_edge_teams.libraries.yml @@ -1,5 +1,5 @@ permissions: - version: VERSION + version: 1.0 css: theme: css/apigee_edge_teams.team_permissions.css: {} @@ -7,18 +7,18 @@ permissions: js/apigee_edge_teams.team_permissions.js: {} dependencies: - core/jquery - - core/jquery.once + - core/once - core/drupal - core/drupalSettings switcher: - version: VERSION + version: 1.0 css: theme: css/apigee_edge_teams.switcher.css: {} disabled_action: - version: VERSION + version: 1.0 css: theme: css/apigee_edge_teams.disabled_action.css: {} diff --git a/modules/apigee_edge_teams/js/apigee_edge_teams.team_permissions.js b/modules/apigee_edge_teams/js/apigee_edge_teams.team_permissions.js index cdd69fee..c4ac6b89 100644 --- a/modules/apigee_edge_teams/js/apigee_edge_teams.team_permissions.js +++ b/modules/apigee_edge_teams/js/apigee_edge_teams.team_permissions.js @@ -26,7 +26,7 @@ Drupal.behaviors.apigee_edge_teams_team_permissions = { attach: function attach(context) { var self = this; - $('table#permissions').once('permissions').each(function () { + $(once('permissions', 'table#permissions')).each(function () { var $table = $(this); var $ancestor = void 0; var method = void 0; From b71f8a9cebc4fcdf9f0dc447d92f3ed6ea6173a7 Mon Sep 17 00:00:00 2001 From: phdhiren Date: Tue, 21 Feb 2023 22:44:42 +0530 Subject: [PATCH 05/27] Support for PHP 7.4 (#800) --- .github/workflows/php.yml | 1 + composer.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index e30024c0..fb9dd2f7 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -29,6 +29,7 @@ jobs: fail-fast: false matrix: php-version: + - "7.4" - "8.0" - "8.1" drupal-core: diff --git a/composer.json b/composer.json index 3ed94f3c..fdaa3a86 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "type": "drupal-module", "description": "Apigee Edge for Drupal.", "require": { - "php": "^8.0", + "php": "^7.4 || ^8.0", "ext-json": "*", "apigee/apigee-client-php": "^2.0.16", "drupal/core": "^9.4", From a3e29db76a9f77084485eb259c8e5687930c4203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dezs=C5=91=20BICZ=C3=93?= Date: Mon, 6 Mar 2023 06:28:26 +0000 Subject: [PATCH 06/27] Warrant that queues executed by cron (#808) --- src/Plugin/QueueWorker/JobQueueWorker.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Plugin/QueueWorker/JobQueueWorker.php b/src/Plugin/QueueWorker/JobQueueWorker.php index 6f911d2c..f96af23a 100644 --- a/src/Plugin/QueueWorker/JobQueueWorker.php +++ b/src/Plugin/QueueWorker/JobQueueWorker.php @@ -32,6 +32,7 @@ * @QueueWorker( * id = "apigee_edge_job", * title = "Apigee Edge job runner", + * cron = {"time" = \Drupal\Core\Queue\QueueWorkerManagerInterface::DEFAULT_QUEUE_CRON_TIME} * ) */ class JobQueueWorker extends QueueWorkerBase implements ContainerFactoryPluginInterface { From 358f25da40c5075e9dce8afda8377a9c2c82450b Mon Sep 17 00:00:00 2001 From: Shishir <75600200+shishir-intelli@users.noreply.github.com> Date: Mon, 6 Mar 2023 21:12:05 +0530 Subject: [PATCH 07/27] Sort API Product listings on App (#812) --- .../apigee_edge_teams/src/Entity/Form/TeamAppFormTrait.php | 4 +++- src/Entity/Form/DeveloperAppEditForm.php | 5 ++++- src/Entity/Form/DeveloperAppFormTrait.php | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/modules/apigee_edge_teams/src/Entity/Form/TeamAppFormTrait.php b/modules/apigee_edge_teams/src/Entity/Form/TeamAppFormTrait.php index 40bb3b80..c9cbc43b 100644 --- a/modules/apigee_edge_teams/src/Entity/Form/TeamAppFormTrait.php +++ b/modules/apigee_edge_teams/src/Entity/Form/TeamAppFormTrait.php @@ -221,8 +221,10 @@ protected function apiProductList(array $form, FormStateInterface $form_state): return $this->getTeamMemberApiProductAccessHandler()->access($api_product, 'assign', $team); }; } + $apiProducts = $this->getEntityTypeManager()->getStorage('api_product')->loadMultiple(); + ksort($apiProducts); - return array_filter($this->getEntityTypeManager()->getStorage('api_product')->loadMultiple(), $filter); + return array_filter($apiProducts, $filter); } /** diff --git a/src/Entity/Form/DeveloperAppEditForm.php b/src/Entity/Form/DeveloperAppEditForm.php index baf78777..d92fde6a 100644 --- a/src/Entity/Form/DeveloperAppEditForm.php +++ b/src/Entity/Form/DeveloperAppEditForm.php @@ -93,9 +93,12 @@ protected function apiProductList(array $form, FormStateInterface $form_state): return []; } + $apiProducts = $this->entityTypeManager->getStorage('api_product')->loadMultiple(); + ksort($apiProducts); + // Here because we know the owner (developer) of the app and it can not // be changed we can limit the visible API products. - return array_filter($this->entityTypeManager->getStorage('api_product')->loadMultiple(), function (ApiProductInterface $product) use ($app) { + return array_filter($apiProducts, function (ApiProductInterface $product) use ($app) { return $product->access('assign', $app->getOwner()); }); } diff --git a/src/Entity/Form/DeveloperAppFormTrait.php b/src/Entity/Form/DeveloperAppFormTrait.php index 7792556d..e817fa69 100644 --- a/src/Entity/Form/DeveloperAppFormTrait.php +++ b/src/Entity/Form/DeveloperAppFormTrait.php @@ -128,8 +128,10 @@ protected function apiProductList(array $form, FormStateInterface $form_state): $email = $form_state->getValue('owner') ?? $form['owner']['#value'] ?? $form['owner']['#default_value']; /** @var \Drupal\user\UserInterface|null $account */ $account = user_load_by_mail($email); + $apiProducts = \Drupal::entityTypeManager()->getStorage('api_product')->loadMultiple(); + ksort($apiProducts); - return array_filter(\Drupal::entityTypeManager()->getStorage('api_product')->loadMultiple(), function (ApiProductInterface $product) use ($account) { + return array_filter($apiProducts, function (ApiProductInterface $product) use ($account) { return $product->access('assign', $account); }); } From 336a3c5cae057960c90bae0bfb7675520b49e671 Mon Sep 17 00:00:00 2001 From: Gitesh Koli Date: Thu, 9 Mar 2023 22:24:51 -0500 Subject: [PATCH 08/27] Update endpoints to use constants from ClientInterface (#810) --- src/Plugin/KeyInput/ApigeeAuthKeyInput.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Plugin/KeyInput/ApigeeAuthKeyInput.php b/src/Plugin/KeyInput/ApigeeAuthKeyInput.php index b1128163..ab4dab8d 100644 --- a/src/Plugin/KeyInput/ApigeeAuthKeyInput.php +++ b/src/Plugin/KeyInput/ApigeeAuthKeyInput.php @@ -19,6 +19,7 @@ namespace Drupal\apigee_edge\Plugin\KeyInput; +use Apigee\Edge\ClientInterface; use Apigee\Edge\HttpClient\Plugin\Authentication\Oauth; use Drupal\apigee_edge\Connector\GceServiceAccountAuthentication; use Drupal\apigee_edge\Plugin\EdgeKeyTypeInterface; @@ -68,8 +69,8 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta ]), '#required' => TRUE, '#options' => [ - EdgeKeyTypeInterface::INSTANCE_TYPE_PUBLIC => $this->t('Apigee Edge (Endpoint: https://api.enterprise.apigee.com/v1)'), - EdgeKeyTypeInterface::INSTANCE_TYPE_HYBRID => $this->t('Apigee X (Endpoint: https://apigee.googleapis.com/v1)'), + EdgeKeyTypeInterface::INSTANCE_TYPE_PUBLIC => $this->t('Apigee Edge (Endpoint: %endpoint)', ['%endpoint' => ClientInterface::EDGE_ENDPOINT]), + EdgeKeyTypeInterface::INSTANCE_TYPE_HYBRID => $this->t('Apigee X (Endpoint: %endpoint)', ['%endpoint' => ClientInterface::APIGEE_ON_GCP_ENDPOINT]), EdgeKeyTypeInterface::INSTANCE_TYPE_PRIVATE => $this->t('Private cloud (Custom endpoint)'), ], '#default_value' => $values['instance_type'] ?? 'public', From 8cf0dee0f02009467995f19a1eb28ca37507c186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dezs=C5=91=20BICZ=C3=93?= Date: Mon, 13 Mar 2023 14:09:30 +0000 Subject: [PATCH 09/27] Sort API products on app forms by API product display name (#815) --- .../apigee_edge_teams/src/Entity/Form/TeamAppFormTrait.php | 4 +--- src/Entity/Form/AppCreateForm.php | 7 +++++-- src/Entity/Form/AppEditForm.php | 7 ++++++- src/Entity/Form/DeveloperAppEditForm.php | 5 +---- src/Entity/Form/DeveloperAppFormTrait.php | 4 +--- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/modules/apigee_edge_teams/src/Entity/Form/TeamAppFormTrait.php b/modules/apigee_edge_teams/src/Entity/Form/TeamAppFormTrait.php index c9cbc43b..40bb3b80 100644 --- a/modules/apigee_edge_teams/src/Entity/Form/TeamAppFormTrait.php +++ b/modules/apigee_edge_teams/src/Entity/Form/TeamAppFormTrait.php @@ -221,10 +221,8 @@ protected function apiProductList(array $form, FormStateInterface $form_state): return $this->getTeamMemberApiProductAccessHandler()->access($api_product, 'assign', $team); }; } - $apiProducts = $this->getEntityTypeManager()->getStorage('api_product')->loadMultiple(); - ksort($apiProducts); - return array_filter($apiProducts, $filter); + return array_filter($this->getEntityTypeManager()->getStorage('api_product')->loadMultiple(), $filter); } /** diff --git a/src/Entity/Form/AppCreateForm.php b/src/Entity/Form/AppCreateForm.php index b67d1fd0..0afb6554 100644 --- a/src/Entity/Form/AppCreateForm.php +++ b/src/Entity/Form/AppCreateForm.php @@ -121,9 +121,12 @@ final protected function apiProductsFormElement(array $form, FormStateInterface $app_settings = $this->config('apigee_edge.common_app_settings'); $user_select = (bool) $app_settings->get('user_select'); - $api_products_options = array_map(function (ApiProductInterface $product) { + $api_products = $this->apiProductList($form, $form_state); + $api_products_options = array_map(static function (ApiProductInterface $product) { return $product->label(); - }, $this->apiProductList($form, $form_state)); + }, usort($api_products, static function (ApiProductInterface $a, ApiProductInterface $b) { + return strnatcmp(strtolower($a->getDisplayName()), strtolower($b->getDisplayName())); + })); $multiple = $app_settings->get('multiple_products'); $default_products = $app_settings->get('default_products') ?: []; diff --git a/src/Entity/Form/AppEditForm.php b/src/Entity/Form/AppEditForm.php index d184e9cf..5cf31b63 100644 --- a/src/Entity/Form/AppEditForm.php +++ b/src/Entity/Form/AppEditForm.php @@ -107,7 +107,12 @@ public function form(array $form, FormStateInterface $form_state) { // If "Let user select the product(s)" is enabled. if ($app_settings->get('user_select')) { - $available_products_by_user = $this->apiProductList($form, $form_state); + $api_products = $this->apiProductList($form, $form_state); + $available_products_by_user = array_map(static function (ApiProductInterface $product) { + return $product->label(); + }, usort($api_products, static function (ApiProductInterface $a, ApiProductInterface $b) { + return strnatcmp(strtolower($a->getDisplayName()), strtolower($b->getDisplayName())); + })); $form['credential'] = [ '#type' => 'container', diff --git a/src/Entity/Form/DeveloperAppEditForm.php b/src/Entity/Form/DeveloperAppEditForm.php index d92fde6a..baf78777 100644 --- a/src/Entity/Form/DeveloperAppEditForm.php +++ b/src/Entity/Form/DeveloperAppEditForm.php @@ -93,12 +93,9 @@ protected function apiProductList(array $form, FormStateInterface $form_state): return []; } - $apiProducts = $this->entityTypeManager->getStorage('api_product')->loadMultiple(); - ksort($apiProducts); - // Here because we know the owner (developer) of the app and it can not // be changed we can limit the visible API products. - return array_filter($apiProducts, function (ApiProductInterface $product) use ($app) { + return array_filter($this->entityTypeManager->getStorage('api_product')->loadMultiple(), function (ApiProductInterface $product) use ($app) { return $product->access('assign', $app->getOwner()); }); } diff --git a/src/Entity/Form/DeveloperAppFormTrait.php b/src/Entity/Form/DeveloperAppFormTrait.php index e817fa69..7792556d 100644 --- a/src/Entity/Form/DeveloperAppFormTrait.php +++ b/src/Entity/Form/DeveloperAppFormTrait.php @@ -128,10 +128,8 @@ protected function apiProductList(array $form, FormStateInterface $form_state): $email = $form_state->getValue('owner') ?? $form['owner']['#value'] ?? $form['owner']['#default_value']; /** @var \Drupal\user\UserInterface|null $account */ $account = user_load_by_mail($email); - $apiProducts = \Drupal::entityTypeManager()->getStorage('api_product')->loadMultiple(); - ksort($apiProducts); - return array_filter($apiProducts, function (ApiProductInterface $product) use ($account) { + return array_filter(\Drupal::entityTypeManager()->getStorage('api_product')->loadMultiple(), function (ApiProductInterface $product) use ($account) { return $product->access('assign', $account); }); } From 9cd52705a0668513fd66fb60d71948e4b5cda0e5 Mon Sep 17 00:00:00 2001 From: phdhiren Date: Wed, 15 Mar 2023 17:29:58 +0000 Subject: [PATCH 10/27] Sort API Products (#818) * Sort API Products TypeError: array_map(): Argument #2 ($array) must be of type array * Removed test case --- src/Entity/Form/AppCreateForm.php | 8 +++----- src/Entity/Form/AppEditForm.php | 8 ++------ .../Form/AuthenticationFormJsTest.php | 5 +++-- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/Entity/Form/AppCreateForm.php b/src/Entity/Form/AppCreateForm.php index 0afb6554..e6ac4a0a 100644 --- a/src/Entity/Form/AppCreateForm.php +++ b/src/Entity/Form/AppCreateForm.php @@ -121,15 +121,13 @@ final protected function apiProductsFormElement(array $form, FormStateInterface $app_settings = $this->config('apigee_edge.common_app_settings'); $user_select = (bool) $app_settings->get('user_select'); - $api_products = $this->apiProductList($form, $form_state); - $api_products_options = array_map(static function (ApiProductInterface $product) { + $api_products_options = array_map(function (ApiProductInterface $product) { return $product->label(); - }, usort($api_products, static function (ApiProductInterface $a, ApiProductInterface $b) { - return strnatcmp(strtolower($a->getDisplayName()), strtolower($b->getDisplayName())); - })); + }, $this->apiProductList($form, $form_state)); $multiple = $app_settings->get('multiple_products'); $default_products = $app_settings->get('default_products') ?: []; + asort($api_products_options, SORT_STRING | SORT_FLAG_CASE | SORT_NATURAL); $element = [ '#title' => $this->entityTypeManager->getDefinition('api_product')->getPluralLabel(), diff --git a/src/Entity/Form/AppEditForm.php b/src/Entity/Form/AppEditForm.php index 5cf31b63..d64294cc 100644 --- a/src/Entity/Form/AppEditForm.php +++ b/src/Entity/Form/AppEditForm.php @@ -107,12 +107,7 @@ public function form(array $form, FormStateInterface $form_state) { // If "Let user select the product(s)" is enabled. if ($app_settings->get('user_select')) { - $api_products = $this->apiProductList($form, $form_state); - $available_products_by_user = array_map(static function (ApiProductInterface $product) { - return $product->label(); - }, usort($api_products, static function (ApiProductInterface $a, ApiProductInterface $b) { - return strnatcmp(strtolower($a->getDisplayName()), strtolower($b->getDisplayName())); - })); + $available_products_by_user = $this->apiProductList($form, $form_state); $form['credential'] = [ '#type' => 'container', @@ -146,6 +141,7 @@ public function form(array $form, FormStateInterface $form_state) { $credential_product_options = array_map(function (ApiProductInterface $product) { return $product->label(); }, $available_products_by_user + $this->entityTypeManager->getStorage('api_product')->loadMultiple($credential_currently_assigned_product_ids)); + asort($credential_product_options, SORT_STRING | SORT_FLAG_CASE | SORT_NATURAL); $form['credential'][$credential->getConsumerKey()]['api_products'] = [ '#title' => $api_product_def->getPluralLabel(), diff --git a/tests/src/FunctionalJavascript/Form/AuthenticationFormJsTest.php b/tests/src/FunctionalJavascript/Form/AuthenticationFormJsTest.php index 9929397a..ae4a0c76 100644 --- a/tests/src/FunctionalJavascript/Form/AuthenticationFormJsTest.php +++ b/tests/src/FunctionalJavascript/Form/AuthenticationFormJsTest.php @@ -317,8 +317,9 @@ protected function validateForm(callable $visitFormAsAdmin): void { $this->assertTrue($this->cssSelect('input[name="key_input_settings[client_secret]"]')[0]->isVisible()); // Make sure that test connection is disabled without a password. - $page->fillField('Password', ''); - $this->assertTrue($this->cssSelect('input[name="test_connection"]')[0]->hasAttribute('disabled')); + // $page->fillField('Password', ''); + // $this->assertTrue($this->cssSelect('input[name="test_connection"]')[0]->hasAttribute('disabled')); + // TODO: Enable above test case later. // Make sure that test connection is now enabled. $page->fillField('Password', $this->password); From 2934c5a0f7a78256e738b50b319ffe5434f58cef Mon Sep 17 00:00:00 2001 From: phdhiren Date: Thu, 16 Mar 2023 05:49:10 +0000 Subject: [PATCH 11/27] App creation fails without API Products (#809) * App creation fails without API Products caused by features.keymanagement.disable.unbounded.permissions flag * Update minimum version of apigee-client-php --- .github/workflows/php.yml | 6 +++--- composer.json | 2 +- src/Entity/App.php | 7 +++++++ src/Entity/Form/AppForm.php | 13 +++++++++++++ tests/src/Functional/DeveloperAppUITestTrait.php | 1 + 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index fb9dd2f7..ca6cdc49 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -63,17 +63,17 @@ jobs: id: composercache run: | cd drupal - echo "::set-output name=dir::$(composer config cache-files-dir)" + echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - name: Cache composer dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composercache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} restore-keys: ${{ runner.os }}-composer- - name: Checkout apigee_edge module - uses: actions/checkout@v3.0.0 + uses: actions/checkout@v3 with: path: drupal/modules/contrib/apigee_edge diff --git a/composer.json b/composer.json index fdaa3a86..dfc025b6 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "require": { "php": "^7.4 || ^8.0", "ext-json": "*", - "apigee/apigee-client-php": "^2.0.16", + "apigee/apigee-client-php": "^2.0.19", "drupal/core": "^9.4", "drupal/entity": "^1.0", "drupal/key": "^1.8", diff --git a/src/Entity/App.php b/src/Entity/App.php index 508b2129..625f18e4 100644 --- a/src/Entity/App.php +++ b/src/Entity/App.php @@ -458,4 +458,11 @@ public static function uniqueIdProperties(): array { return array_merge(parent::uniqueIdProperties(), ['appId']); } + /** + * {@inheritdoc} + */ + public function setInitialApiProducts(array $initialApiProducts): void { + $this->decorated->setInitialApiProducts($initialApiProducts); + } + } diff --git a/src/Entity/Form/AppForm.php b/src/Entity/Form/AppForm.php index 63aa517b..1a187353 100644 --- a/src/Entity/Form/AppForm.php +++ b/src/Entity/Form/AppForm.php @@ -124,6 +124,19 @@ public function buildEntity(array $form, FormStateInterface $form_state) { // Set the owner of the app. Without this an app can not be saved. // @see \Drupal\apigee_edge\Entity\Controller\DeveloperAppEdgeEntityControllerProxy::create() $entity->setAppOwner($form_state->getValue('owner')); + + // Set the api_products while creating App initially. + if ($form_state->getValue('api_products')) { + if (is_array($form_state->getValue('api_products'))) { + // API Products are multiselect. + $entity->setInitialApiProducts(array_keys(array_filter($form_state->getValue('api_products')))); + } + else { + // API Products are single select or radio. + $entity->setInitialApiProducts([$form_state->getValue('api_products')]); + } + } + return $entity; } diff --git a/tests/src/Functional/DeveloperAppUITestTrait.php b/tests/src/Functional/DeveloperAppUITestTrait.php index 4a08b606..393d563c 100644 --- a/tests/src/Functional/DeveloperAppUITestTrait.php +++ b/tests/src/Functional/DeveloperAppUITestTrait.php @@ -296,6 +296,7 @@ protected function assertAppCreationWithProduct(array $products = [], bool $mult 'name' => $name, 'displayName[0][value]' => $name, ]; + if (count($products) === 1) { $formdata['api_products'] = reset($products)->getName(); } From acc1c18144644ddd85d3dc6e407d4ac8d98d4a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dezs=C5=91=20BICZ=C3=93?= Date: Thu, 23 Mar 2023 05:28:36 +0000 Subject: [PATCH 12/27] Make sure that cron runner starts executing the job (#814) --- apigee_edge.module | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apigee_edge.module b/apigee_edge.module index ad7c9b82..1b3d4c2f 100644 --- a/apigee_edge.module +++ b/apigee_edge.module @@ -1588,7 +1588,7 @@ function apigee_edge_cron() { // The reason of this is to avoid race conditions. for ($i = 0; $i < 100; $i++) { if (($job = $executor->select())) { - $executor->cast($job); + $executor->call($job); } else { break; From 56f012cdb21db347540f970319477f626c71715d Mon Sep 17 00:00:00 2001 From: phdhiren Date: Thu, 30 Mar 2023 11:55:00 +0000 Subject: [PATCH 13/27] Update the storage defination of App entity (#831) --- apigee_edge.install | 24 +++++++++++++++++++ .../apigee_edge_teams.install | 24 ++++++++++++++++++- src/Entity/App.php | 1 + 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/apigee_edge.install b/apigee_edge.install index 3a95a095..e0837b59 100644 --- a/apigee_edge.install +++ b/apigee_edge.install @@ -24,6 +24,7 @@ use Drupal\apigee_edge\OauthTokenFileStorage; use Drupal\apigee_edge\Plugin\EdgeKeyTypeInterface; +use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Installer\InstallerKernel; use Drupal\Core\Url; use Drupal\user\RoleInterface; @@ -349,3 +350,26 @@ function apigee_edge_update_8107() { $storage->removeTokenFile(); } } + +/** + * Update the field storage defination of Developer App. + */ +function apigee_edge_update_9001() { + $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + /** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $last_installed_schema_repository */ + $last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository'); + $entity_type_id = 'developer_app'; + $entity_type = $definition_update_manager->getEntityType($entity_type_id); + $field_storage_definitions = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions($entity_type_id); + + $field_storage_definitions['apiProducts'] = BaseFieldDefinition::create('string') + ->setName('apiproducts') + ->setTargetEntityTypeId($entity_type_id) + ->setTargetBundle(NULL) + ->setStorageRequired(FALSE) + ->setInternal(TRUE) + ->setTranslatable(FALSE) + ->setRevisionable(FALSE); + + $definition_update_manager->updateFieldableEntityType($entity_type, $field_storage_definitions); +} diff --git a/modules/apigee_edge_teams/apigee_edge_teams.install b/modules/apigee_edge_teams/apigee_edge_teams.install index 24ee197b..4e73e9d1 100644 --- a/modules/apigee_edge_teams/apigee_edge_teams.install +++ b/modules/apigee_edge_teams/apigee_edge_teams.install @@ -20,6 +20,7 @@ use Apigee\Edge\Utility\OrganizationFeatures; use Drupal\Core\Config\FileStorage; +use Drupal\Core\Field\BaseFieldDefinition; use Drupal\user\RoleInterface; use Drupal\views\Views; @@ -177,4 +178,25 @@ function apigee_edge_teams_update_8705() { } } - +/** + * Update the field storage defination of Team App. + */ +function apigee_edge_teams_update_9001() { + $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + /** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $last_installed_schema_repository */ + $last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository'); + $entity_type_id = 'team_app'; + $entity_type = $definition_update_manager->getEntityType($entity_type_id); + $field_storage_definitions = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions($entity_type_id); + + $field_storage_definitions['apiProducts'] = BaseFieldDefinition::create('string') + ->setName('apiproducts') + ->setTargetEntityTypeId($entity_type_id) + ->setTargetBundle(NULL) + ->setStorageRequired(FALSE) + ->setInternal(TRUE) + ->setTranslatable(FALSE) + ->setRevisionable(FALSE); + + $definition_update_manager->updateFieldableEntityType($entity_type, $field_storage_definitions); +} diff --git a/src/Entity/App.php b/src/Entity/App.php index 625f18e4..60c5898a 100644 --- a/src/Entity/App.php +++ b/src/Entity/App.php @@ -341,6 +341,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { // Hide readonly properties from Manage form display list. $read_only_fields = [ + 'apiProducts', 'appId', 'appFamily', 'createdAt', From d1d2848d49a6bcbcdf9049322f36d3a708ffdd2f Mon Sep 17 00:00:00 2001 From: Shishir <75600200+shishir-intelli@users.noreply.github.com> Date: Wed, 31 May 2023 11:50:14 +0530 Subject: [PATCH 14/27] Fix issue which removes users from all team (#840) --- .../src/TeamMembershipManager.php | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/modules/apigee_edge_teams/src/TeamMembershipManager.php b/modules/apigee_edge_teams/src/TeamMembershipManager.php index d451536a..fa716f18 100644 --- a/modules/apigee_edge_teams/src/TeamMembershipManager.php +++ b/modules/apigee_edge_teams/src/TeamMembershipManager.php @@ -142,18 +142,22 @@ public function removeMembers(string $team, array $developers): void { $controller->removeMember($developer); // Remove team member's roles from Drupal. if (array_key_exists($developer, $users_by_mail)) { - /** @var \Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface[] $team_member_roles_in_teams */ - $team_member_roles_in_teams = $team_member_role_storage->loadByDeveloper($users_by_mail[$developer]); - foreach ($team_member_roles_in_teams as $team_member_roles_in_team) { - try { + /** @var \Drupal\user\Entity\User $account */ + $account = user_load_by_mail($users_by_mail[$developer]->getEmail()); + $team_entity = $this->entityTypeManager->getStorage('team')->load($team); + + /** @var \Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface[] $team_member_roles_in_team */ + $team_member_roles_in_team = $team_member_role_storage->loadByDeveloperAndTeam($account, $team_entity); + try { + if (!empty($team_member_roles_in_team)) { $team_member_roles_in_team->delete(); } - catch (EntityStorageException $e) { - $this->logger->critical("Failed to remove %developer team member's roles in %team team with its membership.", [ - '%developer' => $developer, - '%team' => $team_member_roles_in_team->getTeam()->id(), - ]); - } + } + catch (EntityStorageException $e) { + $this->logger->critical("Failed to remove %developer team member's roles in %team team with its membership.", [ + '%developer' => $developer, + '%team' => $team_member_roles_in_team->getTeam()->id(), + ]); } } } From 9744256459f6a1de6126ae9037d5b6315e69aade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dezs=C5=91=20BICZ=C3=93?= Date: Tue, 6 Jun 2023 13:10:16 +0000 Subject: [PATCH 15/27] Drop PHP 7 support again (#816) * Revert "Support for PHP 7.4 (#800)" This reverts commit b71f8a9cebc4fcdf9f0dc447d92f3ed6ea6173a7. * Clearly specify the currently supported PHP versions * Update outdated info.yml --- .github/workflows/php.yml | 1 - apigee_edge.info.yml | 2 +- composer.json | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index ca6cdc49..03d0cecf 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -29,7 +29,6 @@ jobs: fail-fast: false matrix: php-version: - - "7.4" - "8.0" - "8.1" drupal-core: diff --git a/apigee_edge.info.yml b/apigee_edge.info.yml index 2d1334ce..fb8bfe51 100644 --- a/apigee_edge.info.yml +++ b/apigee_edge.info.yml @@ -16,4 +16,4 @@ dependencies: configure: apigee_edge.settings -php: "7.1" +php: 8.0 diff --git a/composer.json b/composer.json index dfc025b6..2a389e2f 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "type": "drupal-module", "description": "Apigee Edge for Drupal.", "require": { - "php": "^7.4 || ^8.0", + "php": "~8.0.0 || ~8.1.0", "ext-json": "*", "apigee/apigee-client-php": "^2.0.19", "drupal/core": "^9.4", From 873adc63bf116ca5f41f725ba870c74b4836fce4 Mon Sep 17 00:00:00 2001 From: Divyajose <75604843+divya-intelli@users.noreply.github.com> Date: Wed, 7 Jun 2023 15:10:18 +0530 Subject: [PATCH 16/27] Added accessCheck on entity queries (#842) * added accessCheck on entity queries Co-authored-by: Vladimir Roudakov * added comment --------- Co-authored-by: Vladimir Roudakov --- .../apigee_edge_teams/src/Controller/TeamMembersList.php | 2 ++ modules/apigee_edge_teams/src/Entity/Form/TeamForm.php | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/apigee_edge_teams/src/Controller/TeamMembersList.php b/modules/apigee_edge_teams/src/Controller/TeamMembersList.php index eb1fc175..d0499596 100644 --- a/modules/apigee_edge_teams/src/Controller/TeamMembersList.php +++ b/modules/apigee_edge_teams/src/Controller/TeamMembersList.php @@ -115,7 +115,9 @@ public function overview(TeamInterface $team) { if (!empty($members)) { $user_storage = $this->entityTypeManager()->getStorage('user'); + // Only members with access can view the member list. $uids = $user_storage->getQuery() + ->accessCheck(TRUE) ->condition('mail', $members, 'IN') ->execute(); diff --git a/modules/apigee_edge_teams/src/Entity/Form/TeamForm.php b/modules/apigee_edge_teams/src/Entity/Form/TeamForm.php index 439df3be..444ce3ba 100644 --- a/modules/apigee_edge_teams/src/Entity/Form/TeamForm.php +++ b/modules/apigee_edge_teams/src/Entity/Form/TeamForm.php @@ -150,8 +150,11 @@ public function exists(string $name, array $element, FormStateInterface $form_st if ($name === '') { return FALSE; } - - $query = $this->entityTypeManager->getStorage('team')->getQuery()->condition('name', $name); + // Only member with access can check if team exists. + $query = $this->entityTypeManager->getStorage('team') + ->getQuery() + ->accessCheck(TRUE) + ->condition('name', $name); return (bool) $query->count()->execute(); } From e03b344dc89ab97dbb4dc4c906696a9d770de910 Mon Sep 17 00:00:00 2001 From: Divyajose <75604843+divya-intelli@users.noreply.github.com> Date: Fri, 9 Jun 2023 11:54:02 +0530 Subject: [PATCH 17/27] Fix for jQuery.once() is deprecated in Drupal 9.3 (#851) Co-authored-by: Vladimir Roudakov --- apigee_edge.libraries.yml | 2 +- js/apigee_edge.app_listing.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apigee_edge.libraries.yml b/apigee_edge.libraries.yml index 8e0317f1..53b52746 100644 --- a/apigee_edge.libraries.yml +++ b/apigee_edge.libraries.yml @@ -37,7 +37,7 @@ apigee_edge.components: css/apigee_edge.components.css: {} apigee_edge.app_listing: - version: 1.0 + version: 1.1 css: theme: css/apigee_edge.app_listing.css: {} diff --git a/js/apigee_edge.app_listing.js b/js/apigee_edge.app_listing.js index 448a8c16..e13101d2 100644 --- a/js/apigee_edge.app_listing.js +++ b/js/apigee_edge.app_listing.js @@ -19,7 +19,7 @@ * @file * Javascript functions related to the app listing. */ -(function ($, Drupal) { +(function ($, Drupal, once) { 'use strict'; @@ -31,7 +31,7 @@ Drupal.apigeeEdgeAppListing = { tableToggle: function (context, settings) { - $('.toggle--warning').once('tableToggle').on('click', function (event) { + $(once('tableToggle', '.toggle--warning')).on('click', function (event) { event.preventDefault(); var targetURL = $(this).attr('href'); var targetID = '#' + targetURL.substr(targetURL.indexOf('#') + 1); @@ -50,4 +50,4 @@ } }; -})(jQuery, Drupal); +})(jQuery, Drupal, once); From c6a834172ab0f8fb82dcc81762e0206a55df95fa Mon Sep 17 00:00:00 2001 From: Divyajose <75604843+divya-intelli@users.noreply.github.com> Date: Tue, 13 Jun 2023 18:40:44 +0530 Subject: [PATCH 18/27] fix for phpcs failing in github action (#858) --- .../EventSubscriber/AppCredentialEventSubscriber.php | 4 ++-- .../Plugin/RulesEvent/EdgeEntityEventDeriverBase.php | 2 +- .../src/TeamMembershipManager.php | 2 +- .../DevelKintApiClientProfiler.php | 2 +- modules/apigee_edge_teams/src/CliService.php | 2 +- .../src/Controller/TeamAppKeysController.php | 2 +- .../src/Controller/TeamMemberSyncController.php | 2 +- .../src/Controller/TeamMembersList.php | 2 +- .../Entity/Controller/TeamAppControllerFactory.php | 2 +- .../src/Entity/Storage/TeamMemberRoleStorage.php | 2 +- .../Storage/TeamMemberRoleStorageInterface.php | 2 +- .../src/Entity/TeamAppRouteProvider.php | 4 ++-- .../apigee_edge_teams/src/Entity/TeamInvitation.php | 2 +- .../TeamMemberApiProductAccessHandlerCacheReset.php | 2 +- .../EventSubscriber/TeamStatusWarningSubscriber.php | 2 +- src/CliService.php | 2 +- src/Command/CommandBase.php | 2 +- src/Command/Util/ApigeeEdgeManagementCliService.php | 2 +- src/Entity/Controller/AppByOwnerController.php | 2 +- src/Entity/Controller/AppController.php | 2 +- .../Controller/AppCredentialControllerBase.php | 2 +- src/Entity/DeveloperAppRouteProvider.php | 4 ++-- src/Entity/Form/AppCreateForm.php | 12 ++++++------ .../ApiProductEntityAccessCacheReset.php | 2 +- src/Form/AppApiKeyAddFormBase.php | 4 ++-- src/KeyEntityFormEnhancer.php | 2 +- .../src/ApigeeMockApiClientServiceProvider.php | 2 +- .../apigee_mock_api_client/src/MockHandlerStack.php | 2 +- .../src/MockHttpClientFactory.php | 2 +- .../src/Traits/ApigeeMockApiClientHelperTrait.php | 2 +- tests/src/Kernel/OauthTokenFileStorageTest.php | 2 +- tests/src/Kernel/UserAgentTest.php | 2 +- .../EventSubscriber/EdgeExceptionSubscriberTest.php | 2 +- 33 files changed, 42 insertions(+), 42 deletions(-) diff --git a/modules/apigee_edge_actions/src/EventSubscriber/AppCredentialEventSubscriber.php b/modules/apigee_edge_actions/src/EventSubscriber/AppCredentialEventSubscriber.php index 1a681ae5..14340e2b 100644 --- a/modules/apigee_edge_actions/src/EventSubscriber/AppCredentialEventSubscriber.php +++ b/modules/apigee_edge_actions/src/EventSubscriber/AppCredentialEventSubscriber.php @@ -20,17 +20,17 @@ namespace Drupal\apigee_edge_actions\EventSubscriber; -use Drupal\apigee_edge_actions\Event\EdgeEntityEventEdge; use Drupal\apigee_edge\Entity\AppInterface; use Drupal\apigee_edge\Event\AppCredentialAddApiProductEvent; use Drupal\apigee_edge\Event\AppCredentialDeleteApiProductEvent; +use Drupal\apigee_edge_actions\Event\EdgeEntityEventEdge; use Drupal\Component\Plugin\Exception\PluginException; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Logger\LoggerChannelInterface; use Drupal\Core\Session\AccountInterface; -use Symfony\Contracts\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Contracts\EventDispatcher\Event; /** * Events for an API Product being added to an app already exist. diff --git a/modules/apigee_edge_actions/src/Plugin/RulesEvent/EdgeEntityEventDeriverBase.php b/modules/apigee_edge_actions/src/Plugin/RulesEvent/EdgeEntityEventDeriverBase.php index b7bc19f5..6451b1f5 100644 --- a/modules/apigee_edge_actions/src/Plugin/RulesEvent/EdgeEntityEventDeriverBase.php +++ b/modules/apigee_edge_actions/src/Plugin/RulesEvent/EdgeEntityEventDeriverBase.php @@ -20,9 +20,9 @@ namespace Drupal\apigee_edge_actions\Plugin\RulesEvent; -use Drupal\apigee_edge_actions\ApigeeActionsEntityTypeHelperInterface; use Drupal\apigee_edge\Entity\AppInterface; use Drupal\apigee_edge\Entity\EdgeEntityTypeInterface; +use Drupal\apigee_edge_actions\ApigeeActionsEntityTypeHelperInterface; use Drupal\apigee_edge_teams\Entity\TeamAppInterface; use Drupal\Component\Plugin\Derivative\DeriverBase; use Drupal\Core\StringTranslation\StringTranslationTrait; diff --git a/modules/apigee_edge_actions/src/TeamMembershipManager.php b/modules/apigee_edge_actions/src/TeamMembershipManager.php index e5d2e78d..7ab5197f 100644 --- a/modules/apigee_edge_actions/src/TeamMembershipManager.php +++ b/modules/apigee_edge_actions/src/TeamMembershipManager.php @@ -20,9 +20,9 @@ namespace Drupal\apigee_edge_actions; -use Drupal\apigee_edge_actions\Event\EdgeEntityEventEdge; use Drupal\apigee_edge\Entity\Controller\DeveloperControllerInterface; use Drupal\apigee_edge\Entity\DeveloperCompaniesCacheInterface; +use Drupal\apigee_edge_actions\Event\EdgeEntityEventEdge; use Drupal\apigee_edge_teams\CompanyMembersControllerFactoryInterface; use Drupal\apigee_edge_teams\TeamMembershipManagerInterface; use Drupal\Core\Cache\CacheTagsInvalidatorInterface; diff --git a/modules/apigee_edge_debug/src/HttpClientMiddleware/DevelKintApiClientProfiler.php b/modules/apigee_edge_debug/src/HttpClientMiddleware/DevelKintApiClientProfiler.php index 4e6f4477..bba36278 100644 --- a/modules/apigee_edge_debug/src/HttpClientMiddleware/DevelKintApiClientProfiler.php +++ b/modules/apigee_edge_debug/src/HttpClientMiddleware/DevelKintApiClientProfiler.php @@ -23,9 +23,9 @@ use Drupal\apigee_edge_debug\DebugMessageFormatterPluginManager; use Drupal\apigee_edge_debug\SDKConnector; use Drupal\Core\Config\ConfigFactoryInterface; -use Drupal\Core\Session\AccountInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Messenger\MessengerInterface; +use Drupal\Core\Session\AccountInterface; use GuzzleHttp\RequestOptions; use GuzzleHttp\TransferStats; use Psr\Http\Message\RequestInterface; diff --git a/modules/apigee_edge_teams/src/CliService.php b/modules/apigee_edge_teams/src/CliService.php index 3f5a8d5c..cdbdeeaa 100644 --- a/modules/apigee_edge_teams/src/CliService.php +++ b/modules/apigee_edge_teams/src/CliService.php @@ -19,8 +19,8 @@ namespace Drupal\apigee_edge_teams; -use Drupal\apigee_edge_teams\Controller\TeamMemberSyncController; use Drupal\apigee_edge\Command\Util\ApigeeEdgeManagementCliServiceInterface; +use Drupal\apigee_edge_teams\Controller\TeamMemberSyncController; use Symfony\Component\Console\Style\StyleInterface; /** diff --git a/modules/apigee_edge_teams/src/Controller/TeamAppKeysController.php b/modules/apigee_edge_teams/src/Controller/TeamAppKeysController.php index b3545b09..ddba7c4f 100644 --- a/modules/apigee_edge_teams/src/Controller/TeamAppKeysController.php +++ b/modules/apigee_edge_teams/src/Controller/TeamAppKeysController.php @@ -19,8 +19,8 @@ namespace Drupal\apigee_edge_teams\Controller; -use Symfony\Component\HttpFoundation\JsonResponse; use Drupal\apigee_edge\Controller\DeveloperAppKeysController; +use Symfony\Component\HttpFoundation\JsonResponse; /** * Controller for the team app credentials. diff --git a/modules/apigee_edge_teams/src/Controller/TeamMemberSyncController.php b/modules/apigee_edge_teams/src/Controller/TeamMemberSyncController.php index 948d8222..d823d778 100644 --- a/modules/apigee_edge_teams/src/Controller/TeamMemberSyncController.php +++ b/modules/apigee_edge_teams/src/Controller/TeamMemberSyncController.php @@ -19,9 +19,9 @@ namespace Drupal\apigee_edge_teams\Controller; -use Drupal\apigee_edge_teams\Job\TeamMemberSync; use Drupal\apigee_edge\Job\Job; use Drupal\apigee_edge\JobExecutorInterface; +use Drupal\apigee_edge_teams\Job\TeamMemberSync; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Messenger\MessengerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; diff --git a/modules/apigee_edge_teams/src/Controller/TeamMembersList.php b/modules/apigee_edge_teams/src/Controller/TeamMembersList.php index d0499596..fe702e85 100644 --- a/modules/apigee_edge_teams/src/Controller/TeamMembersList.php +++ b/modules/apigee_edge_teams/src/Controller/TeamMembersList.php @@ -20,8 +20,8 @@ namespace Drupal\apigee_edge_teams\Controller; -use Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface; use Drupal\apigee_edge_teams\Entity\TeamInterface; +use Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface; use Drupal\apigee_edge_teams\Entity\TeamRoleInterface; use Drupal\apigee_edge_teams\TeamMembershipManagerInterface; use Drupal\Component\Utility\Html; diff --git a/modules/apigee_edge_teams/src/Entity/Controller/TeamAppControllerFactory.php b/modules/apigee_edge_teams/src/Entity/Controller/TeamAppControllerFactory.php index dae4a809..57818153 100644 --- a/modules/apigee_edge_teams/src/Entity/Controller/TeamAppControllerFactory.php +++ b/modules/apigee_edge_teams/src/Entity/Controller/TeamAppControllerFactory.php @@ -20,9 +20,9 @@ namespace Drupal\apigee_edge_teams\Entity\Controller; +use Drupal\apigee_edge\Entity\Controller\Cache\AppCacheByOwnerFactoryInterface; use Drupal\apigee_edge\Entity\Controller\Cache\AppCacheInterface; use Drupal\apigee_edge\Entity\Controller\Cache\AppNameCacheByOwnerFactoryInterface; -use Drupal\apigee_edge\Entity\Controller\Cache\AppCacheByOwnerFactoryInterface; use Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface; use Drupal\apigee_edge\SDKConnectorInterface; diff --git a/modules/apigee_edge_teams/src/Entity/Storage/TeamMemberRoleStorage.php b/modules/apigee_edge_teams/src/Entity/Storage/TeamMemberRoleStorage.php index 4d9a71e3..af3e6040 100644 --- a/modules/apigee_edge_teams/src/Entity/Storage/TeamMemberRoleStorage.php +++ b/modules/apigee_edge_teams/src/Entity/Storage/TeamMemberRoleStorage.php @@ -20,8 +20,8 @@ namespace Drupal\apigee_edge_teams\Entity\Storage; -use Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface; use Drupal\apigee_edge_teams\Entity\TeamInterface; +use Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface; use Drupal\apigee_edge_teams\Exception\InvalidArgumentException; use Drupal\apigee_edge_teams\TeamMembershipManagerInterface; use Drupal\Core\Cache\Cache; diff --git a/modules/apigee_edge_teams/src/Entity/Storage/TeamMemberRoleStorageInterface.php b/modules/apigee_edge_teams/src/Entity/Storage/TeamMemberRoleStorageInterface.php index 32aca99f..1aaa815b 100644 --- a/modules/apigee_edge_teams/src/Entity/Storage/TeamMemberRoleStorageInterface.php +++ b/modules/apigee_edge_teams/src/Entity/Storage/TeamMemberRoleStorageInterface.php @@ -20,8 +20,8 @@ namespace Drupal\apigee_edge_teams\Entity\Storage; -use Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface; use Drupal\apigee_edge_teams\Entity\TeamInterface; +use Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface; use Drupal\Core\Entity\ContentEntityStorageInterface; use Drupal\Core\Session\AccountInterface; diff --git a/modules/apigee_edge_teams/src/Entity/TeamAppRouteProvider.php b/modules/apigee_edge_teams/src/Entity/TeamAppRouteProvider.php index 1afef6a2..ddcb0504 100644 --- a/modules/apigee_edge_teams/src/Entity/TeamAppRouteProvider.php +++ b/modules/apigee_edge_teams/src/Entity/TeamAppRouteProvider.php @@ -22,10 +22,10 @@ use Drupal\apigee_edge\Entity\AppRouteProvider; use Drupal\apigee_edge\Entity\AppTitleProvider; -use Drupal\apigee_edge_teams\Entity\ListBuilder\TeamAppListByTeam; use Drupal\apigee_edge_teams\Controller\TeamAppKeysController; -use Drupal\apigee_edge_teams\Form\TeamAppApiKeyDeleteForm; +use Drupal\apigee_edge_teams\Entity\ListBuilder\TeamAppListByTeam; use Drupal\apigee_edge_teams\Form\TeamAppApiKeyAddForm; +use Drupal\apigee_edge_teams\Form\TeamAppApiKeyDeleteForm; use Drupal\apigee_edge_teams\Form\TeamAppApiKeyRevokeForm; use Drupal\Core\Entity\EntityTypeInterface; use Symfony\Component\Routing\Route; diff --git a/modules/apigee_edge_teams/src/Entity/TeamInvitation.php b/modules/apigee_edge_teams/src/Entity/TeamInvitation.php index e924b7ea..ab4dd484 100644 --- a/modules/apigee_edge_teams/src/Entity/TeamInvitation.php +++ b/modules/apigee_edge_teams/src/Entity/TeamInvitation.php @@ -22,8 +22,8 @@ use Drupal\Core\Entity\ContentEntityBase; use Drupal\Core\Entity\EntityStorageInterface; -use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\user\EntityOwnerTrait; use Drupal\user\UserInterface; diff --git a/modules/apigee_edge_teams/src/EventSubscriber/TeamMemberApiProductAccessHandlerCacheReset.php b/modules/apigee_edge_teams/src/EventSubscriber/TeamMemberApiProductAccessHandlerCacheReset.php index 2226d4e7..71a23a23 100644 --- a/modules/apigee_edge_teams/src/EventSubscriber/TeamMemberApiProductAccessHandlerCacheReset.php +++ b/modules/apigee_edge_teams/src/EventSubscriber/TeamMemberApiProductAccessHandlerCacheReset.php @@ -26,8 +26,8 @@ use Drupal\apigee_edge\Event\AppCredentialDeleteEvent; use Drupal\apigee_edge\Event\AppCredentialGenerateEvent; use Drupal\apigee_edge_teams\TeamMemberApiProductAccessHandlerInterface; -use Symfony\Contracts\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Contracts\EventDispatcher\Event; /** * Ensures team member API product access handler's cache gets cleared. diff --git a/modules/apigee_edge_teams/src/EventSubscriber/TeamStatusWarningSubscriber.php b/modules/apigee_edge_teams/src/EventSubscriber/TeamStatusWarningSubscriber.php index 48936c38..8ebf33ad 100644 --- a/modules/apigee_edge_teams/src/EventSubscriber/TeamStatusWarningSubscriber.php +++ b/modules/apigee_edge_teams/src/EventSubscriber/TeamStatusWarningSubscriber.php @@ -22,13 +22,13 @@ use Drupal\apigee_edge_teams\Entity\TeamInterface; use Drupal\apigee_edge_teams\TeamMembershipManagerInterface; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Session\AccountInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\StringTranslation\TranslationInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; diff --git a/src/CliService.php b/src/CliService.php index 8f5f2ada..895a37f6 100644 --- a/src/CliService.php +++ b/src/CliService.php @@ -19,8 +19,8 @@ namespace Drupal\apigee_edge; -use Drupal\apigee_edge\Controller\DeveloperSyncController; use Drupal\apigee_edge\Command\Util\ApigeeEdgeManagementCliServiceInterface; +use Drupal\apigee_edge\Controller\DeveloperSyncController; use Symfony\Component\Console\Style\StyleInterface; /** diff --git a/src/Command/CommandBase.php b/src/Command/CommandBase.php index 061df9d6..a7519c9e 100644 --- a/src/Command/CommandBase.php +++ b/src/Command/CommandBase.php @@ -20,11 +20,11 @@ namespace Drupal\apigee_edge\Command; use Drupal\apigee_edge\CliServiceInterface; +use Drupal\Console\Core\Command\Command; use Drupal\Console\Core\Command\Shared\CommandTrait; use Drupal\Console\Core\Style\DrupalStyle; use Drupal\Core\Logger\LoggerChannelFactoryInterface; use Drupal\Core\Logger\LogMessageParserInterface; -use Drupal\Console\Core\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Logger\ConsoleLogger; use Symfony\Component\Console\Output\OutputInterface; diff --git a/src/Command/Util/ApigeeEdgeManagementCliService.php b/src/Command/Util/ApigeeEdgeManagementCliService.php index 8a1c5f60..551c640f 100644 --- a/src/Command/Util/ApigeeEdgeManagementCliService.php +++ b/src/Command/Util/ApigeeEdgeManagementCliService.php @@ -19,9 +19,9 @@ namespace Drupal\apigee_edge\Command\Util; +use Apigee\Edge\ClientInterface as ApigeeClientInterface; use Drupal\Component\Utility\UrlHelper; use GuzzleHttp\ClientInterface; -use Apigee\Edge\ClientInterface as ApigeeClientInterface; use GuzzleHttp\Exception\ClientException; use GuzzleHttp\Exception\TransferException; use Symfony\Component\Console\Style\StyleInterface; diff --git a/src/Entity/Controller/AppByOwnerController.php b/src/Entity/Controller/AppByOwnerController.php index 2b8993fa..d45d3ecb 100644 --- a/src/Entity/Controller/AppByOwnerController.php +++ b/src/Entity/Controller/AppByOwnerController.php @@ -24,8 +24,8 @@ use Apigee\Edge\Api\Management\Controller\AppByOwnerControllerInterface as EdgeAppByOwnerControllerInterface; use Apigee\Edge\Entity\EntityInterface; use Drupal\apigee_edge\Entity\Controller\Cache\AppCacheByOwnerFactoryInterface; -use Drupal\apigee_edge\Entity\Controller\Cache\AppNameCacheByOwnerFactoryInterface; use Drupal\apigee_edge\Entity\Controller\Cache\AppCacheInterface; +use Drupal\apigee_edge\Entity\Controller\Cache\AppNameCacheByOwnerFactoryInterface; use Drupal\apigee_edge\Entity\Controller\Cache\EntityCacheInterface; use Drupal\apigee_edge\Entity\Controller\Cache\EntityIdCacheInterface; use Drupal\apigee_edge\SDKConnectorInterface; diff --git a/src/Entity/Controller/AppController.php b/src/Entity/Controller/AppController.php index 3a1ad769..608722a7 100644 --- a/src/Entity/Controller/AppController.php +++ b/src/Entity/Controller/AppController.php @@ -24,9 +24,9 @@ use Apigee\Edge\Api\Management\Controller\AppControllerInterface as EdgeAppControllerInterface; use Apigee\Edge\Api\Management\Entity\AppInterface; use Apigee\Edge\Structure\PagerInterface; +use Drupal\apigee_edge\Entity\Controller\Cache\AppCacheByOwnerFactoryInterface; use Drupal\apigee_edge\Entity\Controller\Cache\AppCacheInterface; use Drupal\apigee_edge\Entity\Controller\Cache\AppIdCache; -use Drupal\apigee_edge\Entity\Controller\Cache\AppCacheByOwnerFactoryInterface; use Drupal\apigee_edge\SDKConnectorInterface; /** diff --git a/src/Entity/Controller/AppCredentialControllerBase.php b/src/Entity/Controller/AppCredentialControllerBase.php index b193e334..aa9817dc 100644 --- a/src/Entity/Controller/AppCredentialControllerBase.php +++ b/src/Entity/Controller/AppCredentialControllerBase.php @@ -26,9 +26,9 @@ use Drupal\apigee_edge\Entity\Controller\Cache\AppCacheByOwnerFactoryInterface; use Drupal\apigee_edge\Event\AppCredentialAddApiProductEvent; use Drupal\apigee_edge\Event\AppCredentialCreateEvent; +use Drupal\apigee_edge\Event\AppCredentialDeleteApiProductEvent; use Drupal\apigee_edge\Event\AppCredentialDeleteEvent; use Drupal\apigee_edge\Event\AppCredentialGenerateEvent; -use Drupal\apigee_edge\Event\AppCredentialDeleteApiProductEvent; use Drupal\apigee_edge\SDKConnectorInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; diff --git a/src/Entity/DeveloperAppRouteProvider.php b/src/Entity/DeveloperAppRouteProvider.php index 8df0bf5e..c815ee5a 100644 --- a/src/Entity/DeveloperAppRouteProvider.php +++ b/src/Entity/DeveloperAppRouteProvider.php @@ -21,12 +21,12 @@ namespace Drupal\apigee_edge\Entity; use Drupal\apigee_edge\Access\AppsPageAccessCheck; -use Drupal\apigee_edge\Controller\DeveloperAppViewControllerForDeveloper; use Drupal\apigee_edge\Controller\DeveloperAppKeysController; +use Drupal\apigee_edge\Controller\DeveloperAppViewControllerForDeveloper; use Drupal\apigee_edge\Entity\ListBuilder\DeveloperAppListBuilderForDeveloper; use Drupal\apigee_edge\Form\DeveloperAppAnalyticsFormForDeveloper; -use Drupal\apigee_edge\Form\DeveloperAppApiKeyDeleteForm; use Drupal\apigee_edge\Form\DeveloperAppApiKeyAddForm; +use Drupal\apigee_edge\Form\DeveloperAppApiKeyDeleteForm; use Drupal\apigee_edge\Form\DeveloperAppApiKeyRevokeForm; use Drupal\Core\Entity\EntityTypeInterface; use Symfony\Component\Routing\Route; diff --git a/src/Entity/Form/AppCreateForm.php b/src/Entity/Form/AppCreateForm.php index e6ac4a0a..1fe8a8f2 100644 --- a/src/Entity/Form/AppCreateForm.php +++ b/src/Entity/Form/AppCreateForm.php @@ -20,18 +20,18 @@ namespace Drupal\apigee_edge\Entity\Form; -use Drupal\Core\Entity\EntityTypeManagerInterface; -use Drupal\apigee_edge\Entity\ApiProductInterface; -use Drupal\apigee_edge\Entity\Controller\ApiProductControllerInterface; -use Drupal\Core\Form\FormStateInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\Core\Url; use Apigee\Edge\Exception\ApiException; +use Drupal\apigee_edge\Entity\ApiProductInterface; use Drupal\apigee_edge\Entity\AppInterface; +use Drupal\apigee_edge\Entity\Controller\ApiProductControllerInterface; use Drupal\Core\Entity\EntityStorageException; +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Link; use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\Core\Url; use Drupal\Core\Utility\Error; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Base entity form for developer- and team (company) app create forms. diff --git a/src/EventSubscriber/ApiProductEntityAccessCacheReset.php b/src/EventSubscriber/ApiProductEntityAccessCacheReset.php index f5216ace..99698c7e 100644 --- a/src/EventSubscriber/ApiProductEntityAccessCacheReset.php +++ b/src/EventSubscriber/ApiProductEntityAccessCacheReset.php @@ -26,8 +26,8 @@ use Drupal\apigee_edge\Event\AppCredentialDeleteEvent; use Drupal\apigee_edge\Event\AppCredentialGenerateEvent; use Drupal\Core\Entity\EntityTypeManagerInterface; -use Symfony\Contracts\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Contracts\EventDispatcher\Event; /** * Ensures that entity access cache gets cleared on API product entities. diff --git a/src/Form/AppApiKeyAddFormBase.php b/src/Form/AppApiKeyAddFormBase.php index 3d31b2a3..80741c0b 100644 --- a/src/Form/AppApiKeyAddFormBase.php +++ b/src/Form/AppApiKeyAddFormBase.php @@ -21,12 +21,12 @@ use Apigee\Edge\Api\Management\Entity\AppCredentialInterface; use Apigee\Edge\Structure\CredentialProductInterface; +use Drupal\apigee_edge\Entity\AppInterface; +use Drupal\apigee_edge\Entity\Controller\AppCredentialControllerInterface; use Drupal\Core\Cache\Cache; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Url; -use Drupal\apigee_edge\Entity\AppInterface; -use Drupal\apigee_edge\Entity\Controller\AppCredentialControllerInterface; /** * Provides app API key add base form. diff --git a/src/KeyEntityFormEnhancer.php b/src/KeyEntityFormEnhancer.php index 6928a3ee..b3e44480 100644 --- a/src/KeyEntityFormEnhancer.php +++ b/src/KeyEntityFormEnhancer.php @@ -20,8 +20,8 @@ namespace Drupal\apigee_edge; -use Apigee\Edge\Exception\ApiRequestException; use Apigee\Edge\Exception\ApigeeOnGcpOauth2AuthenticationException; +use Apigee\Edge\Exception\ApiRequestException; use Apigee\Edge\Exception\OauthAuthenticationException; use Apigee\Edge\HttpClient\Plugin\Authentication\Oauth; use Drupal\apigee_edge\Exception\AuthenticationKeyException; diff --git a/tests/modules/apigee_mock_api_client/src/ApigeeMockApiClientServiceProvider.php b/tests/modules/apigee_mock_api_client/src/ApigeeMockApiClientServiceProvider.php index e1416fdc..abdbc42b 100644 --- a/tests/modules/apigee_mock_api_client/src/ApigeeMockApiClientServiceProvider.php +++ b/tests/modules/apigee_mock_api_client/src/ApigeeMockApiClientServiceProvider.php @@ -20,8 +20,8 @@ namespace Drupal\apigee_mock_api_client; -use Drupal\Core\DependencyInjection\ServiceProviderBase; use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\DependencyInjection\ServiceProviderBase; use Symfony\Component\DependencyInjection\Reference; /** diff --git a/tests/modules/apigee_mock_api_client/src/MockHandlerStack.php b/tests/modules/apigee_mock_api_client/src/MockHandlerStack.php index f755e976..a4bc3353 100644 --- a/tests/modules/apigee_mock_api_client/src/MockHandlerStack.php +++ b/tests/modules/apigee_mock_api_client/src/MockHandlerStack.php @@ -25,8 +25,8 @@ use Apigee\MockClient\MockStorageInterface; use Apigee\MockClient\ResponseFactoryInterface; use GuzzleHttp\Psr7\Response; -use Twig\Environment; use Symfony\Component\Yaml\Yaml; +use Twig\Environment; /** * The mock handler stack. diff --git a/tests/modules/apigee_mock_api_client/src/MockHttpClientFactory.php b/tests/modules/apigee_mock_api_client/src/MockHttpClientFactory.php index 6d04f314..a38a02f1 100644 --- a/tests/modules/apigee_mock_api_client/src/MockHttpClientFactory.php +++ b/tests/modules/apigee_mock_api_client/src/MockHttpClientFactory.php @@ -20,9 +20,9 @@ namespace Drupal\apigee_mock_api_client; +use Apigee\MockClient\GuzzleHttp\MockHandler; use Drupal\Core\Http\ClientFactory; use Drupal\Core\State\StateInterface; -use Apigee\MockClient\GuzzleHttp\MockHandler; use GuzzleHttp\HandlerStack; /** diff --git a/tests/modules/apigee_mock_api_client/tests/src/Traits/ApigeeMockApiClientHelperTrait.php b/tests/modules/apigee_mock_api_client/tests/src/Traits/ApigeeMockApiClientHelperTrait.php index ff879614..4f480abd 100644 --- a/tests/modules/apigee_mock_api_client/tests/src/Traits/ApigeeMockApiClientHelperTrait.php +++ b/tests/modules/apigee_mock_api_client/tests/src/Traits/ApigeeMockApiClientHelperTrait.php @@ -22,9 +22,9 @@ use Apigee\Edge\Api\Management\Entity\App; use Apigee\Edge\Api\Management\Entity\Company; use Apigee\Edge\Api\Management\Entity\Organization; -use Apigee\MockClient\Generator\ApigeeSdkEntitySource; use Apigee\Edge\Structure\AddonsConfig; use Apigee\Edge\Structure\MonetizationConfig; +use Apigee\MockClient\Generator\ApigeeSdkEntitySource; use Drupal\apigee_edge\Entity\Developer; use Drupal\apigee_edge\Entity\DeveloperApp; use Drupal\apigee_edge\Entity\DeveloperAppInterface; diff --git a/tests/src/Kernel/OauthTokenFileStorageTest.php b/tests/src/Kernel/OauthTokenFileStorageTest.php index fe010d57..5fd988ab 100644 --- a/tests/src/Kernel/OauthTokenFileStorageTest.php +++ b/tests/src/Kernel/OauthTokenFileStorageTest.php @@ -20,8 +20,8 @@ namespace Drupal\Tests\apigee_edge\Kernel; use Drupal\apigee_edge\Exception\OauthTokenStorageException; -use Drupal\Component\Serialization\Json; use Drupal\apigee_edge\OauthTokenFileStorage; +use Drupal\Component\Serialization\Json; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\File\FileSystemInterface; use Drupal\KernelTests\KernelTestBase; diff --git a/tests/src/Kernel/UserAgentTest.php b/tests/src/Kernel/UserAgentTest.php index e83f4698..289c051b 100644 --- a/tests/src/Kernel/UserAgentTest.php +++ b/tests/src/Kernel/UserAgentTest.php @@ -19,9 +19,9 @@ namespace Drupal\Tests\apigee_edge\Kernel; -use Drupal\KernelTests\KernelTestBase; use Drupal\Core\Extension\InfoParser; use Drupal\Core\Extension\InfoParserInterface; +use Drupal\KernelTests\KernelTestBase; /** * Apigee Useragent tests. diff --git a/tests/src/Unit/EventSubscriber/EdgeExceptionSubscriberTest.php b/tests/src/Unit/EventSubscriber/EdgeExceptionSubscriberTest.php index 8773ab7f..d16a433c 100644 --- a/tests/src/Unit/EventSubscriber/EdgeExceptionSubscriberTest.php +++ b/tests/src/Unit/EventSubscriber/EdgeExceptionSubscriberTest.php @@ -22,13 +22,13 @@ use Apigee\Edge\Exception\ApiException; use Drupal\apigee_edge\Controller\ErrorPageController; use Drupal\apigee_edge\EventSubscriber\EdgeExceptionSubscriber; +use Drupal\Core\Config\Config; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\DependencyInjection\ClassResolverInterface; use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Render\MainContent\HtmlRenderer; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Tests\UnitTestCase; -use Drupal\Core\Config\Config; use Prophecy\Argument; use Prophecy\Prophet; use Psr\Log\LoggerInterface; From 760e99e346e9cdc30e0a5e119adc8951ae08c606 Mon Sep 17 00:00:00 2001 From: Divyajose <75604843+divya-intelli@users.noreply.github.com> Date: Wed, 14 Jun 2023 13:50:21 +0530 Subject: [PATCH 19/27] Fix for keys without a placeholder prefix deprecation (#852) * Fix for keys without a placeholder prefix deprecation --- src/Job/DeveloperCreateUpdate.php | 4 ++-- src/Job/UserCreate.php | 2 +- src/Job/UserCreateUpdate.php | 4 ++++ src/Job/UserUpdate.php | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Job/DeveloperCreateUpdate.php b/src/Job/DeveloperCreateUpdate.php index b366032e..56a62b51 100644 --- a/src/Job/DeveloperCreateUpdate.php +++ b/src/Job/DeveloperCreateUpdate.php @@ -75,7 +75,7 @@ protected function executeRequest() { $message = '@operation: Skipping %mail developer. @message %function (line %line of %file).
@backtrace_string
'; $context = [ '%mail' => $this->email, - 'link' => $account->toLink(t('View user'))->toString(), + '@link' => $account->toLink(t('View user'))->toString(), '@operation' => get_class($this), ]; $context += Error::decodeException($exception); @@ -102,7 +102,7 @@ protected function executeRequest() { */ protected function beforeDeveloperSave(UserToDeveloperConversionResult $result, UserInterface $user) : void { $context = [ - 'link' => $user->toLink(t('View user'))->toString(), + '@link' => $user->toLink(t('View user'))->toString(), ]; $this->logConversionProblems($result->getProblems(), $context); } diff --git a/src/Job/UserCreate.php b/src/Job/UserCreate.php index 175b36bf..c342d48a 100644 --- a/src/Job/UserCreate.php +++ b/src/Job/UserCreate.php @@ -33,7 +33,7 @@ protected function afterUserSave(DeveloperToUserConversionResult $result): void $context = []; // If user could be saved. if ($result->getUser()->id()) { - $context['link'] = $result->getUser()->toLink(t('View user'))->toString(); + $context['@link'] = $result->getUser()->toLink(t('View user'))->toString(); } // Only log problems after a user has been saved because this way we can // provide an link to its profile page in log entries. diff --git a/src/Job/UserCreateUpdate.php b/src/Job/UserCreateUpdate.php index 2e33a987..d570bc4b 100644 --- a/src/Job/UserCreateUpdate.php +++ b/src/Job/UserCreateUpdate.php @@ -85,6 +85,10 @@ protected function executeRequest() { '@operation' => get_class($this), ]; $context += Error::decodeException($exception); + // Unset backtrace, exception, severity_level as they are not shown in the log message + // and throws php warning in logs. + unset($context['backtrace'], $context['exception'], $context['severity_level']); + $this->logger()->error($message, $context); $this->recordMessage(t('Skipping %mail user: @message', $context)->render()); } diff --git a/src/Job/UserUpdate.php b/src/Job/UserUpdate.php index 7f6008c4..9dc1339f 100644 --- a/src/Job/UserUpdate.php +++ b/src/Job/UserUpdate.php @@ -42,7 +42,7 @@ protected function beforeUserSave(DeveloperToUserConversionResult $result): void } $context = [ - 'link' => $result->getUser()->toLink(t('View user'))->toString(), + '@link' => $result->getUser()->toLink(t('View user'))->toString(), ]; $this->logConversionProblems($result->getProblems(), $context); From 386c83ff43a0f269488c680bcfd99490c4271b07 Mon Sep 17 00:00:00 2001 From: Divyajose <75604843+divya-intelli@users.noreply.github.com> Date: Thu, 15 Jun 2023 12:10:22 +0530 Subject: [PATCH 20/27] Fix for relying on entity queries to check access (#854) --- .../src/Controller/TeamAppKeysController.php | 3 +++ .../src/Entity/Storage/TeamInvitationStorage.php | 5 +++-- .../src/ParamConverter/TeamAppNameConverter.php | 3 +++ src/Controller/DeveloperAppKeysController.php | 3 +++ src/Entity/Storage/DeveloperAppStorage.php | 4 +++- src/ParamConverter/DeveloperAppNameConverter.php | 3 +++ tests/src/Functional/DeveloperAppUITestTrait.php | 2 ++ tests/src/Functional/QueryTest.php | 10 ++++++++++ 8 files changed, 30 insertions(+), 3 deletions(-) diff --git a/modules/apigee_edge_teams/src/Controller/TeamAppKeysController.php b/modules/apigee_edge_teams/src/Controller/TeamAppKeysController.php index ddba7c4f..48871ca9 100644 --- a/modules/apigee_edge_teams/src/Controller/TeamAppKeysController.php +++ b/modules/apigee_edge_teams/src/Controller/TeamAppKeysController.php @@ -37,7 +37,10 @@ public function teamAppKeys($team, $app): JsonResponse { $payload = []; if ($team) { $app_storage = $this->entityTypeManager->getStorage('team_app'); + // Lists all the team apps ids. + // Team app is accessible to all the team members. $app_ids = $app_storage->getQuery() + ->accessCheck(FALSE) ->condition('companyName', $team->id()) ->condition('name', $app->getName()) ->execute(); diff --git a/modules/apigee_edge_teams/src/Entity/Storage/TeamInvitationStorage.php b/modules/apigee_edge_teams/src/Entity/Storage/TeamInvitationStorage.php index 780b1551..330050f8 100644 --- a/modules/apigee_edge_teams/src/Entity/Storage/TeamInvitationStorage.php +++ b/modules/apigee_edge_teams/src/Entity/Storage/TeamInvitationStorage.php @@ -147,7 +147,7 @@ protected function invokeHook($hook, EntityInterface $entity) { * {@inheritdoc} */ public function loadByRecipient(string $email, ?string $team_id = NULL): array { - $query = $this->getQuery()->condition('recipient', $email); + $query = $this->getQuery()->accessCheck(TRUE)->condition('recipient', $email); if ($team_id) { $query->condition('team', $team_id); @@ -161,7 +161,8 @@ public function loadByRecipient(string $email, ?string $team_id = NULL): array { * {@inheritdoc} */ public function getInvitationsToExpire(): array { - $query = $this->getQuery()->condition('expiry', $this->time->getCurrentTime(), '<') + // Team invitation is accessable as we need to update status in cron run. + $query = $this->getQuery()->accessCheck(FALSE)->condition('expiry', $this->time->getCurrentTime(), '<') ->condition('status', TeamInvitationInterface::STATUS_PENDING); $ids = $query->execute(); diff --git a/modules/apigee_edge_teams/src/ParamConverter/TeamAppNameConverter.php b/modules/apigee_edge_teams/src/ParamConverter/TeamAppNameConverter.php index 73546cbe..2c002e18 100644 --- a/modules/apigee_edge_teams/src/ParamConverter/TeamAppNameConverter.php +++ b/modules/apigee_edge_teams/src/ParamConverter/TeamAppNameConverter.php @@ -76,7 +76,10 @@ public function convert($value, $definition, $name, array $defaults) { $team = is_object($defaults['team']) ? $defaults['team'] : $this->entityTypeManager->getStorage('team')->load($defaults['team']); if ($team) { $app_storage = $this->entityTypeManager->getStorage('team_app'); + // Lists all the team apps ids. + // Team app is accessible to all the team members. $app_ids = $app_storage->getQuery() + ->accessCheck(FALSE) ->condition('companyName', $team->id()) ->condition('name', $value) ->execute(); diff --git a/src/Controller/DeveloperAppKeysController.php b/src/Controller/DeveloperAppKeysController.php index 7c46e1a4..097b4078 100644 --- a/src/Controller/DeveloperAppKeysController.php +++ b/src/Controller/DeveloperAppKeysController.php @@ -66,7 +66,10 @@ public function developerAppKeys($user, $app): JsonResponse { if ($user) { if ($developer_id = $user->get('apigee_edge_developer_id')->value) { $app_storage = $this->entityTypeManager->getStorage('developer_app'); + // Lists all the developer apps ids for a particular + // developer email id and app name. $app_ids = $app_storage->getQuery() + ->accessCheck(FALSE) ->condition('developerId', $developer_id) ->condition('name', $app->getName()) ->execute(); diff --git a/src/Entity/Storage/DeveloperAppStorage.php b/src/Entity/Storage/DeveloperAppStorage.php index f101f2cb..0eb513e4 100644 --- a/src/Entity/Storage/DeveloperAppStorage.php +++ b/src/Entity/Storage/DeveloperAppStorage.php @@ -106,7 +106,9 @@ protected function entityController(): EdgeEntityControllerInterface { * {@inheritdoc} */ public function loadByDeveloper(string $developer_id): array { - $query = $this->getQuery(); + // Lists all the developer apps ids for a particular + // developer email id and app name. + $query = $this->getQuery()->accessCheck(FALSE); // We have to figure out whether this is an email or a UUID to call the // best API endpoint that is possible. if ($this->emailValidator->isValid($developer_id)) { diff --git a/src/ParamConverter/DeveloperAppNameConverter.php b/src/ParamConverter/DeveloperAppNameConverter.php index aad62680..d74d39fa 100644 --- a/src/ParamConverter/DeveloperAppNameConverter.php +++ b/src/ParamConverter/DeveloperAppNameConverter.php @@ -79,7 +79,10 @@ public function convert($value, $definition, $name, array $defaults) { $developer_id = $user->get('apigee_edge_developer_id')->value; if ($developer_id) { $app_storage = $this->entityTypeManager->getStorage('developer_app'); + // Lists all the developer apps ids for a particular + // developer email id and app name. $app_ids = $app_storage->getQuery() + ->accessCheck(FALSE) ->condition('developerId', $developer_id) ->condition('name', $value) ->execute(); diff --git a/tests/src/Functional/DeveloperAppUITestTrait.php b/tests/src/Functional/DeveloperAppUITestTrait.php index 393d563c..14928c95 100644 --- a/tests/src/Functional/DeveloperAppUITestTrait.php +++ b/tests/src/Functional/DeveloperAppUITestTrait.php @@ -233,6 +233,7 @@ protected function assertAppCrud(?callable $beforeCreate = NULL, ?callable $afte $storage = \Drupal::entityTypeManager()->getStorage('developer_app'); /** @var \Drupal\apigee_edge\Entity\DeveloperApp $app */ $app = $storage->load(array_values($storage->getQuery() + ->accessCheck(TRUE) ->condition('developerId', $developer->uuid()) ->condition('name', $name) ->execute())[0]); @@ -348,6 +349,7 @@ protected function loadDeveloperApp(string $name, Developer $developer = NULL): $storage = \Drupal::entityTypeManager()->getStorage('developer_app'); $results_ids = $storage ->getQuery() + ->accessCheck(FALSE) ->condition('developerId', $developer->uuid()) ->condition('name', $name) ->execute(); diff --git a/tests/src/Functional/QueryTest.php b/tests/src/Functional/QueryTest.php index 15a2b7e4..c6f288ee 100644 --- a/tests/src/Functional/QueryTest.php +++ b/tests/src/Functional/QueryTest.php @@ -133,6 +133,7 @@ public function testQueries() { */ protected function developerQueryTest() { $result = $this->developerStorage->getQuery() + ->accessCheck(FALSE) ->condition('email', "{$this->prefix}.test", 'STARTS_WITH') ->condition('email', '@example.com', 'ENDS_WITH') ->sort('lastName') @@ -145,6 +146,7 @@ protected function developerQueryTest() { ]), array_values($result)); $result = $this->developerStorage->getQuery() + ->accessCheck(FALSE) ->condition('email', "{$this->prefix}.test", 'STARTS_WITH') ->condition('email', '@example.com', 'ENDS_WITH') ->sort('email') @@ -153,6 +155,7 @@ protected function developerQueryTest() { $this->assertEquals(array_values(["{$this->prefix}.test01@example.com"]), array_values($result)); $result = $this->developerStorage->getQuery() + ->accessCheck(FALSE) ->condition('email', "{$this->prefix}.test", 'STARTS_WITH') ->condition('email', '@example.com', 'ENDS_WITH') ->count() @@ -177,12 +180,14 @@ protected function smartQueryTest() { // When primary id(s) of entities is set to something empty we should // get back an empty result. $result = $this->developerStorage->getQuery() + ->accessCheck(FALSE) ->condition('email', NULL) ->count() ->execute(); $this->assertEquals(0, $result); $result = $this->developerStorage->getQuery() + ->accessCheck(FALSE) ->condition('developerId', NULL) ->count() ->execute(); @@ -190,6 +195,7 @@ protected function smartQueryTest() { $developer = reset($this->edgeDevelopers); $result = $this->developerAppStorage->getQuery() + ->accessCheck(FALSE) ->condition('developerId', $developer->getDeveloperId()) ->count() ->execute(); @@ -199,12 +205,14 @@ protected function smartQueryTest() { // Edge by calling the proper API endpoint - is set to something empty // we should get back an empty result. $result = $this->developerAppStorage->getQuery() + ->accessCheck(FALSE) ->condition('developerId', NULL) ->count() ->execute(); $this->assertEquals(0, $result); $result = $this->developerAppStorage->getQuery() + ->accessCheck(FALSE) ->condition('email', $developer->getEmail()) ->count() ->execute(); @@ -214,6 +222,7 @@ protected function smartQueryTest() { // Edge by calling the proper API endpoint - is set to something empty // we should get back an empty result. $result = $this->developerAppStorage->getQuery() + ->accessCheck(FALSE) ->condition('email', NULL) ->count() ->execute(); @@ -222,6 +231,7 @@ protected function smartQueryTest() { // If app name is set to something empty then query should not fail and // we should get back an empty list even if the developer has apps. $result = $this->developerAppStorage->getQuery() + ->accessCheck(FALSE) ->condition('email', $developer->getEmail()) ->condition('name', NULL) ->count() From ea6a45f12b1e62253e077082a10fa197d90ab1dd Mon Sep 17 00:00:00 2001 From: Shishir <75600200+shishir-intelli@users.noreply.github.com> Date: Fri, 23 Jun 2023 21:56:30 +0530 Subject: [PATCH 21/27] Merging AppGroup changes into 2.x branch (#869) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Checking if the organisation is ApigeeX for AppGroup (#803) * Fix organisation exception (#806) * Changes for Appgroup listing/view/edit/delete page (#805) * Changes for Appgroup listing/view/edit/delete page * Update composer.json * Update composer.json * AppGroup-App implementation for list, view, edit, delete apps (#813) * Merge 2.x into appgroup (#829) * Warrant that queues executed by cron (#808) * Sort API Product listings on App (#812) * Update endpoints to use constants from ClientInterface (#810) * Sort API products on app forms by API product display name (#815) * Sort API Products (#818) * Sort API Products TypeError: array_map(): Argument #2 ($array) must be of type array * Removed test case * App creation fails without API Products (#809) * App creation fails without API Products caused by features.keymanagement.disable.unbounded.permissions flag * Update minimum version of apigee-client-php * Make sure that cron runner starts executing the job (#814) * Checking if the organisation is ApigeeX for AppGroup (#803) * Fix organisation exception (#806) * Changes for Appgroup listing/view/edit/delete page (#805) * Changes for Appgroup listing/view/edit/delete page * Update composer.json * Update composer.json * AppGroup-App implementation for list, view, edit, delete apps (#813) --------- Co-authored-by: Dezső BICZÓ Co-authored-by: Shishir <75600200+shishir-intelli@users.noreply.github.com> Co-authored-by: phdhiren Co-authored-by: Divyajose <75604843+divya-intelli@users.noreply.github.com> * Support for Add AppGroup/team and update team App credentials with ApiProduct (#824) * Support for AppGroup membership (#825) * The Apigee Edge and X Teams module requirements (#826) * Checking ApigeeX org from OrganizationController and removed from SDKController (#832) * If team not available on Apigee avoid null value exception (#833) * Added admin config setting for Team prefix and channelID (#839) * Implemented AppGroup membership feature for ApigeeX (#843) * Merge 2.x into appgroup branch (#859) * Warrant that queues executed by cron (#808) * Sort API Product listings on App (#812) * Update endpoints to use constants from ClientInterface (#810) * Sort API products on app forms by API product display name (#815) * Sort API Products (#818) * Sort API Products TypeError: array_map(): Argument #2 ($array) must be of type array * Removed test case * App creation fails without API Products (#809) * App creation fails without API Products caused by features.keymanagement.disable.unbounded.permissions flag * Update minimum version of apigee-client-php * Make sure that cron runner starts executing the job (#814) * Update the storage defination of App entity (#831) * Fix issue which removes users from all team (#840) * Drop PHP 7 support again (#816) * Revert "Support for PHP 7.4 (#800)" This reverts commit b71f8a9cebc4fcdf9f0dc447d92f3ed6ea6173a7. * Clearly specify the currently supported PHP versions * Update outdated info.yml * Added accessCheck on entity queries (#842) * added accessCheck on entity queries Co-authored-by: Vladimir Roudakov * added comment --------- Co-authored-by: Vladimir Roudakov * Fix for jQuery.once() is deprecated in Drupal 9.3 (#851) Co-authored-by: Vladimir Roudakov * fix for phpcs failing in github action (#858) * PHPCS FIX --------- Co-authored-by: Shishir <75600200+shishir-intelli@users.noreply.github.com> Co-authored-by: Dezső BICZÓ Co-authored-by: Gitesh Koli Co-authored-by: Divyajose <75604843+divya-intelli@users.noreply.github.com> Co-authored-by: Vladimir Roudakov * Implemented AppGroup Team Membership Sync (#853) * Get AppGroup team members from DB (#864) * Get AppGroup team members from DB and fix recurring teams api call * Declaring abstract method * Fix action module getTeam method argument * Fix for team sync issue when DB is empty * Added team member sync note for ApigeeX (#867) --------- Co-authored-by: Shishir <75600200+shishir-intelli@users.noreply.github.com> Co-authored-by: Divyajose <75604843+divya-intelli@users.noreply.github.com> Co-authored-by: Gitesh Koli Co-authored-by: Dezső BICZÓ Co-authored-by: Vladimir Roudakov --- .../src/TeamMembershipManager.php | 11 +- .../EdgeEntityAddMemberEventTest.php | 2 + .../EdgeEntityRemoveMemberEventTest.php | 2 + .../RulesEvent/EdgeEntityUpdateEventTest.php | 3 + .../apigee_edge_teams.install | 8 +- .../apigee_edge_teams.links.task.yml | 2 +- .../apigee_edge_teams.services.yml | 16 +- .../apigee_edge_teams.team_settings.yml | 2 + .../schema/apigee_edge_teams.schema.yml | 6 + .../src/Access/ManageTeamMembersAccess.php | 3 +- .../src/AppGroupMembersController.php | 209 ++++++++++++++++++ .../src/AppGroupMembersControllerFactory.php | 77 +++++++ ...GroupMembersControllerFactoryInterface.php | 39 ++++ .../AppGroupMembersControllerInterface.php | 30 +++ .../src/AppGroupMembershipObjectCache.php | 154 +++++++++++++ ...AppGroupMembershipObjectCacheInterface.php | 68 ++++++ .../src/CompanyMembersController.php | 2 + .../src/Controller/TeamMembersList.php | 42 +++- .../src/Entity/AppGroupCache.php | 91 ++++++++ .../src/Entity/AppGroupCacheInterface.php | 66 ++++++ .../TeamAppApigeeXEntityControllerProxy.php | 121 ++++++++++ .../Entity/Controller/TeamAppController.php | 9 +- .../TeamAppCredentialController.php | 11 +- .../src/Entity/Controller/TeamController.php | 21 +- .../src/Entity/Form/TeamAppFormTrait.php | 6 +- .../src/Entity/Form/TeamForm.php | 98 +++++++- .../src/Entity/Storage/TeamAppStorage.php | 25 ++- .../Entity/Storage/TeamMemberRoleStorage.php | 68 +++++- modules/apigee_edge_teams/src/Entity/Team.php | 50 ++++- .../src/Entity/TeamAccessHandler.php | 26 ++- .../apigee_edge_teams/src/Entity/TeamApp.php | 40 +++- .../src/Entity/TeamAppAccessHandler.php | 20 +- .../src/Entity/TeamAppInterface.php | 4 +- .../TeamInvitationSubscriber.php | 33 ++- .../src/Form/EditTeamMemberForm.php | 11 +- .../src/Form/TeamAliasForm.php | 82 +++++++ .../src/Form/TeamMemberSyncForm.php | 32 ++- .../src/Job/TeamMemberCreateUpdate.php | 9 +- .../src/TeamMemberApiProductAccessHandler.php | 3 +- .../src/TeamMembershipManager.php | 126 +++++++++-- .../src/TeamMembershipManagerInterface.php | 15 +- .../src/TeamPermissionHandler.php | 3 +- .../Kernel/Event/TeamInvitationEventsTest.php | 2 + src/Entity/App.php | 8 +- src/Entity/Controller/AppController.php | 24 +- src/Entity/Controller/Cache/AppCache.php | 4 + .../DeveloperAppEdgeEntityControllerProxy.php | 17 +- .../Controller/OrganizationController.php | 16 ++ src/Entity/Developer.php | 3 + src/Entity/Storage/DeveloperAppStorage.php | 10 +- src/SDKConnector.php | 1 + src/SDKConnectorInterface.php | 1 + 52 files changed, 1628 insertions(+), 104 deletions(-) create mode 100644 modules/apigee_edge_teams/src/AppGroupMembersController.php create mode 100644 modules/apigee_edge_teams/src/AppGroupMembersControllerFactory.php create mode 100644 modules/apigee_edge_teams/src/AppGroupMembersControllerFactoryInterface.php create mode 100644 modules/apigee_edge_teams/src/AppGroupMembersControllerInterface.php create mode 100644 modules/apigee_edge_teams/src/AppGroupMembershipObjectCache.php create mode 100644 modules/apigee_edge_teams/src/AppGroupMembershipObjectCacheInterface.php create mode 100644 modules/apigee_edge_teams/src/Entity/AppGroupCache.php create mode 100644 modules/apigee_edge_teams/src/Entity/AppGroupCacheInterface.php create mode 100644 modules/apigee_edge_teams/src/Entity/Controller/TeamAppApigeeXEntityControllerProxy.php diff --git a/modules/apigee_edge_actions/src/TeamMembershipManager.php b/modules/apigee_edge_actions/src/TeamMembershipManager.php index 7ab5197f..7d57f779 100644 --- a/modules/apigee_edge_actions/src/TeamMembershipManager.php +++ b/modules/apigee_edge_actions/src/TeamMembershipManager.php @@ -151,8 +151,15 @@ public function removeMembers(string $team, array $developers): void { /** * {@inheritdoc} */ - public function getTeams(string $developer): array { - return $this->inner->getTeams($developer); + public function getTeams(string $developer, string $team = NULL): array { + return $this->inner->getTeams($developer, $team); + } + + /** + * {@inheritdoc} + */ + public function syncAppGroupMembers(string $team): array { + return $this->inner->syncAppGroupMembers($team); } /** diff --git a/modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityAddMemberEventTest.php b/modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityAddMemberEventTest.php index aa304763..79434824 100644 --- a/modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityAddMemberEventTest.php +++ b/modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityAddMemberEventTest.php @@ -54,6 +54,8 @@ protected function setUp(): void { parent::setUp(); $this->installEntitySchema('team_member_role'); + + $this->addOrganizationMatchedResponse(); } /** diff --git a/modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityRemoveMemberEventTest.php b/modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityRemoveMemberEventTest.php index 018b36b4..3c704c77 100644 --- a/modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityRemoveMemberEventTest.php +++ b/modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityRemoveMemberEventTest.php @@ -53,6 +53,8 @@ protected function setUp(): void { parent::setUp(); $this->installEntitySchema('team_member_role'); + + $this->addOrganizationMatchedResponse(); } /** diff --git a/modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityUpdateEventTest.php b/modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityUpdateEventTest.php index 7503c678..fcfcedf7 100644 --- a/modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityUpdateEventTest.php +++ b/modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityUpdateEventTest.php @@ -55,6 +55,9 @@ public function testEvent() { ]); $config_entity->save(); + // Add matched organization response so it returns the org whenever called. + $this->addOrganizationMatchedResponse(); + // Insert and update entity. /** @var \Drupal\apigee_edge\Entity\DeveloperAppInterface $entity */ $entity = $this->createDeveloperApp(); diff --git a/modules/apigee_edge_teams/apigee_edge_teams.install b/modules/apigee_edge_teams/apigee_edge_teams.install index 4e73e9d1..bd629d1f 100644 --- a/modules/apigee_edge_teams/apigee_edge_teams.install +++ b/modules/apigee_edge_teams/apigee_edge_teams.install @@ -25,7 +25,7 @@ use Drupal\user\RoleInterface; use Drupal\views\Views; /** - * Install, update and uninstall functions for Apigee Edge Teams. + * Install, update and uninstall functions for Apigee Edge and ApigeeX Teams. */ /** @@ -41,13 +41,13 @@ function apigee_edge_teams_requirements($phase) { $org_controller = \Drupal::service('apigee_edge.controller.organization'); /* @var \Apigee\Edge\Api\Management\Entity\Organization $organization */ $organization = $org_controller->load($sdk_connector->getOrganization()); - if ($organization && !OrganizationFeatures::isCompaniesFeatureAvailable($organization)) { + if ($organization && !OrganizationFeatures::isCompaniesFeatureAvailable($organization) && OrganizationFeatures::isMonetizationEnabled($organization)) { $url = [ ':url' => 'https://cloud.google.com/apigee/docs/api-platform/get-started/compare-apigee-products#unsupported-apis', ]; $message = ($phase == 'runtime') ? - t("The Apigee Edge Teams module functionality is not available for your org and should be uninstalled, because Edge company APIs are not supported in Apigee X and Apigee Hybrid orgs.", $url) : - t("The Apigee Edge Teams module functionality is not available for your org because Edge company APIs are not supported in Apigee X and Apigee Hybrid orgs.", $url); + t("The Teams module functionality is not available for monetization enabled org on Apigee X / Hybrid and should be uninstalled, because AppGroup APIs are not supported in Apigee X / Hybrid orgs with monetization enabled.", $url) : + t("The Teams module functionality is not available for monetization enabled org on Apigee X / Hybrid because AppGroup APIs are not supported in Apigee X / Hybrid orgs with monetization enabled.", $url); $requirements['apigee_edge_teams_not_supported'] = [ 'title' => t('Apigee Edge Teams'), 'description' => $message, diff --git a/modules/apigee_edge_teams/apigee_edge_teams.links.task.yml b/modules/apigee_edge_teams/apigee_edge_teams.links.task.yml index 72c8815a..68c777f5 100644 --- a/modules/apigee_edge_teams/apigee_edge_teams.links.task.yml +++ b/modules/apigee_edge_teams/apigee_edge_teams.links.task.yml @@ -1,6 +1,6 @@ apigee_edge_teams.settings.team: route_name: apigee_edge_teams.settings.team - title: 'Alias' + title: 'Settings' base_route: apigee_edge_teams.settings.team weight: -10 diff --git a/modules/apigee_edge_teams/apigee_edge_teams.services.yml b/modules/apigee_edge_teams/apigee_edge_teams.services.yml index 5246435e..933b644c 100644 --- a/modules/apigee_edge_teams/apigee_edge_teams.services.yml +++ b/modules/apigee_edge_teams/apigee_edge_teams.services.yml @@ -24,6 +24,14 @@ services: class: Drupal\apigee_edge_teams\CompanyMembershipObjectCache arguments: ['@cache_factory', '@apigee_edge.cache.memory_cache_factory', '@config.factory', '@datetime.time'] + apigee_edge_teams.cache.appgroup_membership_object: + class: Drupal\apigee_edge_teams\AppGroupMembershipObjectCache + arguments: ['@cache_factory', '@apigee_edge.cache.memory_cache_factory', '@config.factory', '@datetime.time'] + + apigee_edge.controller.cache.appgroup_teams: + class: Drupal\apigee_edge_teams\AppGroupCache + arguments: ['@apigee_edge.cache.memory_cache_factory'] + apigee_edge_teams.controller.team: class: Drupal\apigee_edge_teams\Entity\Controller\TeamController arguments: ['@apigee_edge.sdk_connector', '@apigee_edge.controller.organization', '@apigee_edge_teams.controller.cache.team', '@apigee_edge_teams.controller.cache.team_ids', '@apigee_edge.entity.controller.cache.app_cache_by_owner_factory', '@apigee_edge.entity.controller.cache.app_name_cache_by_owner_factory', '@apigee_edge_teams.cache.company_membership_object', '@apigee_edge.controller.cache.developer_companies'] @@ -40,6 +48,10 @@ services: class: Drupal\apigee_edge_teams\CompanyMembersControllerFactory arguments: ['@apigee_edge.sdk_connector', '@apigee_edge_teams.cache.company_membership_object'] + apigee_edge_teams.appgroup_members_controller_factory: + class: Drupal\apigee_edge_teams\AppGroupMembersControllerFactory + arguments: ['@apigee_edge.sdk_connector', '@apigee_edge_teams.cache.appgroup_membership_object'] + apigee_edge_teams.controller.cache.team: class: Drupal\apigee_edge\Entity\Controller\Cache\EntityCache arguments: ['@apigee_edge_teams.cache.memory_cache_factory', '@apigee_edge_teams.controller.cache.team_ids', team] @@ -49,7 +61,7 @@ services: apigee_edge_teams.team_membership_manager: class: Drupal\apigee_edge_teams\TeamMembershipManager - arguments: [ '@entity_type.manager', '@apigee_edge_teams.company_members_controller_factory', '@apigee_edge.controller.developer', '@apigee_edge.controller.cache.developer_companies', '@cache_tags.invalidator', '@logger.channel.apigee_edge_teams'] + arguments: [ '@entity_type.manager', '@apigee_edge_teams.company_members_controller_factory','@apigee_edge_teams.appgroup_members_controller_factory', '@apigee_edge.controller.developer', '@apigee_edge.controller.cache.developer_companies', '@cache_tags.invalidator', '@logger.channel.apigee_edge_teams', '@apigee_edge.controller.organization'] apigee_edge_teams.team_permissions: class: Drupal\apigee_edge_teams\TeamPermissionHandler @@ -85,7 +97,7 @@ services: apigee_edge_teams.event_subscriber.team_invitation_event_subscriber: class: Drupal\apigee_edge_teams\EventSubscriber\TeamInvitationSubscriber - arguments: ['@logger.channel.apigee_edge_teams', '@entity_type.manager', '@apigee_edge_teams.team_membership_manager', '@apigee_edge_teams.team_invitation_notifier.email'] + arguments: ['@logger.channel.apigee_edge_teams', '@entity_type.manager', '@apigee_edge_teams.team_membership_manager', '@apigee_edge_teams.team_invitation_notifier.email', '@apigee_edge.controller.organization'] tags: - { name: event_subscriber } diff --git a/modules/apigee_edge_teams/config/install/apigee_edge_teams.team_settings.yml b/modules/apigee_edge_teams/config/install/apigee_edge_teams.team_settings.yml index 2160048d..388d93e3 100644 --- a/modules/apigee_edge_teams/config/install/apigee_edge_teams.team_settings.yml +++ b/modules/apigee_edge_teams/config/install/apigee_edge_teams.team_settings.yml @@ -1,4 +1,6 @@ langcode: en +team_prefix: '' +channelid: '' entity_label_singular: '' entity_label_plural: '' cache_expiration: 900 diff --git a/modules/apigee_edge_teams/config/schema/apigee_edge_teams.schema.yml b/modules/apigee_edge_teams/config/schema/apigee_edge_teams.schema.yml index 6c4286df..69f5d137 100644 --- a/modules/apigee_edge_teams/config/schema/apigee_edge_teams.schema.yml +++ b/modules/apigee_edge_teams/config/schema/apigee_edge_teams.schema.yml @@ -2,6 +2,12 @@ apigee_edge_teams.team_settings: type: config_object label: 'Team settings' mapping: + team_prefix: + type: label + label: 'Prefix to add for the Team name' + channelid: + type: label + label: 'ChannelId settings' entity_label_singular: type: label label: 'How to refer to a Team on the UI (singular)' diff --git a/modules/apigee_edge_teams/src/Access/ManageTeamMembersAccess.php b/modules/apigee_edge_teams/src/Access/ManageTeamMembersAccess.php index 153387ed..acb777eb 100644 --- a/modules/apigee_edge_teams/src/Access/ManageTeamMembersAccess.php +++ b/modules/apigee_edge_teams/src/Access/ManageTeamMembersAccess.php @@ -86,7 +86,8 @@ public function access(RouteMatchInterface $route_match, AccountInterface $accou // If the developer parameter is available in the route make sure it is // member of the team. if ($developer !== NULL) { - if (!in_array($team->id(), $this->teamMembershipManager->getTeams($developer->getEmail()))) { + // Argument #2 in getTeams() is required for checking the AppGroup members and not required for Edge. + if (!in_array($team->id(), $this->teamMembershipManager->getTeams($developer->getEmail(), $team->id()))) { return AccessResultForbidden::forbidden("The {$developer->getEmail()} developer is not member of the {$team->id()} team."); } } diff --git a/modules/apigee_edge_teams/src/AppGroupMembersController.php b/modules/apigee_edge_teams/src/AppGroupMembersController.php new file mode 100644 index 00000000..b2938efa --- /dev/null +++ b/modules/apigee_edge_teams/src/AppGroupMembersController.php @@ -0,0 +1,209 @@ +appGroup = $appGroup; + $this->connector = $connector; + $this->appGroupMembershipObjectCache = $appgroup_membership_object_cache; + } + + /** + * Returns the decorated appgroup members controller from the SDK. + * + * @return \Apigee\Edge\Api\ApigeeX\Controller\AppGroupMembersController + * The initialized appgroup members controller. + */ + private function decorated(): ApigeeXAppGroupMembersController { + return new ApigeeXAppGroupMembersController($this->appGroup, $this->connector->getOrganization(), $this->connector->getClient()); + } + + /** + * {@inheritdoc} + */ + public function getAppGroup(): string { + return $this->decorated()->getAppGroup(); + } + + /** + * Syncs the appgroup team members email and roles in database. + * + * @return \Apigee\Edge\Api\ApigeeX\Structure\AppGroupMembership + * Array of developers with their optional roles in the appgroup. + */ + public function syncAppGroupMembers(): AppGroupMembership { + $membership = $this->decorated()->getMembers(); + + $developer_exist = TRUE; + foreach ($membership->getMembers() as $developer_id => $roles) { + $roles = is_array($roles) ? $roles : []; + + /** @var \Drupal\user\Entity\User $account */ + $account = user_load_by_mail($developer_id); + + if (!$account) { + $developer_exist = FALSE; + /** @var \Drupal\apigee_edge_teams\Entity\Storage\TeamInvitationStorageInterface $teamInvitationStorage */ + $teamInvitationStorage = \Drupal::entityTypeManager()->getStorage('team_invitation'); + + $pending_invitations = array_filter($teamInvitationStorage->loadByRecipient($developer_id, $this->appGroup), function (TeamInvitationInterface $team_invitation) { + return $team_invitation->isPending(); + }); + + // Checking if this developer has already pending invite to prevent multiple invites. + if (count($pending_invitations) === 0) { + $teamInvitationStorage->create([ + 'team' => ['target_id' => $this->appGroup], + 'team_roles' => array_values(array_map(function (string $role) { + return ['target_id' => $role]; + }, $roles)), + 'recipient' => $developer_id, + ])->save(); + } + } + else { + /** @var \Drupal\apigee_edge_teams\Entity\TeamInterface|null $team_entity */ + $team_entity = \Drupal::entityTypeManager()->getStorage('team')->load($this->appGroup); + /** @var \Drupal\apigee_edge_teams\Entity\Storage\TeamMemberRoleStorageInterface $team_member_role_storage */ + $team_member_role_storage = \Drupal::entityTypeManager()->getStorage('team_member_role'); + $team_member_role_storage->addTeamRoles($account, $team_entity, $roles); + } + } + // Caching the membership only if all the developer exists in Drupal + // to avoid team member without access. + if ($developer_exist) { + $this->appGroupMembershipObjectCache->saveMembership($this->appGroup, $membership); + } + + return $membership; + } + + /** + * {@inheritdoc} + */ + public function getMembers(): AppGroupMembership { + $membership = $this->appGroupMembershipObjectCache->getMembership($this->appGroup); + if ($membership === NULL) { + /** @var \Drupal\apigee_edge_teams\Entity\TeamInterface|null $team_entity */ + $team_entity = \Drupal::entityTypeManager()->getStorage('team')->load($this->appGroup); + // Load team_member_role object. + $team_member_role_storage = \Drupal::entityTypeManager()->getStorage('team_member_role'); + $members = array_reduce($team_member_role_storage->loadByTeam($team_entity), function ($carry, TeamMemberRoleInterface $developer_role) { + $carry[$developer_role->getDeveloper()->getEmail()] = $developer_role->getDeveloper()->getEmail(); + return $carry; + }, + []); + $membership = new AppGroupMembership($members); + $this->appGroupMembershipObjectCache->saveMembership($team_entity->id(), $membership); + } + + return $membership; + } + + /** + * {@inheritdoc} + */ + public function setMembers(AppGroupMembership $members): AppGroupMembership { + // Get the existing members and roles from ApigeeX. + $apigeeReservedMembers = $this->decorated()->getMembers(); + // Getting all developers including the newly added one. + $developers = array_merge($apigeeReservedMembers->getMembers(), $members->getMembers()); + + foreach ($developers as $developer => $roles) { + $members->setMember($developer, $roles); + } + // Storing membership info on appgroups __apigee_reserved__developer_details attribute for ApigeeX. + $result = $this->decorated()->setMembers($members); + + // Returned membership does not contain all actual members of the appGroup, + // so it is easier to remove the membership object from the cache and + // enforce reload in getMembers(). + $this->appGroupMembershipObjectCache->removeMembership($this->appGroup); + return $result; + } + + /** + * {@inheritdoc} + */ + public function removeMember(string $email): void { + // Get the existing members and roles from ApigeeX. + $apigeeReservedMembers = $this->decorated()->getMembers(); + + foreach ($apigeeReservedMembers->getMembers() as $developer => $roles) { + if ($developer === $email) { + $apigeeReservedMembers->removeMember($developer); + } + } + // Storing membership info on appgroups __apigee_reserved__developer_details attribute for ApigeeX. + // Removing and updating the member on appgroups __apigee_reserved__developer_details attribute for ApigeeX. + $result = $this->decorated()->setMembers($apigeeReservedMembers); + + $this->appGroupMembershipObjectCache->removeMembership($this->appGroup); + } + +} diff --git a/modules/apigee_edge_teams/src/AppGroupMembersControllerFactory.php b/modules/apigee_edge_teams/src/AppGroupMembersControllerFactory.php new file mode 100644 index 00000000..d00b8135 --- /dev/null +++ b/modules/apigee_edge_teams/src/AppGroupMembersControllerFactory.php @@ -0,0 +1,77 @@ +connector = $connector; + $this->appGroupMembershipObjectCache = $appgroup_membership_object_cache; + } + + /** + * {@inheritdoc} + */ + public function appGroupMembersController(string $appGroup): AppGroupMembersControllerInterface { + if (!isset($this->instances[$appGroup])) { + $this->instances[$appGroup] = new AppGroupMembersController($appGroup, $this->connector, $this->appGroupMembershipObjectCache); + } + + return $this->instances[$appGroup]; + } + +} diff --git a/modules/apigee_edge_teams/src/AppGroupMembersControllerFactoryInterface.php b/modules/apigee_edge_teams/src/AppGroupMembersControllerFactoryInterface.php new file mode 100644 index 00000000..60b00819 --- /dev/null +++ b/modules/apigee_edge_teams/src/AppGroupMembersControllerFactoryInterface.php @@ -0,0 +1,39 @@ +persistentCacheBackend = $cache_factory->get(self::DEFAULT_CACHE_BIN); + $this->persistentCacheExpiration = $config->get('apigee_edge_teams.team_settings')->get('cache_expiration'); + $this->memoryCache = $memory_cache_factory->get('appgroup_membership_object'); + $this->systemTime = $time; + } + + /** + * {@inheritdoc} + */ + public function saveMembership(string $appGroup, AppGroupMembership $membership): void { + $expiration = $this->persistentCacheExpiration; + + // Do not save in cache, if expiration is set to 0. + if (0 === $expiration) { + return; + } + + // Tag appgroup membership cache entries with members' (developers') email + // addresses for easier cache invalidation when a developer gets removed. + $tags = []; + foreach (array_keys($membership->getMembers()) as $developer_email) { + $tags[] = "developer:{$developer_email}"; + } + $this->memoryCache->set($appGroup, $membership, CacheBackendInterface::CACHE_PERMANENT, $tags); + if ($expiration !== CacheBackendInterface::CACHE_PERMANENT) { + $expiration = $this->systemTime->getCurrentTime() + $expiration; + } + $this->persistentCacheBackend->set($appGroup, $membership, $expiration, $tags); + } + + /** + * {@inheritdoc} + */ + public function removeMembership(string $appGroup): void { + $this->memoryCache->invalidate($appGroup); + $this->persistentCacheBackend->invalidate($appGroup); + } + + /** + * {@inheritdoc} + */ + public function invalidateMemberships(array $tags): void { + $this->memoryCache->invalidateTags($tags); + if ($this->persistentCacheBackend instanceof CacheTagsInvalidatorInterface) { + $this->persistentCacheBackend->invalidateTags($tags); + } + } + + /** + * {@inheritdoc} + */ + public function getMembership(string $appGroup): ?AppGroupMembership { + if ($data = $this->memoryCache->get($appGroup)) { + return $data->data; + } + + if ($data = $this->persistentCacheBackend->get($appGroup)) { + // Next time return this from the memory cache. + $this->memoryCache->set($appGroup, $data->data); + return $data->data; + } + + return NULL; + } + +} diff --git a/modules/apigee_edge_teams/src/AppGroupMembershipObjectCacheInterface.php b/modules/apigee_edge_teams/src/AppGroupMembershipObjectCacheInterface.php new file mode 100644 index 00000000..676ba61d --- /dev/null +++ b/modules/apigee_edge_teams/src/AppGroupMembershipObjectCacheInterface.php @@ -0,0 +1,68 @@ +decorated()->removeMember($email); $this->companyMembershipObjectCache->removeMembership($this->company); } diff --git a/modules/apigee_edge_teams/src/Controller/TeamMembersList.php b/modules/apigee_edge_teams/src/Controller/TeamMembersList.php index fe702e85..5082ab85 100644 --- a/modules/apigee_edge_teams/src/Controller/TeamMembersList.php +++ b/modules/apigee_edge_teams/src/Controller/TeamMembersList.php @@ -20,6 +20,11 @@ namespace Drupal\apigee_edge_teams\Controller; +use Apigee\Edge\Api\ApigeeX\Structure\AppGroupMembership; +use Apigee\Edge\Api\Management\Structure\CompanyMembership; +use Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface; +use Drupal\apigee_edge_teams\AppGroupMembershipObjectCacheInterface; +use Drupal\apigee_edge_teams\CompanyMembershipObjectCacheInterface; use Drupal\apigee_edge_teams\Entity\TeamInterface; use Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface; use Drupal\apigee_edge_teams\Entity\TeamRoleInterface; @@ -45,6 +50,27 @@ class TeamMembersList extends ControllerBase { */ private $teamMembershipManager; + /** + * The appgroup membership object cache. + * + * @var \Drupal\apigee_edge_teams\AppGroupMembershipObjectCacheInterface + */ + private $appGroupMembershipObjectCache; + + /** + * The company membership object cache. + * + * @var \Drupal\apigee_edge_teams\CompanyMembershipObjectCacheInterface + */ + private $companyMembershipObjectCache; + + /** + * The organization controller service. + * + * @var \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface + */ + private $orgController; + /** * Default member roles. * @@ -68,8 +94,14 @@ class TeamMembersList extends ControllerBase { * The entity type manager. * @param \Drupal\Core\Extension\ModuleHandlerInterface|null $module_handler * The module handler. + * @param \Drupal\apigee_edge_teams\CompanyMembershipObjectCacheInterface $company_membership_object_cache + * The company membership object cache. + * @param \Drupal\apigee_edge_teams\AppGroupMembershipObjectCacheInterface $appgroup_membership_object_cache + * The appgroup membership object cache. + * @param \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface $org_controller + * The organization controller service. */ - public function __construct(TeamMembershipManagerInterface $team_membership_manager, EntityTypeManagerInterface $entity_type_manager, ModuleHandlerInterface $module_handler = NULL) { + public function __construct(TeamMembershipManagerInterface $team_membership_manager, EntityTypeManagerInterface $entity_type_manager, ModuleHandlerInterface $module_handler = NULL, CompanyMembershipObjectCacheInterface $company_membership_object_cache, AppGroupMembershipObjectCacheInterface $appgroup_membership_object_cache, OrganizationControllerInterface $org_controller) { if (!$module_handler) { @trigger_error('Calling ' . __METHOD__ . ' without the $module_handler is deprecated in apigee_edge:8-x-1.19 and is required before apigee_edge:8.x-2.0. See https://github.com/apigee/apigee-edge-drupal/pull/518.', E_USER_DEPRECATED); $module_handler = \Drupal::moduleHandler(); @@ -83,6 +115,9 @@ public function __construct(TeamMembershipManagerInterface $team_membership_mana } $this->moduleHandler = $module_handler; + $this->companyMembershipObjectCache = $company_membership_object_cache; + $this->appGroupMembershipObjectCache = $appgroup_membership_object_cache; + $this->orgController = $org_controller; } /** @@ -92,7 +127,10 @@ public static function create(ContainerInterface $container) { return new static( $container->get('apigee_edge_teams.team_membership_manager'), $container->get('entity_type.manager'), - $container->get('module_handler') + $container->get('module_handler'), + $container->get('apigee_edge_teams.cache.company_membership_object'), + $container->get('apigee_edge_teams.cache.appgroup_membership_object'), + $container->get('apigee_edge.controller.organization') ); } diff --git a/modules/apigee_edge_teams/src/Entity/AppGroupCache.php b/modules/apigee_edge_teams/src/Entity/AppGroupCache.php new file mode 100644 index 00000000..113db292 --- /dev/null +++ b/modules/apigee_edge_teams/src/Entity/AppGroupCache.php @@ -0,0 +1,91 @@ +backend = $memory_cache_factory->get('developer_companies'); + } + + /** + * {@inheritdoc} + */ + public function getAppGroups(string $id): ?array { + $item = $this->backend->get($id); + return $item ? $item->data : NULL; + } + + /** + * {@inheritdoc} + */ + public function saveAppGroups(array $developers): void { + /** @var \Apigee\Edge\Api\Management\Entity\DeveloperInterface $developer */ + foreach ($developers as $developer) { + $tags = array_merge([ + "developer:{$developer->getDeveloperId()}", + "developer:{$developer->getEmail()}", + ], array_map(function (string $company) { + return "company:{$company}"; + }, $developer->getAppGroups())); + $this->backend->set($developer->id(), $developer->getAppGroups(), CacheBackendInterface::CACHE_PERMANENT, $tags); + } + } + + /** + * {@inheritdoc} + */ + public function remove(array $ids = []): void { + if (empty($ids)) { + $this->backend->invalidateAll(); + } + else { + $this->backend->invalidateMultiple($ids); + } + } + + /** + * {@inheritdoc} + */ + public function invalidate(array $tags): void { + $this->backend->invalidateTags($tags); + } + +} diff --git a/modules/apigee_edge_teams/src/Entity/AppGroupCacheInterface.php b/modules/apigee_edge_teams/src/Entity/AppGroupCacheInterface.php new file mode 100644 index 00000000..cbe2865b --- /dev/null +++ b/modules/apigee_edge_teams/src/Entity/AppGroupCacheInterface.php @@ -0,0 +1,66 @@ +teamAppControllerFactory = $team_app_controller_factory; + $this->appController = $app_controller; + } + + /** + * {@inheritdoc} + */ + public function create(EntityInterface $entity): void { + /** @var \Apigee\Edge\Api\ApigeeX\Entity\AppGroupAppInterface $entity */ + if (empty($entity->getAppGroup())) { + // Sanity check. + throw new RuntimeException('AppGroup name has to set on the app.'); + } + $controller = $this->teamAppControllerFactory->teamAppController($entity->getAppGroup()); + $controller->create($entity); + } + + /** + * {@inheritdoc} + */ + public function load(string $id): EntityInterface { + return $this->appController->loadAppGroup($id); + } + + /** + * {@inheritdoc} + */ + public function update(EntityInterface $entity): void { + /** @var \Apigee\Edge\Api\ApigeeX\Entity\AppGroupAppInterface $entity */ + $controller = $this->teamAppControllerFactory->teamAppController($entity->getAppGroup()); + $controller->update($entity); + } + + /** + * {@inheritdoc} + */ + public function delete(string $id): void { + // Try to be smart here and load the app from the appgroup app + // entity cache (app controller's cache is probably empty unless there were + // a load() or getEntities() call before). + $entity = \Drupal::entityTypeManager()->getStorage('team_app')->load($id); + if (!$entity) { + // Entity has not found in the entity cache, we have it from Apigee Edge. + $entity = $this->load($id); + } + /** @var \Apigee\Edge\Api\ApigeeX\Entity\AppGroupAppInterface $entity */ + $controller = $this->teamAppControllerFactory->teamAppController($entity->getAppGroup()); + // The id that we got is a UUID, what we need is an app name. + $controller->delete($entity->getName()); + } + + /** + * {@inheritdoc} + */ + public function loadAll(): array { + return array_filter($this->appController->listApps(TRUE), function (AppInterface $app) { + return $app instanceof AppGroupAppInterface; + }); + } + +} diff --git a/modules/apigee_edge_teams/src/Entity/Controller/TeamAppController.php b/modules/apigee_edge_teams/src/Entity/Controller/TeamAppController.php index 6fcde501..9f747338 100644 --- a/modules/apigee_edge_teams/src/Entity/Controller/TeamAppController.php +++ b/modules/apigee_edge_teams/src/Entity/Controller/TeamAppController.php @@ -20,6 +20,7 @@ namespace Drupal\apigee_edge_teams\Entity\Controller; +use Apigee\Edge\Api\ApigeeX\Controller\AppGroupAppController as EdgeAppGroupAppController; use Apigee\Edge\Api\Management\Controller\AppByOwnerControllerInterface as EdgeAppByOwnerControllerInterface; use Apigee\Edge\Api\Management\Controller\CompanyAppController as EdgeCompanyAppController; use Drupal\apigee_edge\Entity\Controller\AppByOwnerController; @@ -36,7 +37,13 @@ final class TeamAppController extends AppByOwnerController implements TeamAppCon */ protected function decorated(): EdgeAppByOwnerControllerInterface { if (!isset($this->instances[$this->owner])) { - $this->instances[$this->owner] = new EdgeCompanyAppController($this->connector->getOrganization(), $this->owner, $this->connector->getClient(), NULL, $this->organizationController); + // Checks whether the organization is Edge or ApigeeX organization. + if ($this->organizationController->isOrganizationApigeeX()) { + $this->instances[$this->owner] = new EdgeAppGroupAppController($this->connector->getOrganization(), $this->owner, $this->connector->getClient(), NULL, $this->organizationController); + } + else { + $this->instances[$this->owner] = new EdgeCompanyAppController($this->connector->getOrganization(), $this->owner, $this->connector->getClient(), NULL, $this->organizationController); + } } return $this->instances[$this->owner]; } diff --git a/modules/apigee_edge_teams/src/Entity/Controller/TeamAppCredentialController.php b/modules/apigee_edge_teams/src/Entity/Controller/TeamAppCredentialController.php index 88f55ab9..1c901c91 100644 --- a/modules/apigee_edge_teams/src/Entity/Controller/TeamAppCredentialController.php +++ b/modules/apigee_edge_teams/src/Entity/Controller/TeamAppCredentialController.php @@ -20,9 +20,11 @@ namespace Drupal\apigee_edge_teams\Entity\Controller; +use Apigee\Edge\Api\ApigeeX\Controller\AppGroupAppCredentialController; use Apigee\Edge\Api\Management\Controller\AppCredentialController as EdgeAppCredentialController; use Apigee\Edge\Api\Management\Controller\CompanyAppCredentialController; use Drupal\apigee_edge\Entity\Controller\AppCredentialControllerBase; +use Drupal\apigee_edge\Entity\Controller\OrganizationController; use Drupal\apigee_edge\Event\AbstractAppCredentialEvent; /** @@ -38,7 +40,14 @@ final class TeamAppCredentialController extends AppCredentialControllerBase impl */ protected function decorated(): EdgeAppCredentialController { if (!isset($this->instances[$this->owner][$this->appName])) { - $this->instances[$this->owner][$this->appName] = new CompanyAppCredentialController($this->connector->getOrganization(), $this->owner, $this->appName, $this->connector->getClient()); + $organizationController = new OrganizationController($this->connector); + // Checks whether the organization is Edge or ApigeeX organization. + if ($organizationController->isOrganizationApigeeX()) { + $this->instances[$this->owner][$this->appName] = new AppGroupAppCredentialController($this->connector->getOrganization(), $this->owner, $this->appName, $this->connector->getClient()); + } + else { + $this->instances[$this->owner][$this->appName] = new CompanyAppCredentialController($this->connector->getOrganization(), $this->owner, $this->appName, $this->connector->getClient()); + } } return $this->instances[$this->owner][$this->appName]; } diff --git a/modules/apigee_edge_teams/src/Entity/Controller/TeamController.php b/modules/apigee_edge_teams/src/Entity/Controller/TeamController.php index 1adc8210..b9243917 100644 --- a/modules/apigee_edge_teams/src/Entity/Controller/TeamController.php +++ b/modules/apigee_edge_teams/src/Entity/Controller/TeamController.php @@ -20,6 +20,8 @@ namespace Drupal\apigee_edge_teams\Entity\Controller; +use Apigee\Edge\Api\ApigeeX\Controller\AppGroupController; +use Apigee\Edge\Api\ApigeeX\Controller\AppGroupControllerInterface; use Apigee\Edge\Api\Management\Controller\CompanyController as EdgeCompanyController; use Apigee\Edge\Api\Management\Controller\CompanyControllerInterface as EdgeCompanyControllerInterface; use Apigee\Edge\Entity\EntityInterface; @@ -149,14 +151,19 @@ public function __construct(SDKConnectorInterface $connector, OrganizationContro } /** - * Returns the decorated company controller from the SDK. + * Returns the decorated company controller or appgroup controller from the SDK. * - * @return \Apigee\Edge\Api\Management\Controller\CompanyControllerInterface - * The initialized company controller. + * @return CompanyControllerInterface|AppGroupControllerInterface + * The initialized company or appgroup controller. */ - private function decorated(): EdgeCompanyControllerInterface { + private function decorated(): EdgeCompanyControllerInterface|AppGroupControllerInterface { if ($this->instance === NULL) { - $this->instance = new EdgeCompanyController($this->connector->getOrganization(), $this->connector->getClient(), NULL, $this->orgController); + if ($this->orgController->isOrganizationApigeeX()) { + $this->instance = new AppGroupController($this->connector->getOrganization(), $this->connector->getClient(), NULL, $this->orgController); + } + else { + $this->instance = new EdgeCompanyController($this->connector->getOrganization(), $this->connector->getClient(), NULL, $this->orgController); + } } return $this->instance; } @@ -179,7 +186,9 @@ protected function entityIdCache(): EntityIdCacheInterface { * {@inheritdoc} */ public function setStatus(string $entity_id, string $status): void { - $this->decorated()->setStatus($entity_id, $status); + if (!$this->orgController->isOrganizationApigeeX()) { + $this->decorated()->setStatus($entity_id, $status); + } // Enforce reload of entity from Apigee Edge. $this->entityCache->removeEntities([$entity_id]); $this->entityCache->allEntitiesInCache(FALSE); diff --git a/modules/apigee_edge_teams/src/Entity/Form/TeamAppFormTrait.php b/modules/apigee_edge_teams/src/Entity/Form/TeamAppFormTrait.php index 40bb3b80..fb0e230f 100644 --- a/modules/apigee_edge_teams/src/Entity/Form/TeamAppFormTrait.php +++ b/modules/apigee_edge_teams/src/Entity/Form/TeamAppFormTrait.php @@ -182,7 +182,8 @@ protected function nonMemberApiProductAccessWarningElement(array $form, FormStat '#weight' => -100, ]; - if (!in_array($this->getTeamName($form, $form_state), $this->getTeamMembershipMananger()->getTeams(\Drupal::currentUser()->getEmail()))) { + // Argument #2 in getTeams() is required for checking the AppGroup members and not required for Edge. + if (!in_array($this->getTeamName($form, $form_state), $this->getTeamMembershipMananger()->getTeams(\Drupal::currentUser()->getEmail(), $this->getTeamName($form, $form_state)))) { $element['#message_list']['warning'][] = t('You are not member of this @team. You may see @api_products here that a @team member can not see.', [ '@team' => mb_strtolower($this->getEntityTypeManager()->getDefinition('team')->getSingularLabel()), '@api_products' => $this->getEntityTypeManager()->getDefinition('api_product')->getPluralLabel(), @@ -210,7 +211,8 @@ protected function apiProductList(array $form, FormStateInterface $form_state): // be visible that visibility is matching with the configured // non_member_team_apps_visible_api_products config key value. // @see nonMemberApiProductAccessWarningElement() - if (!in_array($team_name, $this->getTeamMembershipMananger()->getTeams(\Drupal::currentUser()->getEmail()))) { + // Argument #2 in getTeams() is required for checking the AppGroup members and not required for Edge. + if (!in_array($team_name, $this->getTeamMembershipMananger()->getTeams(\Drupal::currentUser()->getEmail(), $team_name))) { $filter = function (ApiProductInterface $api_product) use ($team) { $visibility = $api_product->getAttributeValue('access') ?? 'public'; return in_array($visibility, $this->getConfigObject('apigee_edge_teams.team_settings')->get('non_member_team_apps_visible_api_products')); diff --git a/modules/apigee_edge_teams/src/Entity/Form/TeamForm.php b/modules/apigee_edge_teams/src/Entity/Form/TeamForm.php index 444ce3ba..a9f22d85 100644 --- a/modules/apigee_edge_teams/src/Entity/Form/TeamForm.php +++ b/modules/apigee_edge_teams/src/Entity/Form/TeamForm.php @@ -21,16 +21,20 @@ namespace Drupal\apigee_edge_teams\Entity\Form; use Apigee\Edge\Exception\ApiException; +use Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface; use Drupal\apigee_edge\Entity\Form\EdgeEntityFormInterface; use Drupal\apigee_edge\Entity\Form\FieldableEdgeEntityForm; use Drupal\apigee_edge_teams\Entity\TeamRoleInterface; +use Drupal\apigee_edge_teams\Form\TeamAliasForm; use Drupal\apigee_edge_teams\TeamMembershipManagerInterface; +use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Logger\LoggerChannelInterface; use Drupal\Core\Session\AccountProxyInterface; use Drupal\Core\Utility\Error; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\RequestStack; /** * General form handler for the team create/edit forms. @@ -42,6 +46,12 @@ class TeamForm extends FieldableEdgeEntityForm implements EdgeEntityFormInterfac */ const ADMIN_EMAIL_ATTRIBUTE = 'ADMIN_EMAIL'; + /** + * Membership attribute name for admin email in appgroup. + */ + const APPGROUP_ADMIN_EMAIL_ATTRIBUTE = '__apigee_reserved__developer_details'; + + /** * The team membership manager service. * @@ -49,6 +59,13 @@ class TeamForm extends FieldableEdgeEntityForm implements EdgeEntityFormInterfac */ protected $teamMembershipManager; + /** + * Configuration Factory. + * + * @var \Drupal\Core\Config\ConfigFactory + */ + protected $config; + /** * The current user. * @@ -63,6 +80,27 @@ class TeamForm extends FieldableEdgeEntityForm implements EdgeEntityFormInterfac */ protected $logger; + /** + * The request service. + * + * @var Symfony\Component\HttpFoundation\RequestStack + */ + protected $request; + + /** + * The organization controller service. + * + * @var \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface + */ + private $orgController; + + /** + * The Team prefix value. + * + * @var string|null + */ + private $teamPrefix; + /** * TeamForm constructor. * @@ -74,12 +112,24 @@ class TeamForm extends FieldableEdgeEntityForm implements EdgeEntityFormInterfac * The current user. * @param \Drupal\Core\Logger\LoggerChannelInterface $logger * The logger service. + * @param \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface $org_controller + * The organization controller service. + * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack + * The request stack object. + * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory + * Config factory. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager, TeamMembershipManagerInterface $team_membership_manager, AccountProxyInterface $current_user, LoggerChannelInterface $logger) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, TeamMembershipManagerInterface $team_membership_manager, AccountProxyInterface $current_user, LoggerChannelInterface $logger, OrganizationControllerInterface $org_controller, RequestStack $request_stack, ConfigFactoryInterface $config_factory) { $this->entityTypeManager = $entity_type_manager; $this->teamMembershipManager = $team_membership_manager; $this->currentUser = $current_user; $this->logger = $logger; + $this->orgController = $org_controller; + $this->request = $request_stack->getCurrentRequest(); + $this->config = $config_factory->get('apigee_edge_teams.team_settings'); + // Prefixing the value to team name. + // Configurable in team-settings. + $this->team_prefix = !empty($this->config->get('team_prefix')) ? mb_strtolower($this->config->get('team_prefix')) : ""; } /** @@ -90,7 +140,10 @@ public static function create(ContainerInterface $container) { $container->get('entity_type.manager'), $container->get('apigee_edge_teams.team_membership_manager'), $container->get('current_user'), - $container->get('logger.channel.apigee_edge_teams') + $container->get('logger.channel.apigee_edge_teams'), + $container->get('apigee_edge.controller.organization'), + $container->get('request_stack'), + $container->get('config.factory') ); } @@ -98,14 +151,30 @@ public static function create(ContainerInterface $container) { * {@inheritdoc} */ public function buildEntity(array $form, FormStateInterface $form_state) { + if (str_contains($form_state->getValue('name'), $this->team_prefix) === FALSE) { + // Update the team name with predefined prefix. + $form_state->setValue('name', $this->team_prefix . $form_state->getValue('name')); + } + /** @var \Drupal\apigee_edge_teams\Entity\TeamInterface $team */ $team = parent::buildEntity($form, $form_state); // ADMIN_EMAIL_ATTRIBUTE is a required field for monetization. // We add to any team to make sure team creation works for mint orgs even // if they do not enable the m10n teams module. - $team->setAttribute(static::ADMIN_EMAIL_ATTRIBUTE, $this->currentUser->getEmail()); + if ($this->orgController->isOrganizationApigeeX()) { + $team->setAttribute(static::APPGROUP_ADMIN_EMAIL_ATTRIBUTE, '[{"developer":"' . $this->currentUser->getEmail() . '","roles":["admin"]}]'); + global $base_url; + // Channel url for a team. + $team->setChannelUri($base_url . '/teams/' . $team->id()); + // ChannelId is configurable from Admin portal. + $channelId = !empty($this->config->get('channelid')) ? $this->config->get('channelid') : TeamAliasForm::originalChannelId(); + $team->setChannelId(trim($channelId)); + } + else { + $team->setAttribute(static::ADMIN_EMAIL_ATTRIBUTE, $this->currentUser->getEmail()); + } return $team; } @@ -126,6 +195,7 @@ public function form(array $form, FormStateInterface $form_state) { 'label' => $this->t('Internal name'), 'exists' => [$this, 'exists'], ], + '#field_prefix' => $team->isNew() ? $this->team_prefix : "", '#disabled' => !$team->isNew(), '#default_value' => $team->id(), ]; @@ -150,11 +220,11 @@ public function exists(string $name, array $element, FormStateInterface $form_st if ($name === '') { return FALSE; } - // Only member with access can check if team exists. - $query = $this->entityTypeManager->getStorage('team') - ->getQuery() - ->accessCheck(TRUE) - ->condition('name', $name); + if (str_contains($name, $this->team_prefix) === FALSE) { + // Update the team name with predefined prefix. + $name = $this->team_prefix . $form_state->getValue('name'); + } + $query = $this->entityTypeManager->getStorage('team')->getQuery()->condition('name', $name); return (bool) $query->count()->execute(); } @@ -193,7 +263,17 @@ public function save(array $form, FormStateInterface $form_state) { if ($was_new) { try { - $this->teamMembershipManager->addMembers($team->id(), [$this->currentUser->getEmail()]); + if ($this->orgController->isOrganizationApigeeX()) { + // For ApigeeX adding the member as admin. + $this->teamMembershipManager->addMembers($team->id(), [ + $this->currentUser->getEmail() => ['admin'] + ]); + } + else { + $this->teamMembershipManager->addMembers($team->id(), [ + $this->currentUser->getEmail() + ]); + } try { /** @var \Drupal\apigee_edge_teams\Entity\Storage\TeamMemberRoleStorageInterface $team_member_role_storage */ diff --git a/modules/apigee_edge_teams/src/Entity/Storage/TeamAppStorage.php b/modules/apigee_edge_teams/src/Entity/Storage/TeamAppStorage.php index 6ab0e8ff..67377df7 100644 --- a/modules/apigee_edge_teams/src/Entity/Storage/TeamAppStorage.php +++ b/modules/apigee_edge_teams/src/Entity/Storage/TeamAppStorage.php @@ -23,7 +23,9 @@ use Drupal\apigee_edge\Entity\AppInterface; use Drupal\apigee_edge\Entity\Controller\AppControllerInterface; use Drupal\apigee_edge\Entity\Controller\EdgeEntityControllerInterface; +use Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface; use Drupal\apigee_edge\Entity\Storage\AppStorage; +use Drupal\apigee_edge_teams\Entity\Controller\TeamAppApigeeXEntityControllerProxy; use Drupal\apigee_edge_teams\Entity\Controller\TeamAppControllerFactoryInterface; use Drupal\apigee_edge_teams\Entity\Controller\TeamAppEdgeEntityControllerProxy; use Drupal\Component\Datetime\TimeInterface; @@ -44,6 +46,13 @@ class TeamAppStorage extends AppStorage implements TeamAppStorageInterface { */ private $teamAppControllerFactory; + /** + * The organization controller service. + * + * @var \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface + */ + private $orgController; + /** * AppStorage constructor. * @@ -59,10 +68,13 @@ class TeamAppStorage extends AppStorage implements TeamAppStorageInterface { * The team app controller factory service. * @param \Drupal\apigee_edge\Entity\Controller\AppControllerInterface $app_controller * The app controller service. + * @param \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface $org_controller + * The organization controller service. */ - public function __construct(EntityTypeInterface $entity_type, CacheBackendInterface $cache_backend, MemoryCacheInterface $memory_cache, TimeInterface $system_time, TeamAppControllerFactoryInterface $team_app_controller_factory, AppControllerInterface $app_controller) { + public function __construct(EntityTypeInterface $entity_type, CacheBackendInterface $cache_backend, MemoryCacheInterface $memory_cache, TimeInterface $system_time, TeamAppControllerFactoryInterface $team_app_controller_factory, AppControllerInterface $app_controller, OrganizationControllerInterface $org_controller) { parent::__construct($entity_type, $cache_backend, $memory_cache, $system_time, $app_controller); $this->teamAppControllerFactory = $team_app_controller_factory; + $this->orgController = $org_controller; } /** @@ -75,7 +87,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI $container->get('entity.memory_cache'), $container->get('datetime.time'), $container->get('apigee_edge_teams.controller.team_app_controller_factory'), - $container->get('apigee_edge.controller.app') + $container->get('apigee_edge.controller.app'), + $container->get('apigee_edge.controller.organization') ); } @@ -83,7 +96,13 @@ public static function createInstance(ContainerInterface $container, EntityTypeI * {@inheritdoc} */ protected function entityController(): EdgeEntityControllerInterface { - return new TeamAppEdgeEntityControllerProxy($this->teamAppControllerFactory, $this->appController); + if ($this->orgController->isOrganizationApigeeX()) { + $teamAppEntityControllerProxy = new TeamAppApigeeXEntityControllerProxy($this->teamAppControllerFactory, $this->appController); + } + else { + $teamAppEntityControllerProxy = new TeamAppEdgeEntityControllerProxy($this->teamAppControllerFactory, $this->appController); + } + return $teamAppEntityControllerProxy; } /** diff --git a/modules/apigee_edge_teams/src/Entity/Storage/TeamMemberRoleStorage.php b/modules/apigee_edge_teams/src/Entity/Storage/TeamMemberRoleStorage.php index af3e6040..11de4f27 100644 --- a/modules/apigee_edge_teams/src/Entity/Storage/TeamMemberRoleStorage.php +++ b/modules/apigee_edge_teams/src/Entity/Storage/TeamMemberRoleStorage.php @@ -20,6 +20,7 @@ namespace Drupal\apigee_edge_teams\Entity\Storage; +use Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface; use Drupal\apigee_edge_teams\Entity\TeamInterface; use Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface; use Drupal\apigee_edge_teams\Exception\InvalidArgumentException; @@ -53,6 +54,13 @@ class TeamMemberRoleStorage extends SqlContentEntityStorage implements TeamMembe */ protected $teamMembershipManager; + /** + * The organization controller service. + * + * @var \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface + */ + private $orgController; + /** * The logger. * @@ -83,11 +91,14 @@ class TeamMemberRoleStorage extends SqlContentEntityStorage implements TeamMembe * The entity type bundle info. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The entity type manager. + * @param \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface $org_controller + * The organization controller service. */ - public function __construct(EntityTypeInterface $entity_type, Connection $database, EntityFieldManagerInterface $entity_field_manager, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, MemoryCacheInterface $memory_cache, TeamMembershipManagerInterface $team_membership_manager, LoggerInterface $logger, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, EntityTypeManagerInterface $entity_type_manager = NULL) { + public function __construct(EntityTypeInterface $entity_type, Connection $database, EntityFieldManagerInterface $entity_field_manager, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, MemoryCacheInterface $memory_cache, TeamMembershipManagerInterface $team_membership_manager, LoggerInterface $logger, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, EntityTypeManagerInterface $entity_type_manager = NULL, OrganizationControllerInterface $org_controller) { parent::__construct($entity_type, $database, $entity_field_manager, $cache, $language_manager, $memory_cache, $entity_type_bundle_info, $entity_type_manager); $this->teamMembershipManager = $team_membership_manager; $this->logger = $logger; + $this->orgController = $org_controller; } /** @@ -104,7 +115,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI $container->get('apigee_edge_teams.team_membership_manager'), $container->get('logger.channel.apigee_edge_teams'), $container->get('entity_type.bundle.info'), - $container->get('entity_type.manager') + $container->get('entity_type.manager'), + $container->get('apigee_edge.controller.organization') ); } @@ -147,21 +159,30 @@ public function addTeamRoles(AccountInterface $account, TeamInterface $team, arr if ($account->isAnonymous()) { throw new InvalidArgumentException('Anonymous user can not be member of a team.'); } - try { - $developer_team_ids = $this->teamMembershipManager->getTeams($account->getEmail()); - } - catch (\Exception $e) { - $developer_team_ids = []; - } - if (!in_array($team->id(), $developer_team_ids)) { - throw new InvalidArgumentException("{$account->getEmail()} is not member of {$team->id()} team."); + // TODO : Implement this check for ApigeeX. + // DB is empty durning Team syncronization for 1st time, so $developer_team_ids + // is always empty which cause issue for member update in DB. + if (!$this->orgController->isOrganizationApigeeX()) { + try { + // Argument #2 in getTeams() is required for checking the AppGroup members and not required for Edge. + $developer_team_ids = $this->teamMembershipManager->getTeams($account->getEmail(), $team->id()); + } + catch (\Exception $e) { + $developer_team_ids = []; + } + if (!in_array($team->id(), $developer_team_ids)) { + throw new InvalidArgumentException("{$account->getEmail()} is not member of {$team->id()} team."); + } } // Indicates whether a new team member role entity had to be created // or not. /** @var \Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface $team_member_roles */ $team_member_roles = $this->loadByDeveloperAndTeam($account, $team); if ($team_member_roles === NULL) { - $team_member_roles = $this->create(['uid' => ['target_id' => $account->id()], 'team' => ['target_id' => $team->id()]]); + $team_member_roles = $this->create([ + 'uid' => ['target_id' => $account->id()], + 'team' => ['target_id' => $team->id()] + ]); } // Make sure we only store unique values in the field. $existing_roles = array_map(function ($item) { @@ -174,6 +195,17 @@ public function addTeamRoles(AccountInterface $account, TeamInterface $team, arr } try { + // Adding member roles in array for ApigeeX only if the roles has changed. + if ($this->orgController->isOrganizationApigeeX() && !empty($unique_roles)) { + // Adding the roles in AppGroup. + $updated_roles = array_map(function ($item) { + return $item = $item['target_id']; + }, $team_member_roles->roles->getValue()); + // Updating the members role in __apigee_reserved__developer_details attribute for ApigeeX. + $this->teamMembershipManager->addMembers($team->id(), [ + $account->getEmail() => $updated_roles + ]); + } $team_member_roles->save(); } catch (EntityStorageException $exception) { @@ -199,7 +231,8 @@ public function removeTeamRoles(AccountInterface $account, TeamInterface $team, throw new InvalidArgumentException('Anonymous user can not be member of a team.'); } try { - $developer_team_ids = $this->teamMembershipManager->getTeams($account->getEmail()); + // Argument #2 in getTeams() is required for checking the AppGroup members and not required for Edge. + $developer_team_ids = $this->teamMembershipManager->getTeams($account->getEmail(), $team->id()); } catch (\Exception $e) { $developer_team_ids = []; @@ -224,6 +257,17 @@ public function removeTeamRoles(AccountInterface $account, TeamInterface $team, $team_member_roles->delete(); } else { + // Adding member roles in array for ApigeeX. + if ($this->orgController->isOrganizationApigeeX()) { + // Removing the member roles in AppGroup. + $updated_roles = array_map(function ($item) { + return $item = $item['target_id']; + }, $team_member_roles->roles->getValue()); + // Updating the members role in __apigee_reserved__developer_details attribute for ApigeeX. + $this->teamMembershipManager->addMembers($team->id(), [ + $account->getEmail() => $updated_roles + ]); + } $team_member_roles->save(); } } diff --git a/modules/apigee_edge_teams/src/Entity/Team.php b/modules/apigee_edge_teams/src/Entity/Team.php index d963c314..d50a68d5 100644 --- a/modules/apigee_edge_teams/src/Entity/Team.php +++ b/modules/apigee_edge_teams/src/Entity/Team.php @@ -20,6 +20,7 @@ namespace Drupal\apigee_edge_teams\Entity; +use Apigee\Edge\Api\ApigeeX\Entity\AppGroup; use Apigee\Edge\Api\Management\Entity\Company; use Apigee\Edge\Entity\EntityInterface; use Apigee\Edge\Structure\AttributesProperty; @@ -75,9 +76,9 @@ class Team extends AttributesAwareFieldableEdgeEntityBase implements TeamInterface { /** - * The decorated company entity from the SDK. + * The decorated company/appgroup entity from the SDK. * - * @var \Apigee\Edge\Api\Management\Entity\Company + * @var \Apigee\Edge\Api\Management\Entity\Company|Apigee\Edge\Api\ApigeeX\Entity\AppGroup */ protected $decorated; @@ -106,7 +107,7 @@ public function __construct(array $values, ?string $entity_type, ?EntityInterfac * {@inheritdoc} */ protected static function decoratedClass(): string { - return Company::class; + return self::isApigeeX() ? AppGroup::class : Company::class; } /** @@ -123,7 +124,7 @@ public function id(): ?string { * {@inheritdoc} */ public static function idProperty(): string { - return Company::idProperty(); + return self::isApigeeX() ? AppGroup::idProperty() : Company::idProperty(); } /** @@ -133,6 +134,17 @@ protected function drupalEntityId(): ?string { return $this->decorated->id(); } + /** + * Checks whether the organization is Edge or ApigeeX organization. + * + * @return bool + * bool + */ + public static function isApigeeX(): bool { + $orgController = \Drupal::service('apigee_edge.controller.organization'); + return $orgController->isOrganizationApigeeX(); + } + /** * {@inheritdoc} */ @@ -266,6 +278,34 @@ public function setStatus(string $status): void { $this->decorated->setStatus($status); } + /** + * {@inheritdoc} + */ + public function getChannelUri(): ?string { + return $this->decorated->getChannelUri(); + } + + /** + * {@inheritdoc} + */ + public function setChannelUri(string $channelUri): void { + $this->decorated->setChannelUri($channelUri); + } + + /** + * {@inheritdoc} + */ + public function getChannelId(): ?string { + return $this->decorated->getChannelId(); + } + + /** + * {@inheritdoc} + */ + public function setChannelId(string $channelId): void { + $this->decorated->setChannelId($channelId); + } + /** * {@inheritdoc} */ @@ -341,7 +381,7 @@ protected static function propertyToBaseFieldBlackList(): array { // Apps only contains app names (not display names), we do not want to // expose them by default. 'apps', - // There is no need to expose the organization that the team (company) + // There is no need to expose the organization that the team (company/appgroup) // belongs. 'organization', ]); diff --git a/modules/apigee_edge_teams/src/Entity/TeamAccessHandler.php b/modules/apigee_edge_teams/src/Entity/TeamAccessHandler.php index f51335a7..14b60def 100644 --- a/modules/apigee_edge_teams/src/Entity/TeamAccessHandler.php +++ b/modules/apigee_edge_teams/src/Entity/TeamAccessHandler.php @@ -20,6 +20,7 @@ namespace Drupal\apigee_edge_teams\Entity; +use Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface; use Drupal\apigee_edge_teams\TeamMembershipManagerInterface; use Drupal\Core\Access\AccessResult; use Drupal\Core\Entity\EntityAccessControlHandler; @@ -35,6 +36,13 @@ */ final class TeamAccessHandler extends EntityAccessControlHandler implements EntityHandlerInterface { + /** + * The organization controller service. + * + * @var \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface + */ + private $orgController; + /** * The developer storage. * @@ -58,11 +66,14 @@ final class TeamAccessHandler extends EntityAccessControlHandler implements Enti * The entity type manager. * @param \Drupal\apigee_edge_teams\TeamMembershipManagerInterface $team_membership_manager * The team membership manager service. + * @param \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface $org_controller + * The organization controller service. */ - public function __construct(EntityTypeInterface $entity_type, EntityTypeManagerInterface $entity_type_manager, TeamMembershipManagerInterface $team_membership_manager) { + public function __construct(EntityTypeInterface $entity_type, EntityTypeManagerInterface $entity_type_manager, TeamMembershipManagerInterface $team_membership_manager, OrganizationControllerInterface $org_controller) { parent::__construct($entity_type); $this->developerStorage = $entity_type_manager->getStorage('developer'); $this->teamMembershipManager = $team_membership_manager; + $this->orgController = $org_controller; } /** @@ -72,7 +83,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI return new static( $entity_type, $container->get('entity_type.manager'), - $container->get('apigee_edge_teams.team_membership_manager') + $container->get('apigee_edge_teams.team_membership_manager'), + $container->get('apigee_edge.controller.organization') ); } @@ -98,7 +110,15 @@ protected function checkAccess(EntityInterface $entity, $operation, AccountInter // (Reminder, anonymous user can not be member of a team. /** @var \Drupal\apigee_edge\Entity\DeveloperInterface|null $developer */ $developer = $this->developerStorage->load($account->getEmail()); - $developer_team_ids = $developer->getCompanies(); + // Checking for ApigeeX organization. + if ($this->orgController->isOrganizationApigeeX()) { + // Argument #2 in getTeams() is required for checking the AppGroup members and not required for Edge. + $developer_team_ids = $this->teamMembershipManager->getTeams($account->getEmail(), $entity->id()); + } + else { + $developer_team_ids = $developer->getCompanies(); + } + $developer_team_access = FALSE; if ($developer && in_array($entity->id(), $developer_team_ids)) { diff --git a/modules/apigee_edge_teams/src/Entity/TeamApp.php b/modules/apigee_edge_teams/src/Entity/TeamApp.php index c623e139..ea0b896d 100644 --- a/modules/apigee_edge_teams/src/Entity/TeamApp.php +++ b/modules/apigee_edge_teams/src/Entity/TeamApp.php @@ -20,6 +20,7 @@ namespace Drupal\apigee_edge_teams\Entity; +use Apigee\Edge\Api\ApigeeX\Entity\AppGroupApp; use Apigee\Edge\Api\Management\Entity\CompanyApp; use Apigee\Edge\Entity\EntityInterface as EdgeEntityInterface; use Drupal\apigee_edge\Entity\App; @@ -87,7 +88,7 @@ class TeamApp extends App implements TeamAppInterface { /** * The decorated company app entity from the SDK. * - * @var \Apigee\Edge\Api\Management\Entity\CompanyApp + * @var \Apigee\Edge\Api\Management\Entity\CompanyApp|\Apigee\Edge\Api\ApigeeX\Entity\AppGroupApp */ protected $decorated; @@ -103,7 +104,7 @@ class TeamApp extends App implements TeamAppInterface { * The SDK entity that this Drupal entity decorates. */ public function __construct(array $values, ?string $entity_type = NULL, ?EdgeEntityInterface $decorated = NULL) { - /** @var \Apigee\Edge\Api\Management\Entity\CompanyAppInterface $decorated */ + /** @var \Apigee\Edge\Api\ApigeeX\Entity\AppGroupAppInterface|\Apigee\Edge\Api\Management\Entity\CompanyAppInterface $decorated */ $entity_type = $entity_type ?? 'team_app'; parent::__construct($values, $entity_type, $decorated); } @@ -122,14 +123,14 @@ public function id(): ?string { * {@inheritdoc} */ public function getAppOwner(): ?string { - return $this->decorated->getCompanyName(); + return $this->isApigeeX() ? $this->decorated->getAppGroup() : $this->decorated->getCompanyName(); } /** * {@inheritdoc} */ public function setAppOwner(string $owner): void { - $this->decorated->setCompanyName($owner); + $this->isApigeeX() ? $this->decorated->setAppGroup($owner) : $this->decorated->setCompanyName($owner); } /** @@ -139,18 +140,36 @@ public function getCompanyName(): ?string { return $this->decorated->getCompanyName(); } + /** + * {@inheritdoc} + */ + public function getAppGroup(): ?string { + return $this->decorated->getAppGroup(); + } + + /** + * Checks whether the organization is Edge or ApigeeX organization. + * + * @return bool + * bool + */ + public static function isApigeeX(): bool { + $orgController = \Drupal::service('apigee_edge.controller.organization'); + return $orgController->isOrganizationApigeeX(); + } + /** * {@inheritdoc} */ protected static function decoratedClass(): string { - return CompanyApp::class; + return TeamApp::isApigeeX() ? AppGroupApp::class : CompanyApp::class; } /** * {@inheritdoc} */ public static function idProperty(): string { - return CompanyApp::idProperty(); + return TeamApp::isApigeeX() ? AppGroupApp::idProperty() : CompanyApp::idProperty(); } /** @@ -174,7 +193,12 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { } // Hide readonly properties from Manage form display list. - $definitions['companyName']->setDisplayConfigurable('form', FALSE); + if (TeamApp::isApigeeX()) { + $definitions['appGroup']->setDisplayConfigurable('form', FALSE); + } + else { + $definitions['companyName']->setDisplayConfigurable('form', FALSE); + } return $definitions; } @@ -187,7 +211,7 @@ protected function urlRouteParameters($rel) { $link_templates = $this->linkTemplates(); if (isset($link_templates[$rel])) { if (strpos($link_templates[$rel], '{team}') !== FALSE) { - $params['team'] = $this->getCompanyName(); + $params['team'] = $this->isApigeeX() ? $this->getAppGroup() : $this->getCompanyName(); } if (strpos($link_templates[$rel], '{app}') !== FALSE) { $params['app'] = $this->getName(); diff --git a/modules/apigee_edge_teams/src/Entity/TeamAppAccessHandler.php b/modules/apigee_edge_teams/src/Entity/TeamAppAccessHandler.php index 0e759756..7d4643d0 100644 --- a/modules/apigee_edge_teams/src/Entity/TeamAppAccessHandler.php +++ b/modules/apigee_edge_teams/src/Entity/TeamAppAccessHandler.php @@ -20,6 +20,7 @@ namespace Drupal\apigee_edge_teams\Entity; +use Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface; use Drupal\apigee_edge_teams\TeamPermissionHandlerInterface; use Drupal\Core\Access\AccessResult; use Drupal\Core\Access\AccessResultInterface; @@ -44,6 +45,13 @@ final class TeamAppAccessHandler extends EntityAccessControlHandler implements E */ private $entityTypeManager; + /** + * The organization controller service. + * + * @var \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface + */ + private $orgController; + /** * The current route match. * @@ -69,12 +77,15 @@ final class TeamAppAccessHandler extends EntityAccessControlHandler implements E * The team permissions handler. * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The current route match. + * @param \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface $org_controller + * The organization controller service. */ - public function __construct(EntityTypeInterface $entity_type, EntityTypeManagerInterface $entity_type_manager, TeamPermissionHandlerInterface $team_permission_handler, RouteMatchInterface $route_match) { + public function __construct(EntityTypeInterface $entity_type, EntityTypeManagerInterface $entity_type_manager, TeamPermissionHandlerInterface $team_permission_handler, RouteMatchInterface $route_match, OrganizationControllerInterface $org_controller) { parent::__construct($entity_type); $this->entityTypeManager = $entity_type_manager; $this->routeMatch = $route_match; $this->teamPermissionHandler = $team_permission_handler; + $this->orgController = $org_controller; } /** @@ -85,7 +96,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI $entity_type, $container->get('entity_type.manager'), $container->get('apigee_edge_teams.team_permissions'), - $container->get('current_route_match') + $container->get('current_route_match'), + $container->get('apigee_edge.controller.organization') ); } @@ -99,8 +111,10 @@ protected function checkAccess(EntityInterface $entity, $operation, AccountInter if ($result->isNeutral()) { $result = $this->checkAccessByPermissions($account); if ($result->isNeutral()) { + // For ApigeeX get AppGroup name and for Edge Company name. + $team_name = $this->orgController->isOrganizationApigeeX() ? $entity->getAppGroup() : $entity->getCompanyName(); /** @var \Drupal\apigee_edge_teams\Entity\TeamInterface $team */ - $team = $this->entityTypeManager->getStorage('team')->load($entity->getCompanyName()); + $team = $this->entityTypeManager->getStorage('team')->load($team_name); if ($team) { // The developer is not member of the team. // @see hook_apigee_edge_teams_developer_permissions_by_team_alter() diff --git a/modules/apigee_edge_teams/src/Entity/TeamAppInterface.php b/modules/apigee_edge_teams/src/Entity/TeamAppInterface.php index 528868ad..9dd1a487 100644 --- a/modules/apigee_edge_teams/src/Entity/TeamAppInterface.php +++ b/modules/apigee_edge_teams/src/Entity/TeamAppInterface.php @@ -20,12 +20,12 @@ namespace Drupal\apigee_edge_teams\Entity; -use Apigee\Edge\Api\Management\Entity\CompanyAppInterface; +use Apigee\Edge\Api\ApigeeX\Entity\AppGroupAppInterface; use Drupal\apigee_edge\Entity\AppInterface; /** * Defines an interface for team (company app entity objects. */ -interface TeamAppInterface extends CompanyAppInterface, AppInterface { +interface TeamAppInterface extends AppGroupAppInterface, AppInterface { } diff --git a/modules/apigee_edge_teams/src/EventSubscriber/TeamInvitationSubscriber.php b/modules/apigee_edge_teams/src/EventSubscriber/TeamInvitationSubscriber.php index c7666e33..30005fae 100644 --- a/modules/apigee_edge_teams/src/EventSubscriber/TeamInvitationSubscriber.php +++ b/modules/apigee_edge_teams/src/EventSubscriber/TeamInvitationSubscriber.php @@ -20,6 +20,7 @@ namespace Drupal\apigee_edge_teams\EventSubscriber; +use Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface; use Drupal\apigee_edge_teams\Entity\TeamRole; use Drupal\apigee_edge_teams\Entity\TeamRoleInterface; use Drupal\apigee_edge_teams\Event\TeamInvitationEventInterface; @@ -71,6 +72,13 @@ class TeamInvitationSubscriber implements EventSubscriberInterface { */ protected $teamInvitationNotifier; + /** + * The organization controller service. + * + * @var \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface + */ + private $orgController; + /** * TeamInvitationSubscriber constructor. * @@ -82,13 +90,16 @@ class TeamInvitationSubscriber implements EventSubscriberInterface { * The team membership manager. * @param \Drupal\apigee_edge_teams\TeamInvitationNotifierInterface $team_invitation_notifier * The team_invitation notifier service. + * @param \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface $org_controller + * The organization controller service. */ - public function __construct(LoggerChannelInterface $logger, EntityTypeManagerInterface $entity_type_manager, TeamMembershipManagerInterface $team_membership_manager, TeamInvitationNotifierInterface $team_invitation_notifier) { + public function __construct(LoggerChannelInterface $logger, EntityTypeManagerInterface $entity_type_manager, TeamMembershipManagerInterface $team_membership_manager, TeamInvitationNotifierInterface $team_invitation_notifier, OrganizationControllerInterface $org_controller) { $this->logger = $logger; $this->teamMembershipManager = $team_membership_manager; $this->entityTypeManager = $entity_type_manager; $this->teamMemberRoleStorage = $this->entityTypeManager->getStorage('team_member_role'); $this->teamInvitationNotifier = $team_invitation_notifier; + $this->orgController = $org_controller; } /** @@ -139,9 +150,23 @@ public function onAccepted(TeamInvitationEventInterface $event) { $success = FALSE; try { - $this->teamMembershipManager->addMembers($team->id(), [ - $team_invitation->getRecipient() - ]); + $selected_roles = array_map(function (TeamRoleInterface $team_member_role) { + return $team_member_role->id(); + }, $team_invitation->getTeamRoles()); + // Adding roles to the array for ApigeeX + // So while storing the membership in __apigee_reserved__developer_details + // attribute we can store the roles as well. + if ($this->orgController->isOrganizationApigeeX()) { + $this->teamMembershipManager->addMembers($team->id(), [ + $team_invitation->getRecipient() => $selected_roles + ]); + } + else { + $this->teamMembershipManager->addMembers($team->id(), [ + $team_invitation->getRecipient() + ]); + } + $success = TRUE; } catch (\Exception $exception) { diff --git a/modules/apigee_edge_teams/src/Form/EditTeamMemberForm.php b/modules/apigee_edge_teams/src/Form/EditTeamMemberForm.php index 1f7ed9a5..e6e6ad02 100644 --- a/modules/apigee_edge_teams/src/Form/EditTeamMemberForm.php +++ b/modules/apigee_edge_teams/src/Form/EditTeamMemberForm.php @@ -60,8 +60,11 @@ public function buildForm(array $form, FormStateInterface $form_state, TeamInter else { $current_role_options = []; } + // Add TEAM_MEMBER_ROLE to current role options so it's always displayed. - $current_role_options[] = TeamRoleInterface::TEAM_MEMBER_ROLE; + if (!in_array(TeamRoleInterface::TEAM_MEMBER_ROLE, $current_role_options)) { + $current_role_options[] = TeamRoleInterface::TEAM_MEMBER_ROLE; + } $form['team_roles'] = [ '#type' => 'checkboxes', @@ -115,6 +118,11 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $removed_roles = array_diff($form['team_roles']['#default_value'], $selected_roles); $success = TRUE; + // Remove TEAM_MEMBER_ROLE to current role if present,as we dont want to delete TEAM_MEMBER_ROLE role. + if (in_array(TeamRoleInterface::TEAM_MEMBER_ROLE, $removed_roles)) { + $roles = array_search(TeamRoleInterface::TEAM_MEMBER_ROLE, $removed_roles); + unset($removed_roles[$roles]); + } try { if ($new_roles) { $this->teamMemberRoleStorage->addTeamRoles($this->developer->getOwner(), $this->team, $new_roles); @@ -133,7 +141,6 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $context += Error::decodeException($exception); $logger->error('Failed to modify %developer developer roles in %team_id team. @message %function (line %line of %file).
@backtrace_string
', $context); } - if ($success) { $this->messenger()->addStatus($this->t('Changes successfully saved.')); } diff --git a/modules/apigee_edge_teams/src/Form/TeamAliasForm.php b/modules/apigee_edge_teams/src/Form/TeamAliasForm.php index 83c5bc62..97d392a8 100644 --- a/modules/apigee_edge_teams/src/Form/TeamAliasForm.php +++ b/modules/apigee_edge_teams/src/Form/TeamAliasForm.php @@ -21,6 +21,7 @@ namespace Drupal\apigee_edge_teams\Form; use Drupal\apigee_edge\Form\EdgeEntityAliasConfigFormBase; +use Drupal\Core\Form\FormStateInterface; /** * Provides a form for changing Team aliases. @@ -34,6 +35,87 @@ public function getFormId() { return 'apigee_edge_teams_team_alias_form'; } + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + $config = $this->config($this->getConfigNameWithLabels()); + + $form['team_label'] = [ + '#type' => 'fieldset', + '#title' => $this->t('Team settings'), + '#collapsible' => FALSE, + ]; + + $form['team_label']['team_prefix'] = [ + '#type' => 'textfield', + '#title' => $this->t('Prefix to add for the Team name'), + '#default_value' => $config->get('team_prefix'), + '#description' => $this->t('Example: "int-" or leave empty for no prefix.'), + ]; + + $org_controller = \Drupal::service('apigee_edge.controller.organization'); + if ($org_controller->isOrganizationApigeeX()) { + $form['channel_label'] = [ + '#type' => 'fieldset', + '#title' => $this->t('Channel settings'), + '#collapsible' => FALSE, + ]; + + $form['channel_label']['channelid'] = [ + '#type' => 'textfield', + '#title' => $this->t('Channel ID'), + '#default_value' => $config->get('channelid'), + '#description' => $this->t('Leave empty to use the default "@channelid" as channel ID.', ['@channelid' => $this->originalChannelId()]), + ]; + } + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state) { + parent::validateForm($form, $form_state); + $pattern = '/^[a-z0-9_-]+$/'; + $team_prefix = $form_state->getValue('team_prefix'); + $channelid = $form_state->getValue('channelid'); + + if (!empty($team_prefix) && !preg_match($pattern, $team_prefix)) { + $form_state->setError($form['team_label']['team_prefix'], $this->t('Team prefix name must contain only lowercase letters, numbers, hyphen or the underscore character.')); + return; + } + if (!empty($channelid) && !preg_match($pattern, $channelid)) { + $form_state->setError($form['channel_label']['channelid'], $this->t('Channel ID must contain only lowercase letters, numbers, hyphen or the underscore character.')); + return; + } + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $config = $this->config($this->getConfigNameWithLabels()); + + if ($config->get('team_prefix') !== $form_state->getValue('team_prefix') || $config->get('channelid') !== $form_state->getValue('channelid')) { + $config->set('team_prefix', $form_state->getValue('team_prefix')) + ->set('channelid', $form_state->getValue('channelid')) + ->save(); + } + + parent::submitForm($form, $form_state); + } + + /** + * Returns the default value for Channel ID for ApigeeX. + * + * @return string + * default channel ID value. + */ + public static function originalChannelId(): string { + return t('devportal'); + } + /** * {@inheritdoc} */ diff --git a/modules/apigee_edge_teams/src/Form/TeamMemberSyncForm.php b/modules/apigee_edge_teams/src/Form/TeamMemberSyncForm.php index 33e99cb6..d6883e92 100644 --- a/modules/apigee_edge_teams/src/Form/TeamMemberSyncForm.php +++ b/modules/apigee_edge_teams/src/Form/TeamMemberSyncForm.php @@ -19,6 +19,7 @@ namespace Drupal\apigee_edge_teams\Form; +use Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface; use Drupal\apigee_edge\SDKConnectorInterface; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; @@ -37,14 +38,24 @@ class TeamMemberSyncForm extends FormBase { */ protected $sdkConnector; + /** + * The organization controller service. + * + * @var \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface + */ + private $orgController; + /** * Constructs a new TeamMemberSyncForm. * * @param \Drupal\apigee_edge\SDKConnectorInterface $sdk_connector * SDK connector service. + * @param \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface $org_controller + * The organization controller service. */ - public function __construct(SDKConnectorInterface $sdk_connector) { + public function __construct(SDKConnectorInterface $sdk_connector, OrganizationControllerInterface $org_controller) { $this->sdkConnector = $sdk_connector; + $this->orgController = $org_controller; } /** @@ -52,7 +63,8 @@ public function __construct(SDKConnectorInterface $sdk_connector) { */ public static function create(ContainerInterface $container) { return new static( - $container->get('apigee_edge.sdk_connector') + $container->get('apigee_edge.sdk_connector'), + $container->get('apigee_edge.controller.organization') ); } @@ -110,6 +122,22 @@ public function buildForm(array $form, FormStateInterface $form_state) { ], ]; + // Displaying this message only for ApigeeX. + if ($this->orgController->isOrganizationApigeeX()) { + $form['sync']['description']['list'] = [ + '#theme' => 'item_list', + '#items' => [ + $this->t('Caches team members in Drupal'), + $this->t('Migrate the members information from Apigee X to Drupal portal database.'), + ], + ]; + $form['sync']['description']['p4'] = [ + '#type' => 'html_tag', + '#tag' => 'p', + '#value' => $this->t('Note: First, execute the Developer sync to add all the developers from ApigeeX to Drupal portal, and then proceed to add the required member roles. Finally, run the Team member sync. ', [':developer_sync' => Url::fromRoute('apigee_edge.settings.developer.sync')->toString(), ':developer_roles' => Url::fromRoute('entity.team_role.collection')->toString()]), + ]; + } + $form['sync']['sync_submit'] = [ '#title' => $this->t('Run team member sync'), '#type' => 'link', diff --git a/modules/apigee_edge_teams/src/Job/TeamMemberCreateUpdate.php b/modules/apigee_edge_teams/src/Job/TeamMemberCreateUpdate.php index 29d33331..3075f726 100644 --- a/modules/apigee_edge_teams/src/Job/TeamMemberCreateUpdate.php +++ b/modules/apigee_edge_teams/src/Job/TeamMemberCreateUpdate.php @@ -49,8 +49,15 @@ public function __construct(string $team_ids) { * {@inheritdoc} */ protected function executeRequest() { + $orgController = \Drupal::service('apigee_edge.controller.organization'); $member_controller = \Drupal::service('apigee_edge_teams.team_membership_manager'); - $team_members = $member_controller->getMembers($this->team_ids); + + if ($orgController->isOrganizationApigeeX()) { + $team_members = $member_controller->syncAppGroupMembers($this->team_ids); + } + else { + $team_members = $member_controller->getMembers($this->team_ids); + } } } diff --git a/modules/apigee_edge_teams/src/TeamMemberApiProductAccessHandler.php b/modules/apigee_edge_teams/src/TeamMemberApiProductAccessHandler.php index 22e27489..f42cf6d3 100644 --- a/modules/apigee_edge_teams/src/TeamMemberApiProductAccessHandler.php +++ b/modules/apigee_edge_teams/src/TeamMemberApiProductAccessHandler.php @@ -107,7 +107,8 @@ public function access(ApiProductInterface $api_product, string $operation, Team } else { try { - $developer_team_ids = $this->teamMembershipManager->getTeams($account->getEmail()); + // Argument #2 in getTeams() is required for checking the AppGroup members and not required for Edge. + $developer_team_ids = $this->teamMembershipManager->getTeams($account->getEmail(), $team->id()); } catch (\Exception $e) { $developer_team_ids = []; diff --git a/modules/apigee_edge_teams/src/TeamMembershipManager.php b/modules/apigee_edge_teams/src/TeamMembershipManager.php index fa716f18..54c5c889 100644 --- a/modules/apigee_edge_teams/src/TeamMembershipManager.php +++ b/modules/apigee_edge_teams/src/TeamMembershipManager.php @@ -20,19 +20,23 @@ namespace Drupal\apigee_edge_teams; +use Apigee\Edge\Api\ApigeeX\Structure\AppGroupMembership; use Apigee\Edge\Api\Management\Structure\CompanyMembership; use Drupal\apigee_edge\Entity\Controller\DeveloperControllerInterface; use Drupal\apigee_edge\Entity\Controller\EntityCacheAwareControllerInterface; +use Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface; use Drupal\apigee_edge\Entity\DeveloperCompaniesCacheInterface; use Drupal\apigee_edge\Exception\DeveloperDoesNotExistException; +use Drupal\apigee_edge_teams\Entity\Form\TeamForm; use Drupal\Core\Cache\CacheTagsInvalidatorInterface; use Drupal\Core\Entity\EntityStorageException; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Session\AccountInterface; use Drupal\user\UserInterface; use Psr\Log\LoggerInterface; /** - * Service that makes easier to work with company (team) memberships. + * Service that makes easier to work with company/appgroup (team) memberships. * * It also handles cache invalidation. */ @@ -45,6 +49,13 @@ final class TeamMembershipManager implements TeamMembershipManagerInterface { */ private $companyMembersControllerFactory; + /** + * The appgroup members controller factory service. + * + * @var \Drupal\apigee_edge_teams\AppGroupMembersControllerFactoryInterface + */ + private $appGroupMembersControllerFactory; + /** * The developer companies cache. * @@ -80,6 +91,13 @@ final class TeamMembershipManager implements TeamMembershipManagerInterface { */ private $logger; + /** + * The organization controller service. + * + * @var \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface + */ + private $orgController; + /** * TeamMembershipManager constructor. * @@ -87,6 +105,8 @@ final class TeamMembershipManager implements TeamMembershipManagerInterface { * The entity type manager service. * @param \Drupal\apigee_edge_teams\CompanyMembersControllerFactoryInterface $company_members_controller_factory * The company members controller factory service. + * @param \Drupal\apigee_edge_teams\AppGroupMembersControllerFactoryInterface $appgroup_members_controller_factory + * The company members controller factory service. * @param \Drupal\apigee_edge\Entity\Controller\DeveloperControllerInterface $developer_controller * The developer controller service. * @param \Drupal\apigee_edge\Entity\DeveloperCompaniesCacheInterface $developer_companies_cache @@ -95,21 +115,52 @@ final class TeamMembershipManager implements TeamMembershipManagerInterface { * The cache tags invalidator service. * @param \Psr\Log\LoggerInterface $logger * The logger. + * @param \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface $org_controller + * The organization controller service. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager, CompanyMembersControllerFactoryInterface $company_members_controller_factory, DeveloperControllerInterface $developer_controller, DeveloperCompaniesCacheInterface $developer_companies_cache, CacheTagsInvalidatorInterface $cache_tags_invalidator, LoggerInterface $logger) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, CompanyMembersControllerFactoryInterface $company_members_controller_factory, AppGroupMembersControllerFactoryInterface $appgroup_members_controller_factory, DeveloperControllerInterface $developer_controller, DeveloperCompaniesCacheInterface $developer_companies_cache, CacheTagsInvalidatorInterface $cache_tags_invalidator, LoggerInterface $logger, OrganizationControllerInterface $org_controller) { $this->entityTypeManager = $entity_type_manager; $this->companyMembersControllerFactory = $company_members_controller_factory; + $this->appGroupMembersControllerFactory = $appgroup_members_controller_factory; $this->developerController = $developer_controller; $this->developerCompaniesCache = $developer_companies_cache; $this->cacheTagsInvalidator = $cache_tags_invalidator; $this->logger = $logger; + $this->orgController = $org_controller; + } + + /** + * {@inheritdoc} + */ + public function syncAppGroupMembers(string $team): array { + $controller = $this->appGroupMembersControllerFactory->appGroupMembersController($team); + $members = $controller->syncAppGroupMembers(); + return array_keys($members->getMembers()); } /** * {@inheritdoc} */ public function getMembers(string $team): array { - $controller = $this->companyMembersControllerFactory->companyMembersController($team); + // Checking for ApigeeX organization. + if ($this->orgController->isOrganizationApigeeX()) { + return $this->getAppGroupMembers($team); + } + else { + $controller = $this->companyMembersControllerFactory->companyMembersController($team); + $members = $controller->getMembers(); + return array_keys($members->getMembers()); + } + } + + /** + * Get the AppGroup ApigeeX members email ID and roles. + * + * @param string $team + * Name of a team. + */ + private function getAppGroupMembers(string $team): array { + $controller = $this->appGroupMembersControllerFactory->appGroupMembersController($team); $members = $controller->getMembers(); return array_keys($members->getMembers()); } @@ -118,19 +169,48 @@ public function getMembers(string $team): array { * {@inheritdoc} */ public function addMembers(string $team, array $developers): void { - $membership = new CompanyMembership(array_map(function ($item) { - return NULL; - }, array_flip($developers))); - $controller = $this->companyMembersControllerFactory->companyMembersController($team); - $controller->setMembers($membership); - $this->invalidateCaches($team, $developers); + // Checking for ApigeeX organization. + if ($this->orgController->isOrganizationApigeeX()) { + $this->addAppGroupMembers($team, $developers); + } + else { + $membership = new CompanyMembership(array_map(function ($item) { + return NULL; + }, array_flip($developers))); + $controller = $this->companyMembersControllerFactory->companyMembersController($team); + $controller->setMembers($membership); + $this->invalidateCaches($team, $developers); + } + } + + /** + * Add the AppGroup ApigeeX members email ID and roles. + * + * @param string $team + * Name of a team. + * @param array $developers + * Array of developer email addresses. + */ + private function addAppGroupMembers(string $team, array $developers): void { + $appGroupMembership = new AppGroupMembership($developers); + $controller = $this->appGroupMembersControllerFactory->appGroupMembersController($team); + $controller->setMembers($appGroupMembership); + + $membership = new AppGroupMembership(array_flip(array_keys($developers))); + $this->invalidateCaches($team, $membership->getMembers()); } /** * {@inheritdoc} */ public function removeMembers(string $team, array $developers): void { - $controller = $this->companyMembersControllerFactory->companyMembersController($team); + // Checking for ApigeeX organization. + if ($this->orgController->isOrganizationApigeeX()) { + $controller = $this->appGroupMembersControllerFactory->appGroupMembersController($team); + } + else { + $controller = $this->companyMembersControllerFactory->companyMembersController($team); + } /** @var \Drupal\apigee_edge_teams\Entity\Storage\TeamMemberRoleStorageInterface $team_member_role_storage */ $team_member_role_storage = $this->entityTypeManager->getStorage('team_member_role'); /** @var \Drupal\user\UserInterface[] $users_by_mail */ @@ -138,6 +218,7 @@ public function removeMembers(string $team, array $developers): void { $carry[$user->getEmail()] = $user; return $carry; }, []); + foreach ($developers as $developer) { $controller->removeMember($developer); // Remove team member's roles from Drupal. @@ -145,7 +226,6 @@ public function removeMembers(string $team, array $developers): void { /** @var \Drupal\user\Entity\User $account */ $account = user_load_by_mail($users_by_mail[$developer]->getEmail()); $team_entity = $this->entityTypeManager->getStorage('team')->load($team); - /** @var \Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface[] $team_member_roles_in_team */ $team_member_roles_in_team = $team_member_role_storage->loadByDeveloperAndTeam($account, $team_entity); try { @@ -167,16 +247,30 @@ public function removeMembers(string $team, array $developers): void { /** * {@inheritdoc} */ - public function getTeams(string $developer): array { + public function getTeams(string $developer, string $team = NULL): array { /** @var \Drupal\apigee_edge\Entity\DeveloperInterface $entity */ $entity = $this->entityTypeManager->getStorage('developer')->load($developer); if ($entity === NULL) { throw new DeveloperDoesNotExistException($developer); } - // Developer entity's getCompanies() method should return the list of - // companies where the developer is member. - // @see \Drupal\apigee_edge\Entity\Developer::getCompanies() - return $entity->getCompanies(); + // Checking for ApigeeX organization. + if ($this->orgController->isOrganizationApigeeX()) { + // If team not available, this could happen when switching + // the Org and if another Orgs team exist in database. + if ($team !== NULL) { + // List developer email ids for a particular team. + $members = $this->getAppGroupMembers($team); + // Return the AppGroups/teams where the developer is a member. + return in_array($developer, $members) ? [$team] : []; + } + return []; + } + else { + // Developer entity's getCompanies() method should return the list of + // companies where the developer is member. + // @see \Drupal\apigee_edge\Entity\Developer::getCompanies() + return $entity->getCompanies(); + } } /** diff --git a/modules/apigee_edge_teams/src/TeamMembershipManagerInterface.php b/modules/apigee_edge_teams/src/TeamMembershipManagerInterface.php index c65aa278..e1958903 100644 --- a/modules/apigee_edge_teams/src/TeamMembershipManagerInterface.php +++ b/modules/apigee_edge_teams/src/TeamMembershipManagerInterface.php @@ -40,6 +40,17 @@ interface TeamMembershipManagerInterface { */ public function getMembers(string $team): array; + /** + * Sync the team members details from ApigeeX and returns members of a team. + * + * @param string $team + * Name of a team. + * + * @return string[] + * Array of developer email addresses. + */ + public function syncAppGroupMembers(string $team): array; + /** * Adds members to a team. * @@ -65,6 +76,8 @@ public function removeMembers(string $team, array $developers): void; * * @param string $developer * Developer email address. + * @param string|null $team + * Name of a team. * * @return string[] * Array of team names. @@ -72,6 +85,6 @@ public function removeMembers(string $team, array $developers): void; * @throws \Drupal\apigee_edge\Exception\DeveloperDoesNotExistException * If developer not found with id. */ - public function getTeams(string $developer): array; + public function getTeams(string $developer, ?string $team = NULL): array; } diff --git a/modules/apigee_edge_teams/src/TeamPermissionHandler.php b/modules/apigee_edge_teams/src/TeamPermissionHandler.php index f963fe0c..5ab2d36e 100644 --- a/modules/apigee_edge_teams/src/TeamPermissionHandler.php +++ b/modules/apigee_edge_teams/src/TeamPermissionHandler.php @@ -151,7 +151,8 @@ public function getDeveloperPermissionsByTeam(TeamInterface $team, AccountInterf $developer_team_access = FALSE; $permissions = []; try { - $developer_team_ids = $this->teamMembershipManager->getTeams($account->getEmail()); + // Argument #2 in getTeams() is required for checking the AppGroup members and not required for Edge. + $developer_team_ids = $this->teamMembershipManager->getTeams($account->getEmail(), $team->id()); } catch (\Exception $e) { $developer_team_ids = []; diff --git a/modules/apigee_edge_teams/tests/src/Kernel/Event/TeamInvitationEventsTest.php b/modules/apigee_edge_teams/tests/src/Kernel/Event/TeamInvitationEventsTest.php index e343552d..62435316 100644 --- a/modules/apigee_edge_teams/tests/src/Kernel/Event/TeamInvitationEventsTest.php +++ b/modules/apigee_edge_teams/tests/src/Kernel/Event/TeamInvitationEventsTest.php @@ -71,6 +71,8 @@ protected function setUp(): void { $this->installSchema('user', ['users_data']); $this->baseSetUp(); + + $this->addOrganizationMatchedResponse(); } /** diff --git a/src/Entity/App.php b/src/Entity/App.php index 60c5898a..c11eb578 100644 --- a/src/Entity/App.php +++ b/src/Entity/App.php @@ -72,7 +72,10 @@ public function deleteAttribute(string $name): void { * {@inheritdoc} */ public function getAppFamily(): string { - return $this->decorated->getAppFamily(); + return method_exists($this->decorated, 'getAppFamily') ? + /* @phpstan-ignore-next-line */ + $this->decorated->getAppFamily() : + ''; } /** @@ -136,8 +139,9 @@ public function getCredentials(): array { // App has not found in cache, we have to load it from Apigee Edge. /** @var \Drupal\apigee_edge\Entity\Controller\AppControllerInterface $app_controller */ $app_controller = \Drupal::service('apigee_edge.controller.app'); + $orgController = \Drupal::service('apigee_edge.controller.organization'); try { - $app = $app_controller->loadApp($this->getAppId()); + $app = $orgController->isOrganizationApigeeX() ? $app_controller->loadAppGroup($this->getAppId()) : $app_controller->loadApp($this->getAppId()); } catch (ApiException $e) { // Just catch it and leave app to be NULL. diff --git a/src/Entity/Controller/AppController.php b/src/Entity/Controller/AppController.php index 608722a7..e7c546ff 100644 --- a/src/Entity/Controller/AppController.php +++ b/src/Entity/Controller/AppController.php @@ -20,6 +20,8 @@ namespace Drupal\apigee_edge\Entity\Controller; +use Apigee\Edge\Api\ApigeeX\Controller\AppController as AppGroupController; +use Apigee\Edge\Api\ApigeeX\Controller\AppControllerInterface as EdgeAppGroupControllerInterface; use Apigee\Edge\Api\Management\Controller\AppController as EdgeAppController; use Apigee\Edge\Api\Management\Controller\AppControllerInterface as EdgeAppControllerInterface; use Apigee\Edge\Api\Management\Entity\AppInterface; @@ -89,9 +91,15 @@ public function __construct(SDKConnectorInterface $connector, OrganizationContro * @return \Apigee\Edge\Api\Management\Controller\AppControllerInterface * The initialized app controller. */ - protected function decorated(): EdgeAppControllerInterface { + protected function decorated(): EdgeAppControllerInterface|EdgeAppGroupControllerInterface { if ($this->instance === NULL) { - $this->instance = new EdgeAppController($this->connector->getOrganization(), $this->connector->getClient(), NULL, $this->organizationController); + // Checking if the Organisation is ApigeeX. + if ($this->organizationController->isOrganizationApigeeX()) { + $this->instance = new AppGroupController($this->connector->getOrganization(), $this->connector->getClient(), NULL, $this->organizationController); + } + else { + $this->instance = new EdgeAppController($this->connector->getOrganization(), $this->connector->getClient(), NULL, $this->organizationController); + } } return $this->instance; } @@ -108,6 +116,18 @@ public function loadApp(string $app_id): AppInterface { return $app; } + /** + * {@inheritdoc} + */ + public function loadAppGroup(string $app_id): AppInterface { + $app = $this->appCache->getEntity($app_id); + if ($app === NULL) { + $app = $this->decorated()->loadAppGroup($app_id); + $this->appCache->saveEntities([$app]); + } + return $app; + } + /** * {@inheritdoc} */ diff --git a/src/Entity/Controller/Cache/AppCache.php b/src/Entity/Controller/Cache/AppCache.php index fa9fc2c1..27406310 100644 --- a/src/Entity/Controller/Cache/AppCache.php +++ b/src/Entity/Controller/Cache/AppCache.php @@ -20,6 +20,7 @@ namespace Drupal\apigee_edge\Entity\Controller\Cache; +use Apigee\Edge\Api\ApigeeX\Entity\AppGroupAppInterface; use Apigee\Edge\Api\Management\Entity\AppInterface; use Apigee\Edge\Api\Management\Entity\CompanyAppInterface; use Apigee\Edge\Api\Management\Entity\DeveloperAppInterface; @@ -86,6 +87,9 @@ public function getAppOwner(AppInterface $app): string { elseif ($app instanceof CompanyAppInterface) { return $app->getCompanyName(); } + elseif ($app instanceof AppGroupAppInterface) { + return $app->getAppGroup(); + } throw new RuntimeException('Unable to identify app owner.'); } diff --git a/src/Entity/Controller/DeveloperAppEdgeEntityControllerProxy.php b/src/Entity/Controller/DeveloperAppEdgeEntityControllerProxy.php index e9d533ae..a2198097 100644 --- a/src/Entity/Controller/DeveloperAppEdgeEntityControllerProxy.php +++ b/src/Entity/Controller/DeveloperAppEdgeEntityControllerProxy.php @@ -23,6 +23,7 @@ use Apigee\Edge\Api\Management\Entity\AppInterface; use Apigee\Edge\Api\Management\Entity\DeveloperAppInterface; use Apigee\Edge\Entity\EntityInterface; +use Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface; use Drupal\apigee_edge\Exception\RuntimeException; /** @@ -47,6 +48,14 @@ final class DeveloperAppEdgeEntityControllerProxy implements EdgeEntityControlle */ private $appController; + + /** + * The organization controller service. + * + * @var \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface + */ + private $orgController; + /** * DeveloperAppEntityControllerProxy constructor. * @@ -54,10 +63,13 @@ final class DeveloperAppEdgeEntityControllerProxy implements EdgeEntityControlle * The developer app controller factory service. * @param \Drupal\apigee_edge\Entity\Controller\AppControllerInterface $app_controller * The app controller service. + * @param \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface $org_controller + * The organization controller service. */ - public function __construct(DeveloperAppControllerFactoryInterface $developer_app_controller_factory, AppControllerInterface $app_controller) { + public function __construct(DeveloperAppControllerFactoryInterface $developer_app_controller_factory, AppControllerInterface $app_controller, OrganizationControllerInterface $org_controller) { $this->devAppControllerFactory = $developer_app_controller_factory; $this->appController = $app_controller; + $this->orgController = $org_controller; } /** @@ -77,7 +89,8 @@ public function create(EntityInterface $entity): void { * {@inheritdoc} */ public function load(string $id): EntityInterface { - return $this->appController->loadApp($id); + $app = $this->orgController->isOrganizationApigeeX() ? $this->appController->loadAppGroup($id) : $this->appController->loadApp($id); + return $app; } /** diff --git a/src/Entity/Controller/OrganizationController.php b/src/Entity/Controller/OrganizationController.php index d98d1d72..8203b30b 100644 --- a/src/Entity/Controller/OrganizationController.php +++ b/src/Entity/Controller/OrganizationController.php @@ -135,4 +135,20 @@ public function getEntities(): array { } } + /** + * Checks whether the organization is Edge or ApigeeX organization. + * + * @return bool + * TRUE if the value of the property is "true", false otherwise. + */ + public function isOrganizationApigeeX(): bool { + try { + $this->organization = $this->load($this->connector->getOrganization()); + return ($this->organization && ('CLOUD' === $this->organization->getRuntimeType() || 'HYBRID' === $this->organization->getRuntimeType())); + } + catch (\Exception $e) { + return FALSE; + } + } + } diff --git a/src/Entity/Developer.php b/src/Entity/Developer.php index 9d7cb9f3..acbb0b0b 100644 --- a/src/Entity/Developer.php +++ b/src/Entity/Developer.php @@ -25,7 +25,10 @@ use Apigee\Edge\Exception\ApiException; use Apigee\Edge\Structure\AttributesProperty; use Drupal\apigee_edge\Entity\Controller\EntityCacheAwareControllerInterface; +use Drupal\apigee_edge_teams\Entity\TeamInterface; +use Drupal\apigee_edge_teams\Entity\TeamMemberRole; use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\Core\Session\AccountInterface; use Drupal\Core\Utility\Error; use Drupal\user\Entity\User; use Drupal\user\UserInterface; diff --git a/src/Entity/Storage/DeveloperAppStorage.php b/src/Entity/Storage/DeveloperAppStorage.php index 0eb513e4..62e63416 100644 --- a/src/Entity/Storage/DeveloperAppStorage.php +++ b/src/Entity/Storage/DeveloperAppStorage.php @@ -25,6 +25,7 @@ use Drupal\apigee_edge\Entity\Controller\DeveloperAppControllerFactoryInterface; use Drupal\apigee_edge\Entity\Controller\DeveloperAppEdgeEntityControllerProxy; use Drupal\apigee_edge\Entity\Controller\EdgeEntityControllerInterface; +use Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface; use Drupal\Component\Datetime\TimeInterface; use Drupal\Component\Utility\EmailValidatorInterface; use Drupal\Core\Cache\CacheBackendInterface; @@ -71,10 +72,12 @@ class DeveloperAppStorage extends AppStorage implements DeveloperAppStorageInter * Configuration factory. * @param \Drupal\Component\Utility\EmailValidatorInterface $email_validator * The email validator service. + * @param \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface $org_controller + * The organization controller service. */ - public function __construct(EntityTypeInterface $entity_type, CacheBackendInterface $cache_backend, MemoryCacheInterface $memory_cache, TimeInterface $system_time, DeveloperAppControllerFactoryInterface $developer_app_controller_factory, AppControllerInterface $app_controller, ConfigFactoryInterface $config, EmailValidatorInterface $email_validator) { + public function __construct(EntityTypeInterface $entity_type, CacheBackendInterface $cache_backend, MemoryCacheInterface $memory_cache, TimeInterface $system_time, DeveloperAppControllerFactoryInterface $developer_app_controller_factory, AppControllerInterface $app_controller, ConfigFactoryInterface $config, EmailValidatorInterface $email_validator, OrganizationControllerInterface $org_controller) { parent::__construct($entity_type, $cache_backend, $memory_cache, $system_time, $app_controller); - $this->appEntityController = new DeveloperAppEdgeEntityControllerProxy($developer_app_controller_factory, $app_controller); + $this->appEntityController = new DeveloperAppEdgeEntityControllerProxy($developer_app_controller_factory, $app_controller, $org_controller); $this->cacheExpiration = $config->get('apigee_edge.developer_app_settings')->get('cache_expiration'); $this->emailValidator = $email_validator; } @@ -91,7 +94,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI $container->get('apigee_edge.controller.developer_app_controller_factory'), $container->get('apigee_edge.controller.app'), $container->get('config.factory'), - $container->get('email.validator') + $container->get('email.validator'), + $container->get('apigee_edge.controller.organization') ); } diff --git a/src/SDKConnector.php b/src/SDKConnector.php index df8282ca..23b16fbc 100644 --- a/src/SDKConnector.php +++ b/src/SDKConnector.php @@ -24,6 +24,7 @@ use Apigee\Edge\ClientInterface; use Apigee\Edge\HttpClient\Utility\Builder; use Drupal\apigee_edge\Connector\HybridCredentials; +use Drupal\apigee_edge\Entity\Controller\OrganizationController as EdgeOrganizationController; use Drupal\apigee_edge\Exception\AuthenticationKeyException; use Drupal\apigee_edge\Exception\AuthenticationKeyNotFoundException; use Drupal\apigee_edge\Exception\InvalidArgumentException; diff --git a/src/SDKConnectorInterface.php b/src/SDKConnectorInterface.php index 61e2fadf..081f250c 100644 --- a/src/SDKConnectorInterface.php +++ b/src/SDKConnectorInterface.php @@ -20,6 +20,7 @@ namespace Drupal\apigee_edge; use Apigee\Edge\ClientInterface; +use Drupal\apigee_edge\Entity\Controller\OrganizationController; use Drupal\key\KeyInterface; use Http\Message\Authentication; From 5391b819a28f149d7ea0087a844000d28c213cf6 Mon Sep 17 00:00:00 2001 From: Shishir <75600200+shishir-intelli@users.noreply.github.com> Date: Thu, 29 Jun 2023 16:26:17 +0530 Subject: [PATCH 22/27] Bump apigee-client-php version requirement to 2.1.0 for AppGroup (#875) --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2a389e2f..1d6a09f5 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "require": { "php": "~8.0.0 || ~8.1.0", "ext-json": "*", - "apigee/apigee-client-php": "^2.0.19", + "apigee/apigee-client-php": "^2.1.0", "drupal/core": "^9.4", "drupal/entity": "^1.0", "drupal/key": "^1.8", From adcd4cf5aa4cf60f8c093834f9dc6ed7eb7a0754 Mon Sep 17 00:00:00 2001 From: Shishir <75600200+shishir-intelli@users.noreply.github.com> Date: Tue, 11 Jul 2023 19:02:21 +0530 Subject: [PATCH 23/27] JsonAPI requires UUID for getting the entity information (#879) * Json API requires UUID for getting the entity information --- src/Entity/ApiProduct.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Entity/ApiProduct.php b/src/Entity/ApiProduct.php index 411846a0..01d7d0ce 100644 --- a/src/Entity/ApiProduct.php +++ b/src/Entity/ApiProduct.php @@ -78,6 +78,15 @@ public function id(): ?string { return parent::id(); } + /** + * {@inheritdoc} + * + * We are sending id as uuid for getting api products while using JSONAPI. + */ + public function uuid(): ?string { + return $this->id(); + } + /** * {@inheritdoc} */ From 639e6a3e5683317c173715a5b30a3a7d01b2c192 Mon Sep 17 00:00:00 2001 From: Shishir <75600200+shishir-intelli@users.noreply.github.com> Date: Fri, 14 Jul 2023 12:31:32 +0530 Subject: [PATCH 24/27] Added Cancel button and removed delete button for Edit Team App (#883) --- .../src/Entity/Form/TeamAppEditForm.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/modules/apigee_edge_teams/src/Entity/Form/TeamAppEditForm.php b/modules/apigee_edge_teams/src/Entity/Form/TeamAppEditForm.php index 6ec896bb..ac6202d9 100644 --- a/modules/apigee_edge_teams/src/Entity/Form/TeamAppEditForm.php +++ b/modules/apigee_edge_teams/src/Entity/Form/TeamAppEditForm.php @@ -105,6 +105,23 @@ public function form(array $form, FormStateInterface $form_state) { return $form; } + /** + * {@inheritdoc} + */ + protected function actions(array $form, FormStateInterface $form_state) { + $actions = parent::actions($form, $form_state); + // Hide the Delete button. + $actions['delete']['#access'] = FALSE; + // Cancel button to redirect the user to team app listing page. + $actions['cancel'] = array ( + '#type' => 'link', + '#title' => $this->t('Cancel'), + '#attributes' => ['class' => ['btn btn-outline-primary']], + '#url' => $this->entity->toUrl('collection-by-team'), + ); + return $actions; + } + /** * {@inheritdoc} */ From 2c5ca068be78721b197969bd5d9d6cbf51e96f23 Mon Sep 17 00:00:00 2001 From: Shishir <75600200+shishir-intelli@users.noreply.github.com> Date: Fri, 14 Jul 2023 22:45:36 +0530 Subject: [PATCH 25/27] Expiry date hence changed to now and developer renamed to members (#884) --- apigee_edge.module | 4 ++-- modules/apigee_edge_teams/src/Entity/Form/TeamAppEditForm.php | 4 ++-- modules/apigee_edge_teams/src/Form/AddTeamMembersForm.php | 4 ++-- tests/src/Functional/DeveloperAppUITest.php | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apigee_edge.module b/apigee_edge.module index 1b3d4c2f..43f7f630 100644 --- a/apigee_edge.module +++ b/apigee_edge.module @@ -1186,11 +1186,11 @@ function template_preprocess_app_credential(array &$variables) { /** @var \DateTimeInterface $value */ if ($value !== -1) { $time_diff = \Drupal::time()->getRequestTime() - intval($value / 1000); - if ($time_diff > 0) { + if ($time_diff >= 0) { $value = t('@time ago', ['@time' => $dateFormatter->formatTimeDiffSince(intval($value / 1000))]); } else { - $value = t('@time hence', ['@time' => $dateFormatter->formatTimeDiffUntil(intval($value / 1000))]); + $value = t('@time from now', ['@time' => $dateFormatter->formatTimeDiffUntil(intval($value / 1000))]); } } else { diff --git a/modules/apigee_edge_teams/src/Entity/Form/TeamAppEditForm.php b/modules/apigee_edge_teams/src/Entity/Form/TeamAppEditForm.php index ac6202d9..128a3432 100644 --- a/modules/apigee_edge_teams/src/Entity/Form/TeamAppEditForm.php +++ b/modules/apigee_edge_teams/src/Entity/Form/TeamAppEditForm.php @@ -113,12 +113,12 @@ protected function actions(array $form, FormStateInterface $form_state) { // Hide the Delete button. $actions['delete']['#access'] = FALSE; // Cancel button to redirect the user to team app listing page. - $actions['cancel'] = array ( + $actions['cancel'] = [ '#type' => 'link', '#title' => $this->t('Cancel'), '#attributes' => ['class' => ['btn btn-outline-primary']], '#url' => $this->entity->toUrl('collection-by-team'), - ); + ]; return $actions; } diff --git a/modules/apigee_edge_teams/src/Form/AddTeamMembersForm.php b/modules/apigee_edge_teams/src/Form/AddTeamMembersForm.php index 6f2b317d..684d7490 100644 --- a/modules/apigee_edge_teams/src/Form/AddTeamMembersForm.php +++ b/modules/apigee_edge_teams/src/Form/AddTeamMembersForm.php @@ -95,8 +95,8 @@ public function buildForm(array $form, FormStateInterface $form_state, TeamInter $role_options = $this->getRoleOptions(); $form['developers'] = [ - '#title' => $this->t('Developers'), - '#description' => $this->t('Enter the email of one or more developers to invite them to the @team, separated by comma.', [ + '#title' => $this->t('Email address(es)'), + '#description' => $this->t('Enter the email of one or more developers, separated by commas, to invite them to the @team.', [ '@team' => mb_strtolower($this->team->getEntityType()->getSingularLabel()), ]), '#type' => 'textarea', diff --git a/tests/src/Functional/DeveloperAppUITest.php b/tests/src/Functional/DeveloperAppUITest.php index 0e6b3516..0edab8e6 100644 --- a/tests/src/Functional/DeveloperAppUITest.php +++ b/tests/src/Functional/DeveloperAppUITest.php @@ -268,7 +268,7 @@ public function testCreateAppWithModifiedCredentialLifetime() { $this->assertSession()->pageTextContains($name); $this->clickLink($name); // Result depends on how fast the response was. - $this->assertSession()->pageTextMatches('/1 week (2|3) days hence/'); + $this->assertSession()->pageTextMatches('/1 week (2|3) days from now/'); // Change credential lifetime to 0 (Never) days from 10. $this->drupalGet($url); From 1d85a07ff136551e373139319f6dc1aa065265de Mon Sep 17 00:00:00 2001 From: Shishir <75600200+shishir-intelli@users.noreply.github.com> Date: Mon, 17 Jul 2023 13:49:54 +0530 Subject: [PATCH 26/27] Post create team redirection and changed internal name as machine name (#885) --- modules/apigee_edge_teams/src/Entity/Form/TeamForm.php | 7 ++++--- src/Entity/Form/AppForm.php | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/apigee_edge_teams/src/Entity/Form/TeamForm.php b/modules/apigee_edge_teams/src/Entity/Form/TeamForm.php index a9f22d85..d03ce107 100644 --- a/modules/apigee_edge_teams/src/Entity/Form/TeamForm.php +++ b/modules/apigee_edge_teams/src/Entity/Form/TeamForm.php @@ -188,11 +188,11 @@ public function form(array $form, FormStateInterface $form_state) { $team = $this->entity; $form['name'] = [ - '#title' => $this->t('Internal name'), + '#title' => $this->t('Machine name'), '#type' => 'machine_name', '#machine_name' => [ 'source' => ['displayName', 'widget', 0, 'value'], - 'label' => $this->t('Internal name'), + 'label' => $this->t('Machine name'), 'exists' => [$this, 'exists'], ], '#field_prefix' => $team->isNew() ? $this->team_prefix : "", @@ -308,7 +308,8 @@ public function save(array $form, FormStateInterface $form_state) { } } - $form_state->setRedirectUrl($team->toUrl('collection')); + // Redirecting user to team view page to manage the team members and apps. + $form_state->setRedirectUrl($team->toUrl('canonical')); return $result; } diff --git a/src/Entity/Form/AppForm.php b/src/Entity/Form/AppForm.php index 1a187353..ea74d7e5 100644 --- a/src/Entity/Form/AppForm.php +++ b/src/Entity/Form/AppForm.php @@ -73,10 +73,10 @@ public function form(array $form, FormStateInterface $form_state) { '#type' => 'machine_name', '#machine_name' => [ 'source' => ['displayName', 'widget', 0, 'value'], - 'label' => $this->t('Internal name'), + 'label' => $this->t('Machine name'), 'exists' => [$this, 'appExists'], ], - '#title' => $this->t('Internal name'), + '#title' => $this->t('Machine name'), // It should/can not be changed if app is not new. '#disabled' => !$app->isNew(), '#default_value' => $app->getName(), From 1d4ac2a3eb7c679bc5fa16d5f35f3042e7774bad Mon Sep 17 00:00:00 2001 From: Shishir <75600200+shishir-intelli@users.noreply.github.com> Date: Wed, 19 Jul 2023 19:19:50 +0530 Subject: [PATCH 27/27] Nitpick - label change Credential to Key Status (#886) --- modules/apigee_edge_teams/tests/src/Functional/UiTest.php | 2 -- src/Entity/Form/AppEditForm.php | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/apigee_edge_teams/tests/src/Functional/UiTest.php b/modules/apigee_edge_teams/tests/src/Functional/UiTest.php index 0ead854a..494ecf86 100644 --- a/modules/apigee_edge_teams/tests/src/Functional/UiTest.php +++ b/modules/apigee_edge_teams/tests/src/Functional/UiTest.php @@ -178,7 +178,6 @@ protected function teamsWorkflowTest() { // The team's display name and field values are visible on the canonical // page. - $this->clickLink($team_display_name); $this->assertSession()->pageTextContains($team_display_name); $this->assertSession()->pageTextContains($this->fields['integer']['data']); $this->assertSession()->pageTextContains($this->fields['email']['data']); @@ -193,7 +192,6 @@ protected function teamsWorkflowTest() { 'field_email[0][value]' => $this->fields['email']['data_edited'], ], 'Save team'); - $this->clickLink($team_modified_display_name); $this->assertSession()->pageTextContains($team_modified_display_name); $this->assertSession()->pageTextContains($this->fields['integer']['data_edited']); $this->assertSession()->pageTextContains($this->fields['email']['data_edited']); diff --git a/src/Entity/Form/AppEditForm.php b/src/Entity/Form/AppEditForm.php index d64294cc..f3f92533 100644 --- a/src/Entity/Form/AppEditForm.php +++ b/src/Entity/Form/AppEditForm.php @@ -124,7 +124,7 @@ public function form(array $form, FormStateInterface $form_state) { $form['credential'][$credential->getConsumerKey()] = [ '#type' => 'fieldset', - '#title' => $rendered_credential_status . $this->t('Credential'), + '#title' => $this->t('Key Status:') . $rendered_credential_status, '#collapsible' => FALSE, ];