Skip to content

Commit ea6a45f

Browse files
shishir-intellidivya-intelligiteshkmxr576VladimirAus
authored
Merging AppGroup changes into 2.x branch (#869)
* Checking if the organisation is ApigeeX for AppGroup (#803) * Fix organisation exception (#806) * Changes for Appgroup listing/view/edit/delete page (#805) * Changes for Appgroup listing/view/edit/delete page * Update composer.json * Update composer.json * AppGroup-App implementation for list, view, edit, delete apps (#813) * Merge 2.x into appgroup (#829) * Warrant that queues executed by cron (#808) * Sort API Product listings on App (#812) * Update endpoints to use constants from ClientInterface (#810) * Sort API products on app forms by API product display name (#815) * Sort API Products (#818) * Sort API Products TypeError: array_map(): Argument #2 ($array) must be of type array * Removed test case * App creation fails without API Products (#809) * App creation fails without API Products caused by features.keymanagement.disable.unbounded.permissions flag * Update minimum version of apigee-client-php * Make sure that cron runner starts executing the job (#814) * Checking if the organisation is ApigeeX for AppGroup (#803) * Fix organisation exception (#806) * Changes for Appgroup listing/view/edit/delete page (#805) * Changes for Appgroup listing/view/edit/delete page * Update composer.json * Update composer.json * AppGroup-App implementation for list, view, edit, delete apps (#813) --------- Co-authored-by: Dezső BICZÓ <[email protected]> Co-authored-by: Shishir <[email protected]> Co-authored-by: phdhiren <[email protected]> Co-authored-by: Divyajose <[email protected]> * Support for Add AppGroup/team and update team App credentials with ApiProduct (#824) * Support for AppGroup membership (#825) * The Apigee Edge and X Teams module requirements (#826) * Checking ApigeeX org from OrganizationController and removed from SDKController (#832) * If team not available on Apigee avoid null value exception (#833) * Added admin config setting for Team prefix and channelID (#839) * Implemented AppGroup membership feature for ApigeeX (#843) * Merge 2.x into appgroup branch (#859) * Warrant that queues executed by cron (#808) * Sort API Product listings on App (#812) * Update endpoints to use constants from ClientInterface (#810) * Sort API products on app forms by API product display name (#815) * Sort API Products (#818) * Sort API Products TypeError: array_map(): Argument #2 ($array) must be of type array * Removed test case * App creation fails without API Products (#809) * App creation fails without API Products caused by features.keymanagement.disable.unbounded.permissions flag * Update minimum version of apigee-client-php * Make sure that cron runner starts executing the job (#814) * Update the storage defination of App entity (#831) * Fix issue which removes users from all team (#840) * Drop PHP 7 support again (#816) * Revert "Support for PHP 7.4 (#800)" This reverts commit b71f8a9. * Clearly specify the currently supported PHP versions * Update outdated info.yml * Added accessCheck on entity queries (#842) * added accessCheck on entity queries Co-authored-by: Vladimir Roudakov <[email protected]> * added comment --------- Co-authored-by: Vladimir Roudakov <[email protected]> * Fix for jQuery.once() is deprecated in Drupal 9.3 (#851) Co-authored-by: Vladimir Roudakov <[email protected]> * fix for phpcs failing in github action (#858) * PHPCS FIX --------- Co-authored-by: Shishir <[email protected]> Co-authored-by: Dezső BICZÓ <[email protected]> Co-authored-by: Gitesh Koli <[email protected]> Co-authored-by: Divyajose <[email protected]> Co-authored-by: Vladimir Roudakov <[email protected]> * Implemented AppGroup Team Membership Sync (#853) * Get AppGroup team members from DB (#864) * Get AppGroup team members from DB and fix recurring teams api call * Declaring abstract method * Fix action module getTeam method argument * Fix for team sync issue when DB is empty * Added team member sync note for ApigeeX (#867) --------- Co-authored-by: Shishir <[email protected]> Co-authored-by: Divyajose <[email protected]> Co-authored-by: Gitesh Koli <[email protected]> Co-authored-by: Dezső BICZÓ <[email protected]> Co-authored-by: Vladimir Roudakov <[email protected]>
1 parent 386c83f commit ea6a45f

File tree

52 files changed

+1628
-104
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1628
-104
lines changed

modules/apigee_edge_actions/src/TeamMembershipManager.php

+9-2
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,15 @@ public function removeMembers(string $team, array $developers): void {
151151
/**
152152
* {@inheritdoc}
153153
*/
154-
public function getTeams(string $developer): array {
155-
return $this->inner->getTeams($developer);
154+
public function getTeams(string $developer, string $team = NULL): array {
155+
return $this->inner->getTeams($developer, $team);
156+
}
157+
158+
/**
159+
* {@inheritdoc}
160+
*/
161+
public function syncAppGroupMembers(string $team): array {
162+
return $this->inner->syncAppGroupMembers($team);
156163
}
157164

158165
/**

modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityAddMemberEventTest.php

+2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ protected function setUp(): void {
5454
parent::setUp();
5555

5656
$this->installEntitySchema('team_member_role');
57+
58+
$this->addOrganizationMatchedResponse();
5759
}
5860

5961
/**

modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityRemoveMemberEventTest.php

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ protected function setUp(): void {
5353
parent::setUp();
5454

5555
$this->installEntitySchema('team_member_role');
56+
57+
$this->addOrganizationMatchedResponse();
5658
}
5759

5860
/**

modules/apigee_edge_actions/tests/src/Kernel/Plugin/RulesEvent/EdgeEntityUpdateEventTest.php

+3
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ public function testEvent() {
5555
]);
5656
$config_entity->save();
5757

58+
// Add matched organization response so it returns the org whenever called.
59+
$this->addOrganizationMatchedResponse();
60+
5861
// Insert and update entity.
5962
/** @var \Drupal\apigee_edge\Entity\DeveloperAppInterface $entity */
6063
$entity = $this->createDeveloperApp();

modules/apigee_edge_teams/apigee_edge_teams.install

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use Drupal\user\RoleInterface;
2525
use Drupal\views\Views;
2626

2727
/**
28-
* Install, update and uninstall functions for Apigee Edge Teams.
28+
* Install, update and uninstall functions for Apigee Edge and ApigeeX Teams.
2929
*/
3030

3131
/**
@@ -41,13 +41,13 @@ function apigee_edge_teams_requirements($phase) {
4141
$org_controller = \Drupal::service('apigee_edge.controller.organization');
4242
/* @var \Apigee\Edge\Api\Management\Entity\Organization $organization */
4343
$organization = $org_controller->load($sdk_connector->getOrganization());
44-
if ($organization && !OrganizationFeatures::isCompaniesFeatureAvailable($organization)) {
44+
if ($organization && !OrganizationFeatures::isCompaniesFeatureAvailable($organization) && OrganizationFeatures::isMonetizationEnabled($organization)) {
4545
$url = [
4646
':url' => 'https://cloud.google.com/apigee/docs/api-platform/get-started/compare-apigee-products#unsupported-apis',
4747
];
4848
$message = ($phase == 'runtime') ?
49-
t("The Apigee Edge Teams module functionality is not available for your org and should be uninstalled, because <a href=':url' target='_blank'>Edge company APIs are not supported in Apigee X and Apigee Hybrid orgs</a>.", $url) :
50-
t("The Apigee Edge Teams module functionality is not available for your org because <a href=':url' target='_blank'>Edge company APIs are not supported in Apigee X and Apigee Hybrid orgs</a>.", $url);
49+
t("The Teams module functionality is not available for monetization enabled org on Apigee X / Hybrid and should be uninstalled, because <a href=':url' target='_blank'>AppGroup APIs are not supported in Apigee X / Hybrid orgs with monetization enabled</a>.", $url) :
50+
t("The Teams module functionality is not available for monetization enabled org on Apigee X / Hybrid because <a href=':url' target='_blank'>AppGroup APIs are not supported in Apigee X / Hybrid orgs with monetization enabled</a>.", $url);
5151
$requirements['apigee_edge_teams_not_supported'] = [
5252
'title' => t('Apigee Edge Teams'),
5353
'description' => $message,

modules/apigee_edge_teams/apigee_edge_teams.links.task.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
apigee_edge_teams.settings.team:
22
route_name: apigee_edge_teams.settings.team
3-
title: 'Alias'
3+
title: 'Settings'
44
base_route: apigee_edge_teams.settings.team
55
weight: -10
66

modules/apigee_edge_teams/apigee_edge_teams.services.yml

+14-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ services:
2424
class: Drupal\apigee_edge_teams\CompanyMembershipObjectCache
2525
arguments: ['@cache_factory', '@apigee_edge.cache.memory_cache_factory', '@config.factory', '@datetime.time']
2626

27+
apigee_edge_teams.cache.appgroup_membership_object:
28+
class: Drupal\apigee_edge_teams\AppGroupMembershipObjectCache
29+
arguments: ['@cache_factory', '@apigee_edge.cache.memory_cache_factory', '@config.factory', '@datetime.time']
30+
31+
apigee_edge.controller.cache.appgroup_teams:
32+
class: Drupal\apigee_edge_teams\AppGroupCache
33+
arguments: ['@apigee_edge.cache.memory_cache_factory']
34+
2735
apigee_edge_teams.controller.team:
2836
class: Drupal\apigee_edge_teams\Entity\Controller\TeamController
2937
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:
4048
class: Drupal\apigee_edge_teams\CompanyMembersControllerFactory
4149
arguments: ['@apigee_edge.sdk_connector', '@apigee_edge_teams.cache.company_membership_object']
4250

51+
apigee_edge_teams.appgroup_members_controller_factory:
52+
class: Drupal\apigee_edge_teams\AppGroupMembersControllerFactory
53+
arguments: ['@apigee_edge.sdk_connector', '@apigee_edge_teams.cache.appgroup_membership_object']
54+
4355
apigee_edge_teams.controller.cache.team:
4456
class: Drupal\apigee_edge\Entity\Controller\Cache\EntityCache
4557
arguments: ['@apigee_edge_teams.cache.memory_cache_factory', '@apigee_edge_teams.controller.cache.team_ids', team]
@@ -49,7 +61,7 @@ services:
4961

5062
apigee_edge_teams.team_membership_manager:
5163
class: Drupal\apigee_edge_teams\TeamMembershipManager
52-
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']
64+
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']
5365

5466
apigee_edge_teams.team_permissions:
5567
class: Drupal\apigee_edge_teams\TeamPermissionHandler
@@ -85,7 +97,7 @@ services:
8597

8698
apigee_edge_teams.event_subscriber.team_invitation_event_subscriber:
8799
class: Drupal\apigee_edge_teams\EventSubscriber\TeamInvitationSubscriber
88-
arguments: ['@logger.channel.apigee_edge_teams', '@entity_type.manager', '@apigee_edge_teams.team_membership_manager', '@apigee_edge_teams.team_invitation_notifier.email']
100+
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']
89101
tags:
90102
- { name: event_subscriber }
91103

modules/apigee_edge_teams/config/install/apigee_edge_teams.team_settings.yml

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
langcode: en
2+
team_prefix: ''
3+
channelid: ''
24
entity_label_singular: ''
35
entity_label_plural: ''
46
cache_expiration: 900

modules/apigee_edge_teams/config/schema/apigee_edge_teams.schema.yml

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ apigee_edge_teams.team_settings:
22
type: config_object
33
label: 'Team settings'
44
mapping:
5+
team_prefix:
6+
type: label
7+
label: 'Prefix to add for the Team name'
8+
channelid:
9+
type: label
10+
label: 'ChannelId settings'
511
entity_label_singular:
612
type: label
713
label: 'How to refer to a Team on the UI (singular)'

modules/apigee_edge_teams/src/Access/ManageTeamMembersAccess.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ public function access(RouteMatchInterface $route_match, AccountInterface $accou
8686
// If the developer parameter is available in the route make sure it is
8787
// member of the team.
8888
if ($developer !== NULL) {
89-
if (!in_array($team->id(), $this->teamMembershipManager->getTeams($developer->getEmail()))) {
89+
// Argument #2 in getTeams() is required for checking the AppGroup members and not required for Edge.
90+
if (!in_array($team->id(), $this->teamMembershipManager->getTeams($developer->getEmail(), $team->id()))) {
9091
return AccessResultForbidden::forbidden("The {$developer->getEmail()} developer is not member of the {$team->id()} team.");
9192
}
9293
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
<?php
2+
3+
/**
4+
* Copyright 2023 Google Inc.
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU General Public License
8+
* version 2 as published by the Free Software Foundation.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18+
* MA 02110-1301, USA.
19+
*/
20+
21+
namespace Drupal\apigee_edge_teams;
22+
23+
use Apigee\Edge\Api\ApigeeX\Controller\AppGroupMembersController as ApigeeXAppGroupMembersController;
24+
use Apigee\Edge\Api\ApigeeX\Structure\AppGroupMembership;
25+
use Drupal\apigee_edge\Entity\Controller\OrganizationController;
26+
use Drupal\apigee_edge\SDKConnectorInterface;
27+
use Drupal\apigee_edge_teams\Entity\Form\TeamForm;
28+
use Drupal\apigee_edge_teams\Entity\TeamInvitationInterface;
29+
use Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface;
30+
use Drupal\Component\Serialization\Json;
31+
32+
/**
33+
* Definition of the AppGroup members controller service.
34+
*
35+
* @internal You should use the team membership manager service instead of this.
36+
*/
37+
final class AppGroupMembersController implements AppGroupMembersControllerInterface {
38+
39+
/**
40+
* Name of a appgroup.
41+
*
42+
* @var string
43+
*/
44+
private $appGroup;
45+
46+
/**
47+
* The SDK connector service.
48+
*
49+
* @var \Drupal\apigee_edge\SDKConnectorInterface
50+
*/
51+
private $connector;
52+
53+
/**
54+
* The appgroup membership object cache.
55+
*
56+
* @var \Drupal\apigee_edge_teams\AppGroupMembershipObjectCacheInterface
57+
*/
58+
private $appGroupMembershipObjectCache;
59+
60+
/**
61+
* AppGroupMembersController constructor.
62+
*
63+
* @param string $appGroup
64+
* The name of the appgroup.
65+
* @param \Drupal\apigee_edge\SDKConnectorInterface $connector
66+
* The SDK connector service.
67+
* @param \Drupal\apigee_edge_teams\AppGroupMembershipObjectCacheInterface $appgroup_membership_object_cache
68+
* The appgroup membership object cache.
69+
*/
70+
public function __construct(string $appGroup, SDKConnectorInterface $connector, AppGroupMembershipObjectCacheInterface $appgroup_membership_object_cache) {
71+
$this->appGroup = $appGroup;
72+
$this->connector = $connector;
73+
$this->appGroupMembershipObjectCache = $appgroup_membership_object_cache;
74+
}
75+
76+
/**
77+
* Returns the decorated appgroup members controller from the SDK.
78+
*
79+
* @return \Apigee\Edge\Api\ApigeeX\Controller\AppGroupMembersController
80+
* The initialized appgroup members controller.
81+
*/
82+
private function decorated(): ApigeeXAppGroupMembersController {
83+
return new ApigeeXAppGroupMembersController($this->appGroup, $this->connector->getOrganization(), $this->connector->getClient());
84+
}
85+
86+
/**
87+
* {@inheritdoc}
88+
*/
89+
public function getAppGroup(): string {
90+
return $this->decorated()->getAppGroup();
91+
}
92+
93+
/**
94+
* Syncs the appgroup team members email and roles in database.
95+
*
96+
* @return \Apigee\Edge\Api\ApigeeX\Structure\AppGroupMembership
97+
* Array of developers with their optional roles in the appgroup.
98+
*/
99+
public function syncAppGroupMembers(): AppGroupMembership {
100+
$membership = $this->decorated()->getMembers();
101+
102+
$developer_exist = TRUE;
103+
foreach ($membership->getMembers() as $developer_id => $roles) {
104+
$roles = is_array($roles) ? $roles : [];
105+
106+
/** @var \Drupal\user\Entity\User $account */
107+
$account = user_load_by_mail($developer_id);
108+
109+
if (!$account) {
110+
$developer_exist = FALSE;
111+
/** @var \Drupal\apigee_edge_teams\Entity\Storage\TeamInvitationStorageInterface $teamInvitationStorage */
112+
$teamInvitationStorage = \Drupal::entityTypeManager()->getStorage('team_invitation');
113+
114+
$pending_invitations = array_filter($teamInvitationStorage->loadByRecipient($developer_id, $this->appGroup), function (TeamInvitationInterface $team_invitation) {
115+
return $team_invitation->isPending();
116+
});
117+
118+
// Checking if this developer has already pending invite to prevent multiple invites.
119+
if (count($pending_invitations) === 0) {
120+
$teamInvitationStorage->create([
121+
'team' => ['target_id' => $this->appGroup],
122+
'team_roles' => array_values(array_map(function (string $role) {
123+
return ['target_id' => $role];
124+
}, $roles)),
125+
'recipient' => $developer_id,
126+
])->save();
127+
}
128+
}
129+
else {
130+
/** @var \Drupal\apigee_edge_teams\Entity\TeamInterface|null $team_entity */
131+
$team_entity = \Drupal::entityTypeManager()->getStorage('team')->load($this->appGroup);
132+
/** @var \Drupal\apigee_edge_teams\Entity\Storage\TeamMemberRoleStorageInterface $team_member_role_storage */
133+
$team_member_role_storage = \Drupal::entityTypeManager()->getStorage('team_member_role');
134+
$team_member_role_storage->addTeamRoles($account, $team_entity, $roles);
135+
}
136+
}
137+
// Caching the membership only if all the developer exists in Drupal
138+
// to avoid team member without access.
139+
if ($developer_exist) {
140+
$this->appGroupMembershipObjectCache->saveMembership($this->appGroup, $membership);
141+
}
142+
143+
return $membership;
144+
}
145+
146+
/**
147+
* {@inheritdoc}
148+
*/
149+
public function getMembers(): AppGroupMembership {
150+
$membership = $this->appGroupMembershipObjectCache->getMembership($this->appGroup);
151+
if ($membership === NULL) {
152+
/** @var \Drupal\apigee_edge_teams\Entity\TeamInterface|null $team_entity */
153+
$team_entity = \Drupal::entityTypeManager()->getStorage('team')->load($this->appGroup);
154+
// Load team_member_role object.
155+
$team_member_role_storage = \Drupal::entityTypeManager()->getStorage('team_member_role');
156+
$members = array_reduce($team_member_role_storage->loadByTeam($team_entity), function ($carry, TeamMemberRoleInterface $developer_role) {
157+
$carry[$developer_role->getDeveloper()->getEmail()] = $developer_role->getDeveloper()->getEmail();
158+
return $carry;
159+
},
160+
[]);
161+
$membership = new AppGroupMembership($members);
162+
$this->appGroupMembershipObjectCache->saveMembership($team_entity->id(), $membership);
163+
}
164+
165+
return $membership;
166+
}
167+
168+
/**
169+
* {@inheritdoc}
170+
*/
171+
public function setMembers(AppGroupMembership $members): AppGroupMembership {
172+
// Get the existing members and roles from ApigeeX.
173+
$apigeeReservedMembers = $this->decorated()->getMembers();
174+
// Getting all developers including the newly added one.
175+
$developers = array_merge($apigeeReservedMembers->getMembers(), $members->getMembers());
176+
177+
foreach ($developers as $developer => $roles) {
178+
$members->setMember($developer, $roles);
179+
}
180+
// Storing membership info on appgroups __apigee_reserved__developer_details attribute for ApigeeX.
181+
$result = $this->decorated()->setMembers($members);
182+
183+
// Returned membership does not contain all actual members of the appGroup,
184+
// so it is easier to remove the membership object from the cache and
185+
// enforce reload in getMembers().
186+
$this->appGroupMembershipObjectCache->removeMembership($this->appGroup);
187+
return $result;
188+
}
189+
190+
/**
191+
* {@inheritdoc}
192+
*/
193+
public function removeMember(string $email): void {
194+
// Get the existing members and roles from ApigeeX.
195+
$apigeeReservedMembers = $this->decorated()->getMembers();
196+
197+
foreach ($apigeeReservedMembers->getMembers() as $developer => $roles) {
198+
if ($developer === $email) {
199+
$apigeeReservedMembers->removeMember($developer);
200+
}
201+
}
202+
// Storing membership info on appgroups __apigee_reserved__developer_details attribute for ApigeeX.
203+
// Removing and updating the member on appgroups __apigee_reserved__developer_details attribute for ApigeeX.
204+
$result = $this->decorated()->setMembers($apigeeReservedMembers);
205+
206+
$this->appGroupMembershipObjectCache->removeMembership($this->appGroup);
207+
}
208+
209+
}

0 commit comments

Comments
 (0)