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

[WIP] Adds machine token commands for 1.0 #1182

Merged
merged 10 commits into from Sep 19, 2016
16 changes: 9 additions & 7 deletions php/Terminus/Commands/MachineTokensCommand.php
Expand Up @@ -2,6 +2,7 @@

namespace Terminus\Commands;

use Terminus\Exceptions\TerminusException;
use Terminus\Session;

/**
Expand Down Expand Up @@ -94,17 +95,18 @@ public function delete($args, $assoc_args) {
'Deleting {name} ...',
array('name' => $name)
);
$response = $machine_token->delete();
if ($response['status_code'] == 200) {
$this->log()->info(
'Deleted {name}!',
array('name' => $name)
);
} else {
try {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How good of you to fix the original, too! 💐

$machine_token->delete();
}
catch (TerminusException $e) {
$this->failure(
'There was an problem deleting the machine token.'
);
}
$this->log()->info(
'Deleted {name}!',
array('name' => $name)
);
}

}
Expand Down
41 changes: 34 additions & 7 deletions php/Terminus/Exceptions/TerminusException.php
Expand Up @@ -12,34 +12,61 @@
*/
class TerminusException extends \Exception {
/**
* @var [array]
* @var array
*/
private $replacements;

private $raw_message;

/**
* Object constructor. Sets context array as replacements property
*
* @param [string] $message Message to send when throwing the exception
* @param [array] $replacements Context array to interpolate into message
* @param [integer] $code Exit code
* @return [TerminusException] $this
* @param string $message Message to send when throwing the exception
* @param array $replacements Context array to interpolate into message
* @param int $code Exit code
*/
public function __construct(
$message = null,
$replacements = array(),
$code = 0
) {
$this->replacements = $replacements;
parent::__construct($message, $code);
$this->raw_message = $message;

parent::__construct($this->interpolateString($message, $replacements), $code);
}

/**
* Returns the replacements context array
*
* @return [array] $this->replacements
* @return array $this->replacements The replacement variables.
*/
public function getReplacements() {
return $this->replacements;
}

/**
* Returns the replacements context array
*
* @return string $this->replacements
*/
public function getRawMessage() {
return $this->raw_message;
}

/**
* Replace the variables into the message string.
*
* @param string $message The raw, uninterpolated message string
* @param array $replacements The values to replace into the message
* @return string
*/
protected function interpolateString($message, $replacements) {
$tr = [];
foreach ($replacements as $key => $val) {
$tr['{' . $key . '}'] = $val;
}
return strtr($message, $tr);
}

}
10 changes: 7 additions & 3 deletions php/Terminus/Models/MachineToken.php
Expand Up @@ -2,6 +2,8 @@

namespace Terminus\Models;

use Terminus\Exceptions\TerminusException;

class MachineToken extends TerminusModel {

/**
Expand All @@ -17,15 +19,17 @@ public function __construct($attributes, array $options = []) {

/**
* Deletes machine token
*
* @return array
* @return void
* @throws \Terminus\Exceptions\TerminusException
*/
public function delete() {
$response = $this->request->request(
"users/{$this->user->id}/machine_tokens/{$this->id}",
['method' => 'delete',]
);
return $response;
if ($response['status_code'] !== 200) {
throw new TerminusException('There was an problem deleting the machine token.');
}
}

}
4 changes: 2 additions & 2 deletions php/Terminus/Runner.php
Expand Up @@ -298,8 +298,8 @@ private function runCommand() {
self::getLogger()->info($return);
}
} catch (\Exception $e) {
if (method_exists($e, 'getReplacements')) {
self::getLogger()->error($e->getMessage(), $e->getReplacements());
if (method_exists($e, 'getRawMessage') && method_exists($e, 'getReplacements')) {
self::getLogger()->error($e->getRawMessage(), $e->getReplacements());
} else {
self::getLogger()->error($e->getMessage());
}
Expand Down
12 changes: 11 additions & 1 deletion src/Commands/MachineToken/DeleteCommand.php
Expand Up @@ -3,6 +3,7 @@
namespace Pantheon\Terminus\Commands\MachineToken;

use Pantheon\Terminus\Commands\TerminusCommand;
use Terminus\Exceptions\TerminusException;

class DeleteCommand extends TerminusCommand
{
Expand All @@ -15,14 +16,23 @@ class DeleteCommand extends TerminusCommand
* Removes a machine token from the logged-in user's account
*
* @name machine-token:delete
* @param string $machine_token_id The ID of the machine token to be deleted
* @throws \Terminus\Exceptions\TerminusException
* @aliases mt:delete
*
* @param machine_token_id The ID of the machine token to be deleted
* @usage terminus machine-token:delete <machine_token_id>
* Removes the given machine token from the user's account
*/
public function delete($machine_token_id) {
$user = $this->session()->getUser();

// Find the token. Will throw an exception if it doesn't exist.
$machine_token = $user->machine_tokens->get($machine_token_id);
Copy link
Contributor Author

@ronan ronan Sep 16, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I'm letting the exception thrown by get() fall through and get caught by the runner. This works fine (and saves a few lines of code) but the Robo runner isn't familiar with our translatable exceptions. That means the output when there is an error here is:

[error] Could not find {model} "{id}"

We have 3 options:

  1. Catch and rethrow here with a regular, untranslatable exception
  2. Override the runner to output a "translated" version of the exception error.
  3. Change TerminusException to do the replacement itself so that getMessage() always returns a valid error message

I favor #3. We'll have to revisit it a bit when we actually start looking at translating error messages, but it should be backwards compatible with the old Terminus runner and forwards compatible with the new one (while not prematurely interpolating error strings).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also favor approach approach 3.

$name = $machine_token->get('device_name');

$this->log()->notice('Deleting {token} ...', ['token' => $name]);
$machine_token->delete();
$this->log()->notice('Deleted {token}!', ['token' => $name]);
}

}
33 changes: 27 additions & 6 deletions src/Commands/MachineToken/ListCommand.php
Expand Up @@ -3,25 +3,46 @@
namespace Pantheon\Terminus\Commands\MachineToken;

use Pantheon\Terminus\Commands\TerminusCommand;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;


class ListCommand extends TerminusCommand
{
/**
* @var boolean True if the command requires the user to be logged in
*/
protected $authorized = true;

/**
* Lists the IDs and labels of machine tokens belonging to the logged-in user
*
* @authorized
*
* @name machine-token:list
* @aliases machine-tokens mt:list mts
*
* @usage terminus machine-token:list
* Lists your user's machine tokens
*
* @return RowsOfFields
*
* @field-labels
* id: ID
* device_name: Device Name
*/
public function listTokens() {
public function listTokens($options = ['format' => 'table', 'fields' => '']) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

format and fields should be global options ala --yes. I can add that once #1179 is merged

$user = $this->session()->getUser();

$machine_tokens = $user->machine_tokens->all();
$data = array();
foreach ($machine_tokens as $id => $machine_token) {
$data[] = array(
'id' => $machine_token->id,
'device_name' => $machine_token->get('device_name'),
);
}

if (count($data) == 0) {
$this->log()->warning('You have no machine tokens.');
}

// Return the output data.
return new RowsOfFields($data);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay!

}

}
23 changes: 23 additions & 0 deletions tests/active_features/machine-token.feature
@@ -0,0 +1,23 @@
Feature: Machine tokens command
In order to manage my devices
As a user
I need to be able to view and delete my machine tokens.

Background: I am logged in
Given I am authenticated

@vcr machine-tokens_list
Scenario: List the machine tokens
When I run "terminus machine-token:list"
Then I should get:
"""
[[machine_token_id]]
"""

@vcr machine-tokens_delete
Scenario: Delete machine token
When I run "terminus machine-token:delete [[machine_token_id]]"
Then I should get:
"""
Deleted [[machine_token_device]]!
"""
@@ -0,0 +1,51 @@
<?php
/**
* @file
* Contains Pantheon\Terminus\UnitTests\Commands\Auth\MachineTokenCommandTest
*/


namespace Pantheon\Terminus\UnitTests\Commands\Auth;


use Pantheon\Terminus\Session\Session;
use Psr\Log\NullLogger;
use Terminus\Collections\MachineTokens;
use Terminus\Models\User;

abstract class MachineTokenCommandTest extends \PHPUnit_Framework_TestCase {
protected $session;
protected $machine_tokens;
protected $user;
protected $logger;
protected $command;

/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*/
protected function setUp()
{
$this->machine_tokens = $this->getMockBuilder(MachineTokens::class)
->disableOriginalConstructor()
->getMock();

$this->user = $this->getMockBuilder(User::class)
->disableOriginalConstructor()
->getMock();
$this->user->machine_tokens = $this->machine_tokens;

$this->session = $this->getMockBuilder(Session::class)
->disableOriginalConstructor()
->getMock();

$this->session->method('getUser')
->willReturn($this->user);

$this->logger = $this->getMockBuilder(NullLogger::class)
->setMethods(array('log'))
->getMock();


}
}