Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check the organization /can-create API before creating a project #1500

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 79 additions & 27 deletions src/Command/Project/ProjectCreateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Platformsh\Cli\Exception\ProjectNotFoundException;
use Platformsh\Cli\Util\OsUtil;
use Platformsh\Cli\Util\Sort;
use Platformsh\Client\Model\Organization\Organization;
use Platformsh\Client\Model\Region;
use Platformsh\Client\Model\SetupOptions;
use Platformsh\Client\Model\Subscription\SubscriptionOptions;
Expand Down Expand Up @@ -68,34 +69,12 @@ protected function configure()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$organizationsEnabled = $this->config()->getWithDefault('api.organizations', false);

// Check if the user needs phone verification before creating a project.
$needsVerify = $this->api()->checkUserVerification();
if ($needsVerify['state']) {
if ($needsVerify['type'] === 'phone') {
$this->stdErr->writeln('Phone number verification is required before creating a project.');
if ($input->isInteractive()) {
$this->stdErr->writeln('');
$exitCode = $this->runOtherCommand('auth:verify-phone-number');
if ($exitCode !== 0) {
return 1;
}
$this->stdErr->writeln('');
} else if ($this->config()->has('service.console_url')) {
$this->stdErr->writeln('');
$url = $this->config()->get('service.console_url') . '/-/phone-verify';
$this->stdErr->writeln('Please open the following URL in a browser to verify your phone number:');
$this->stdErr->writeln(sprintf('<info>%s</info>', $url));
return 1;
}
} else {
$this->stdErr->writeln('Verification via Support is required before creating a project.');
if ($this->config()->has('service.console_url')) {
$url = $this->config()->get('service.console_url') . '/support';
$this->stdErr->writeln('Please open the following URL in a browser to open a ticket with Support:');
$this->stdErr->writeln(sprintf('<info>%s</info>', $url));
}
return 1;
}
$needsVerify = !$organizationsEnabled && $this->api()->checkUserVerification();
if ($needsVerify['state'] && !$this->requireVerification($needsVerify['type'], $input)) {
return 1;
}

/** @var \Platformsh\Cli\Service\Git $git */
Expand All @@ -121,6 +100,11 @@ protected function execute(InputInterface $input, OutputInterface $output)
return 1;
}
}

if (!$this->checkCanCreate($organization, $input)) {
return 1;
}

$this->stdErr->writeln('Creating a project under the organization ' . $this->api()->getOrganizationLabel($organization));
$this->stdErr->writeln('');

Expand Down Expand Up @@ -343,6 +327,74 @@ protected function execute(InputInterface $input, OutputInterface $output)
return 0;
}

/**
* Checks the organization /can-create API before creating a project.
*
* This will show whether billing changes or verification are needed.
*
* @param Organization $organization
* @param InputInterface $input
* @return bool
*/
private function checkCanCreate(Organization $organization, InputInterface $input)
{
$canCreate = $this->api()->checkCanCreate($organization);
if ($canCreate['can_create']) {
return true;
}
$this->stdErr->writeln($canCreate['message']);
if ($canCreate['required_action']) {
$consoleUrl = $this->config()->getWithDefault('service.console_url', '');
if ($consoleUrl && $canCreate['required_action']['action'] === 'billing_details') {
$this->stdErr->writeln('');
$this->stdErr->writeln('View or update billing details at:');
$this->stdErr->writeln(sprintf('<info>%s/%s/-/billing</info>', rtrim($consoleUrl, '/'), $organization->name));
return false;
}
if ($canCreate['required_action']['action'] === 'verification') {
$this->stdErr->writeln('');
return $this->requireVerification($canCreate['required_action']['type'], $input);
}
}
return false;
}

/**
* Requires phone or support verification.
*
* @param string $type
* @param InputInterface $input
* @return bool True if verification succeeded, false otherwise.
*/
private function requireVerification($type, InputInterface $input)
{
if ($type === 'phone') {
$this->stdErr->writeln('Phone number verification is required before creating a project.');
if ($input->isInteractive()) {
$this->stdErr->writeln('');
$exitCode = $this->runOtherCommand('auth:verify-phone-number');
if ($exitCode === 0) {
$this->stdErr->writeln('');
return true;
}
} else if ($this->config()->has('service.console_url')) {
$this->stdErr->writeln('');
$url = $this->config()->get('service.console_url') . '/-/phone-verify';
$this->stdErr->writeln('Please open the following URL in a browser to verify your phone number:');
$this->stdErr->writeln(sprintf('<info>%s</info>', $url));
return false;
}
} else {
$this->stdErr->writeln('Verification via Support is required before creating a project.');
if ($this->config()->has('service.console_url')) {
$url = $this->config()->get('service.console_url') . '/support';
$this->stdErr->writeln('Please open the following URL in a browser to open a ticket with Support:');
$this->stdErr->writeln(sprintf('<info>%s</info>', $url));
}
}
return false;
}

/**
* Return a list of plans.
*
Expand Down
10 changes: 10 additions & 0 deletions src/Service/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -1505,6 +1505,16 @@ public function checkUserVerification()
return $this->getHttpClient()->post( '/me/verification')->json();
}

/**
* Returns whether the user is allowed to create a project under an organization.
*
* @return array{'can_create': bool, 'message': string, 'required_action': ?array{'action': string, 'type': string}}
*/
public function checkCanCreate(Organization $org)
{
return $this->getHttpClient()->get( $org->getUri() . '/subscriptions/can-create')->json();
}

/**
* Returns a descriptive label for a referenced user.
*
Expand Down