Skip to content

Commit 8238937

Browse files
committed
Use the new user-access API
1 parent 47cade7 commit 8238937

File tree

8 files changed

+308
-148
lines changed

8 files changed

+308
-148
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"guzzlehttp/guzzle": "^5.3",
99
"guzzlehttp/ringphp": "^1.1",
1010
"platformsh/console-form": ">=0.0.37 <2.0",
11-
"platformsh/client": ">=0.78.1 <2.0",
11+
"platformsh/client": ">=0.79.0 <2.0",
1212
"symfony/console": "^3.0 >=3.2",
1313
"symfony/yaml": "^3.0 || ^2.6",
1414
"symfony/finder": "^3.0",

composer.lock

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Command/User/UserAddCommand.php

Lines changed: 105 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
<?php
22
namespace Platformsh\Cli\Command\User;
33

4-
use Platformsh\Cli\Command\CommandBase;
54
use Platformsh\Cli\Console\ArrayArgument;
5+
use Platformsh\Cli\Util\OsUtil;
66
use Platformsh\Cli\Util\Wildcard;
77
use Platformsh\Client\Model\EnvironmentAccess;
88
use Platformsh\Client\Model\EnvironmentType;
99
use Platformsh\Client\Model\Invitation\AlreadyInvitedException;
1010
use Platformsh\Client\Model\Invitation\Permission;
1111
use Platformsh\Client\Model\ProjectAccess;
12+
use Platformsh\Client\Model\UserAccess\ProjectUserAccess;
1213
use Symfony\Component\Console\Exception\InvalidArgumentException;
1314
use Symfony\Component\Console\Helper\ProgressBar;
1415
use Symfony\Component\Console\Input\InputArgument;
@@ -18,7 +19,7 @@
1819
use Symfony\Component\Console\Output\OutputInterface;
1920
use Symfony\Component\Console\Question\Question;
2021

21-
class UserAddCommand extends CommandBase
22+
class UserAddCommand extends UserCommandBase
2223
{
2324

2425
protected function configure()
@@ -121,13 +122,10 @@ protected function execute(InputInterface $input, OutputInterface $output)
121122
$email = $input->getArgument('email');
122123
if (!$email) {
123124
$update = stripos($input->getFirstArgument(), ':u');
124-
if ($update && $input->isInteractive()) {
125-
$choices = [];
126-
foreach ($this->api()->getProjectAccesses($project) as $access) {
127-
$account = $this->api()->getAccount($access);
128-
$choices[$account['email']] = $this->getUserLabel($access);
129-
}
130-
$email = $questionHelper->choose($choices, 'Enter a number to choose a user to update:');
125+
if (!$input->isInteractive()) {
126+
throw new InvalidArgumentException('An email address is required (in non-interactive mode).');
127+
} elseif ($update) {
128+
$email = $questionHelper->choose($this->listUsers($project), 'Enter a number to choose a user to update:');
131129
} else {
132130
$question = new Question("Enter the user's email address: ");
133131
$question->setValidator(function ($answer) {
@@ -140,41 +138,59 @@ protected function execute(InputInterface $input, OutputInterface $output)
140138
}
141139
$this->validateEmail($email);
142140

143-
// Check the user's existing role on the project.
144-
$existingProjectAccess = $this->api()->loadProjectAccessByEmail($project, $email);
145141
$existingTypeRoles = [];
146-
if ($existingProjectAccess) {
147-
// Exit if the user is the owner already.
148-
if ($existingProjectAccess->id === $project->owner) {
149-
if ($hasOutput) {
150-
$this->stdErr->writeln('');
151-
}
152-
153-
$this->stdErr->writeln(sprintf('The user %s is the owner of %s.', $this->getUserLabel($existingProjectAccess), $this->api()->getProjectLabel($project)));
154-
if ($specifiedProjectRole || $specifiedTypeRoles) {
155-
$this->stdErr->writeln('');
156-
$this->stdErr->writeln("<comment>The project owner's role(s) cannot be changed.</comment>");
142+
$existingProjectRole = null;
143+
$existingUserLabel = null;
144+
$existingUserId = null;
145+
146+
/**
147+
* @var ProjectUserAccess|ProjectAccess|null $selection
148+
*/
149+
$selection = $this->loadProjectUserByEmail($project, $email);
150+
if ($selection instanceof ProjectUserAccess) {
151+
$existingUserId = $selection->user_id;
152+
$existingProjectRole = $selection->getProjectRole();
153+
$existingTypeRoles = $selection->getEnvironmentTypeRoles();
154+
$userInfo = $selection->getUserInfo();
155+
$existingUserLabel = sprintf('<info>%s</info> (%s)', trim($userInfo->first_name . ' ' . $userInfo->last_name), $userInfo->email);
156+
} elseif ($selection instanceof ProjectAccess) {
157+
$existingUserId = $selection->id;
158+
$existingProjectRole = $selection->role;
159+
$existingUserLabel = $this->getUserLabel($selection);
160+
$existingTypeRoles = $this->getTypeRoles($selection, $environmentTypes);
161+
}
162+
163+
if ($existingUserId !== null) {
164+
$this->debug(sprintf('The user %s already exists on the project (user ID: %s)', $email, $existingUserId));
165+
}
166+
167+
// Exit if the user is the owner already.
168+
if ($existingUserId !== null && $existingUserId === $project->owner) {
169+
if ($hasOutput) {
170+
$this->stdErr->writeln('');
171+
}
157172

158-
return 1;
159-
}
173+
$this->stdErr->writeln(sprintf('The user %s is the owner of %s.', $existingUserLabel, $this->api()->getProjectLabel($project)));
174+
if ($specifiedProjectRole || $specifiedTypeRoles) {
175+
$this->stdErr->writeln('');
176+
$this->stdErr->writeln("<comment>The project owner's role(s) cannot be changed.</comment>");
160177

161-
return 0;
178+
return 1;
162179
}
163180

164-
// Check the user's existing role(s) on the project's environments and types.
165-
$existingTypeRoles = $this->getTypeRoles($existingProjectAccess, $environmentTypes);
181+
return 0;
166182
}
167183

168184
// If the user already exists, print a summary of their roles on the
169185
// project and environments.
170-
if ($existingProjectAccess) {
186+
if ($existingUserId !== null) {
171187
if ($hasOutput) {
172188
$this->stdErr->writeln('');
173189
}
174190

175-
$this->stdErr->writeln(sprintf('Current role(s) of <info>%s</info> on %s:', $this->getUserLabel($existingProjectAccess), $this->api()->getProjectLabel($project)));
176-
$this->stdErr->writeln(sprintf(' Project role: <info>%s</info>', $existingProjectAccess->role));
177-
if ($existingProjectAccess->role !== ProjectAccess::ROLE_ADMIN) {
191+
$this->stdErr->writeln(sprintf('Current role(s) of %s on %s:', $existingUserLabel, $this->api()->getProjectLabel($project)));
192+
$this->stdErr->writeln(sprintf(' Project role: <info>%s</info>', $existingProjectRole));
193+
if ($existingProjectRole !== ProjectAccess::ROLE_ADMIN) {
178194
foreach ($environmentTypes as $type) {
179195
$role = isset($existingTypeRoles[$type->id]) ? $existingTypeRoles[$type->id] : '[none]';
180196
$this->stdErr->writeln(sprintf(' Role on environment type <info>%s</info>: %s', $type->id, $role));
@@ -184,7 +200,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
184200
}
185201

186202
// Resolve or merge the project role.
187-
$desiredProjectRole = $specifiedProjectRole ?: ($existingProjectAccess ? $existingProjectAccess->role : ProjectAccess::ROLE_VIEWER);
203+
$desiredProjectRole = $specifiedProjectRole ?: ($existingProjectRole ?: ProjectAccess::ROLE_VIEWER);
188204
$provideProjectForm = !$input->getOption('role') && $input->isInteractive();
189205
if ($provideProjectForm) {
190206
if ($hasOutput) {
@@ -219,9 +235,9 @@ protected function execute(InputInterface $input, OutputInterface $output)
219235

220236
// Build a list of the changes that are going to be made.
221237
$changesText = [];
222-
if ($existingProjectAccess) {
223-
if ($existingProjectAccess->role !== $desiredProjectRole) {
224-
$changesText[] = sprintf('Project role: <error>%s</error> -> <info>%s</info>', $existingProjectAccess->role, $desiredProjectRole);
238+
if ($existingUserId !== null) {
239+
if ($existingProjectRole !== $desiredProjectRole) {
240+
$changesText[] = sprintf('Project role: <error>%s</error> -> <info>%s</info>', $existingProjectRole, $desiredProjectRole);
225241
}
226242
} else {
227243
$changesText[] = sprintf('Project role: <info>%s</info>', $desiredProjectRole);
@@ -271,12 +287,12 @@ protected function execute(InputInterface $input, OutputInterface $output)
271287
$this->stdErr->writeln('<error>No environment types selected.</error>');
272288
$this->stdErr->writeln('A non-admin user must be added to at least one environment type.');
273289

274-
if ($existingProjectAccess) {
290+
if ($existingUserId !== null) {
275291
$this->stdErr->writeln('');
276292
$this->stdErr->writeln(sprintf(
277293
'To delete the user, run: <info>%s user:delete %s</info>',
278294
$this->config()->get('application.executable'),
279-
$this->api()->getAccount($existingProjectAccess)['email']
295+
OsUtil::escapeShellArg($email)
280296
));
281297
}
282298

@@ -290,7 +306,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
290306
}
291307

292308
// Print a summary of the changes that are about to be made.
293-
if ($existingProjectAccess) {
309+
if ($existingUserId !== null) {
294310
$this->stdErr->writeln('Summary of changes:');
295311
} else {
296312
$this->stdErr->writeln(sprintf('Adding the user <info>%s</info> to %s:', $email, $this->api()->getProjectLabel($project)));
@@ -301,7 +317,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
301317
$this->stdErr->writeln('');
302318

303319
// Ask for confirmation.
304-
if ($existingProjectAccess) {
320+
if ($existingUserId !== null) {
305321
if (!$questionHelper->confirm('Are you sure you want to make these change(s)?')) {
306322
return 1;
307323
}
@@ -317,7 +333,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
317333
$this->stdErr->writeln('');
318334

319335
// If the user does not already exist on the project, then use the Invitations API.
320-
if (!$existingProjectAccess) {
336+
if ($existingUserId === null) {
321337
$this->stdErr->writeln('Inviting the user to the project...');
322338
$permissions = [];
323339
foreach ($desiredTypeRoles as $type => $role) {
@@ -340,56 +356,68 @@ protected function execute(InputInterface $input, OutputInterface $output)
340356
return 0;
341357
}
342358

343-
// Make the desired changes at the project level.
344-
if ($existingProjectAccess->role !== $desiredProjectRole) {
345-
$this->stdErr->writeln("Setting the user's project role to: $desiredProjectRole");
346-
$result = $existingProjectAccess->update(['role' => $desiredProjectRole]);
347-
$activities = $result->getActivities();
348-
$userId = $existingProjectAccess->id;
349-
} else {
350-
$userId = $existingProjectAccess->id;
351-
$activities = [];
352-
}
353-
354-
// Make the desired changes at the environment type level.
355-
if ($desiredProjectRole !== ProjectAccess::ROLE_ADMIN) {
356-
foreach ($typeChanges as $typeId => $role) {
357-
$type = $project->getEnvironmentType($typeId);
358-
if (!$type) {
359-
$this->stdErr->writeln('Environment type not found: <comment>' . $typeId . '</comment>');
360-
continue;
361-
}
362-
$access = $type->getUser($userId);
363-
if ($role === 'none') {
364-
if ($access) {
365-
$this->stdErr->writeln("Removing the user from the environment type <info>$typeId</info>");
366-
$result = $access->delete();
367-
} else {
359+
$activities = [];
360+
if ($selection instanceof ProjectUserAccess) {
361+
$permissions = [$desiredProjectRole];
362+
foreach ($desiredTypeRoles as $typeId => $role) {
363+
$permissions[] = sprintf('%s:%s', $typeId, $role);
364+
}
365+
if ($permissions != $selection->permissions) {
366+
$this->stdErr->writeln("Updating the user's project access");
367+
$this->debug('New permissions: ' . implode(', ', $permissions));
368+
$selection->update(['permissions' => $permissions]);
369+
} else {
370+
$this->stdErr->writeln('No changes to make');
371+
$this->debug('Permissions match: ' . implode(', ', $permissions));
372+
}
373+
} elseif ($selection instanceof ProjectAccess) {
374+
// Make the desired changes at the project level.
375+
if ($existingProjectRole !== $desiredProjectRole) {
376+
$this->stdErr->writeln("Setting the user's project role to: $desiredProjectRole");
377+
$result = $selection->update(['role' => $desiredProjectRole]);
378+
$activities = $result->getActivities();
379+
}
380+
381+
// Make the desired changes at the environment type level.
382+
if ($desiredProjectRole !== ProjectAccess::ROLE_ADMIN) {
383+
foreach ($typeChanges as $typeId => $role) {
384+
$type = $project->getEnvironmentType($typeId);
385+
if (!$type) {
386+
$this->stdErr->writeln('Environment type not found: <comment>' . $typeId . '</comment>');
368387
continue;
369388
}
370-
} elseif ($access) {
371-
if ($access->role === $role) {
372-
continue;
389+
$access = $type->getUser($existingUserId);
390+
if ($role === 'none') {
391+
if ($access) {
392+
$this->stdErr->writeln("Removing the user from the environment type <info>$typeId</info>");
393+
$result = $access->delete();
394+
} else {
395+
continue;
396+
}
397+
} elseif ($access) {
398+
if ($access->role === $role) {
399+
continue;
400+
}
401+
$this->stdErr->writeln("Setting the user's role on the environment type <info>$typeId</info> to: $role");
402+
$result = $access->update(['role' => $role]);
403+
} else {
404+
$this->stdErr->writeln("Adding the user to the environment type: <info>$typeId</info>");
405+
$result = $type->addUser($existingUserId, $role);
373406
}
374-
$this->stdErr->writeln("Setting the user's role on the environment type <info>$typeId</info> to: $role");
375-
$result = $access->update(['role' => $role]);
376-
} else {
377-
$this->stdErr->writeln("Adding the user to the environment type: <info>$typeId</info>");
378-
$result = $type->addUser($userId, $role);
407+
$activities = array_merge($activities, $result->getActivities());
379408
}
380-
$activities = array_merge($activities, $result->getActivities());
381409
}
382410
}
383411

384412
// Wait for activities to complete.
385-
if (!$activities) {
386-
$this->redeployWarning();
387-
} elseif ($this->shouldWait($input)) {
413+
if ($activities && $this->shouldWait($input)) {
388414
/** @var \Platformsh\Cli\Service\ActivityMonitor $activityMonitor */
389415
$activityMonitor = $this->getService('activity_monitor');
390416
if (!$activityMonitor->waitMultiple($activities, $project)) {
391417
return 1;
392418
}
419+
} elseif (!$this->config()->get('api.centralized_permissions')) {
420+
$this->redeployWarning();
393421
}
394422

395423
return 0;

0 commit comments

Comments
 (0)