diff --git a/modules/apigee_edge_actions/src/TeamMembershipManager.php b/modules/apigee_edge_actions/src/TeamMembershipManager.php index 7ab5197fb..7d57f7799 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 aa304763d..794348247 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 018b36b48..3c704c77e 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 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 4e73e9d1b..bd629d1f6 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 72c8815ad..68c777f56 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 5246435ec..933b644cf 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 2160048db..388d93e3d 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 6c4286dfe..69f5d137a 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 153387ed7..acb777ebb 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 000000000..b2938efa0 --- /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 000000000..d00b81355 --- /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 000000000..60b00819a --- /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 000000000..676ba61d0 --- /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 fe702e856..5082ab854 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 000000000..113db2925 --- /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 000000000..cbe2865bd --- /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 6fcde5012..9f7473385 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 88f55ab9c..1c901c911 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 1adc8210a..b9243917e 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 40bb3b80c..fb0e230fd 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 444ce3ba7..a9f22d85a 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 6ab0e8ff4..67377df77 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 af3e60405..11de4f271 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 d963c3147..d50a68d53 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 f51335a78..14b60def2 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 c623e1391..ea0b896dc 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 0e759756f..7d4643d07 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 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/modules/apigee_edge_teams/src/EventSubscriber/TeamInvitationSubscriber.php b/modules/apigee_edge_teams/src/EventSubscriber/TeamInvitationSubscriber.php index c7666e339..30005fae7 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 1f7ed9a50..e6e6ad02f 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 83c5bc621..97d392a86 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 33e99cb65..d6883e92c 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 29d33331a..3075f7263 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 22e274892..f42cf6d3b 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 fa716f189..54c5c889b 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 c65aa2788..e19589031 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 f963fe0c9..5ab2d36e4 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 e343552dd..62435316c 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 60c5898af..c11eb578b 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 608722a76..e7c546ff7 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 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..a21980977 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 d98d1d72b..8203b30b4 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 9d7cb9f38..acbb0b0b1 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 0eb513e46..62e634161 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 df8282ca0..23b16fbce 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 61e2fadfc..081f250cb 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;