diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index ca6cdc49c..03d0cecf3 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 2d1334ced..4d9a35063 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 bd77e0418..1550b9823 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", "ext-json": "*", "apigee/apigee-client-php": "dev-appgroup", "drupal/core": "^9.4", 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 7503c6785..fcfcedf7f 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 24ee197b2..9a681b006 100644 --- a/modules/apigee_edge_teams/apigee_edge_teams.install +++ b/modules/apigee_edge_teams/apigee_edge_teams.install @@ -18,50 +18,10 @@ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -use Apigee\Edge\Utility\OrganizationFeatures; use Drupal\Core\Config\FileStorage; use Drupal\user\RoleInterface; use Drupal\views\Views; -/** - * Install, update and uninstall functions for Apigee Edge Teams. - */ - -/** - * Implements hook_requirements(). - */ -function apigee_edge_teams_requirements($phase) { - $requirements = []; - - if ($phase == 'install' || $phase == 'runtime') { - try { - /** @var \Drupal\apigee_edge\SDKConnectorInterface $sdk_connector */ - $sdk_connector = \Drupal::service('apigee_edge.sdk_connector'); - $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)) { - $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); - $requirements['apigee_edge_teams_not_supported'] = [ - 'title' => t('Apigee Edge Teams'), - 'description' => $message, - 'severity' => REQUIREMENT_ERROR, - ]; - } - } - catch (\Exception $exception) { - // Do nothing if connection to Edge is not available. - } - } - - return $requirements; -} - /** * Implements hook_install(). */ diff --git a/modules/apigee_edge_teams/src/Entity/Controller/TeamAppApigeeXEntityControllerProxy.php b/modules/apigee_edge_teams/src/Entity/Controller/TeamAppApigeeXEntityControllerProxy.php new file mode 100644 index 000000000..caef6ed21 --- /dev/null +++ b/modules/apigee_edge_teams/src/Entity/Controller/TeamAppApigeeXEntityControllerProxy.php @@ -0,0 +1,121 @@ +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 6fcde5012..095d2baa1 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,14 @@ 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); + + // Checking if the Organisation is Hybrid/ApigeeX. + if ($this->isOrgApigeeX()) { + $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/Storage/TeamAppStorage.php b/modules/apigee_edge_teams/src/Entity/Storage/TeamAppStorage.php index 6ab0e8ff4..e61aadce7 100644 --- a/modules/apigee_edge_teams/src/Entity/Storage/TeamAppStorage.php +++ b/modules/apigee_edge_teams/src/Entity/Storage/TeamAppStorage.php @@ -26,6 +26,7 @@ use Drupal\apigee_edge\Entity\Storage\AppStorage; use Drupal\apigee_edge_teams\Entity\Controller\TeamAppControllerFactoryInterface; use Drupal\apigee_edge_teams\Entity\Controller\TeamAppEdgeEntityControllerProxy; +use Drupal\apigee_edge_teams\Entity\Controller\TeamAppApigeeXEntityControllerProxy; use Drupal\Component\Datetime\TimeInterface; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Cache\MemoryCache\MemoryCacheInterface; @@ -83,7 +84,13 @@ public static function createInstance(ContainerInterface $container, EntityTypeI * {@inheritdoc} */ protected function entityController(): EdgeEntityControllerInterface { - return new TeamAppEdgeEntityControllerProxy($this->teamAppControllerFactory, $this->appController); + if ($this->appController->isOrgApigeeX()) { + $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/TeamApp.php b/modules/apigee_edge_teams/src/Entity/TeamApp.php index c623e1391..d04ad0862 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,26 @@ public function id(): ?string { * {@inheritdoc} */ public function getAppOwner(): ?string { - return $this->decorated->getCompanyName(); + $appController = \Drupal::service('apigee_edge.controller.app'); + if ($appController->isOrgApigeeX()) { + return $this->decorated->getAppGroup(); + } + else { + return $this->decorated->getCompanyName(); + } } /** * {@inheritdoc} */ public function setAppOwner(string $owner): void { - $this->decorated->setCompanyName($owner); + $appController = \Drupal::service('apigee_edge.controller.app'); + if ($appController->isOrgApigeeX()) { + $this->decorated->setAppGroup($owner); + } + else { + $this->decorated->setCompanyName($owner); + } } /** @@ -139,18 +152,37 @@ public function getCompanyName(): ?string { return $this->decorated->getCompanyName(); } + /** + * {@inheritdoc} + */ + public function getAppGroup(): ?string { + return $this->decorated->getAppGroup(); + } + /** * {@inheritdoc} */ protected static function decoratedClass(): string { - return CompanyApp::class; + $appController = \Drupal::service('apigee_edge.controller.app'); + if ($appController->isOrgApigeeX()) { + return AppGroupApp::class; + } + else { + return CompanyApp::class; + } } /** * {@inheritdoc} */ public static function idProperty(): string { - return CompanyApp::idProperty(); + $appController = \Drupal::service('apigee_edge.controller.app'); + if ($appController->isOrgApigeeX()) { + return AppGroupApp::idProperty(); + } + else { + return CompanyApp::idProperty(); + } } /** @@ -174,7 +206,13 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { } // Hide readonly properties from Manage form display list. - $definitions['companyName']->setDisplayConfigurable('form', FALSE); + $appController = \Drupal::service('apigee_edge.controller.app'); + if ($appController->isOrgApigeeX()) { + $definitions['appGroup']->setDisplayConfigurable('form', FALSE); + } + else { + $definitions['companyName']->setDisplayConfigurable('form', FALSE); + } return $definitions; } @@ -187,7 +225,13 @@ protected function urlRouteParameters($rel) { $link_templates = $this->linkTemplates(); if (isset($link_templates[$rel])) { if (strpos($link_templates[$rel], '{team}') !== FALSE) { - $params['team'] = $this->getCompanyName(); + $appController = \Drupal::service('apigee_edge.controller.app'); + if ($appController->isOrgApigeeX()) { + $params['team'] = $this->getAppGroup(); + } + else { + $params['team'] = $this->getCompanyName(); + } } if (strpos($link_templates[$rel], '{app}') !== FALSE) { $params['app'] = $this->getName(); diff --git a/modules/apigee_edge_teams/src/Entity/TeamAppInterface.php b/modules/apigee_edge_teams/src/Entity/TeamAppInterface.php index 528868ad8..9dd1a4879 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/src/Entity/App.php b/src/Entity/App.php index 625f18e47..68941b450 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() : + ''; } /** @@ -137,7 +140,7 @@ public function getCredentials(): array { /** @var \Drupal\apigee_edge\Entity\Controller\AppControllerInterface $app_controller */ $app_controller = \Drupal::service('apigee_edge.controller.app'); try { - $app = $app_controller->loadApp($this->getAppId()); + $app = $app_controller->isOrgApigeeX() ? $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 3a1ad7692..d9d9b30dd 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 Hybrid/ApigeeX. + if ($this->isOrgApigeeX()) { + $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/AppControllerBase.php b/src/Entity/Controller/AppControllerBase.php index 00871e6f1..d27958b98 100644 --- a/src/Entity/Controller/AppControllerBase.php +++ b/src/Entity/Controller/AppControllerBase.php @@ -77,4 +77,15 @@ public function entityCache(): EntityCacheInterface { return $this->appCache; } + /** + * Checking if the Organisation is ApigeeX. + * + * @return bool + * TRUE if given Organisation is ApigeeX. FALSE otherwise. + */ + public function isOrgApigeeX(): bool { + // Checking if the Organisation is ApigeeX. + return $this->connector->isOrganizationApigeeX($this->organizationController); + } + } diff --git a/src/Entity/Controller/Cache/AppCache.php b/src/Entity/Controller/Cache/AppCache.php index fa9fc2c19..274063100 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 e9d533aee..bee93e480 100644 --- a/src/Entity/Controller/DeveloperAppEdgeEntityControllerProxy.php +++ b/src/Entity/Controller/DeveloperAppEdgeEntityControllerProxy.php @@ -77,7 +77,8 @@ public function create(EntityInterface $entity): void { * {@inheritdoc} */ public function load(string $id): EntityInterface { - return $this->appController->loadApp($id); + $app = $this->appController->isOrgApigeeX() ? $this->appController->loadAppGroup($id) : $this->appController->loadApp($id); + return $app; } /** diff --git a/src/SDKConnectorInterface.php b/src/SDKConnectorInterface.php index e96eeab6e..6b02620e3 100644 --- a/src/SDKConnectorInterface.php +++ b/src/SDKConnectorInterface.php @@ -38,7 +38,7 @@ interface SDKConnectorInterface { public function getOrganization(): string; /** - * Checking if the Organisation is ApigeeX.. + * Checking if the Organisation is ApigeeX. * * @return bool * TRUE if given Organisation is ApigeeX. FALSE otherwise.