Skip to content

Commit

Permalink
Merge pull request #89 from seegno/pr/85
Browse files Browse the repository at this point in the history
Add OAuth support, improved pagination and transaction resend
  • Loading branch information
nunofgs committed Jul 23, 2015
2 parents 1b3abf4 + 1490bf5 commit bdcf925
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 8 deletions.
43 changes: 43 additions & 0 deletions lib/Bitreserve/BitreserveClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Bitreserve;

use Bitreserve\Exception\AuthenticationRequiredException;
use Bitreserve\Factory\BitreserveClientFactory;
use Bitreserve\HttpClient\HttpClient;
use Bitreserve\HttpClient\HttpClientInterface;
Expand Down Expand Up @@ -254,6 +255,46 @@ public function createToken($login, $password, $description, $otp = null)
return $response->getContent();
}

/**
* Authorize user via Bitreserve Connect.
*
* @param string $code The code parameter that is passed via the Bitreserve Connect callback url.
*
* @return User
*/
public function authorizeUser($code)
{
$clientId = $this->getOption('client_id');
$clientSecret = $this->getOption('client_secret');

if (!$clientId) {
throw new AuthenticationRequiredException('Missing `client_id` option');
}

if (!$clientSecret) {
throw new AuthenticationRequiredException('Missing `client_secret` option');
}

$headers = array(
'Accept' => 'application/x-www-form-urlencoded',
'Authorization' => sprintf('Basic %s', base64_encode(sprintf('%s:%s', $clientId, $clientSecret))),
'Content-Type' => 'application/x-www-form-urlencoded',
);

$parameters = http_build_query(array(
'code' => $code,
'grant_type' => 'authorization_code',
));

$response = $this->getHttpClient()->post(
'/oauth2/token',
$parameters,
array_merge($this->getDefaultHeaders(), $headers)
);

return $this->getUser($response->getContent());
}

/**
* Send a GET request with query parameters.
*
Expand Down Expand Up @@ -347,6 +388,8 @@ public function delete($path, array $parameters = array(), $requestHeaders = arr
/**
* Build the API path that includes the API version.
*
* @param string $path The path to append to the base URL.
*
* @return string
*/
protected function buildPath($path)
Expand Down
20 changes: 19 additions & 1 deletion lib/Bitreserve/Model/Transaction.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public function commit()
public function cancel()
{
if (empty($this->origin['CardId'])) {
throw new LogicException('Origin CardId is missing from this transaction');
throw new LogicException('Origin `CardId` is missing from this transaction');
}

if ('pending' === $this->status) {
Expand All @@ -212,4 +212,22 @@ public function cancel()

$this->updateFields($response->getContent());
}

/**
* {@inheritdoc}
*/
public function resend()
{
if (empty($this->origin['CardId'])) {
throw new LogicException('Origin `CardId` is missing from this transaction');
}

if ('waiting' !== $this->status) {
throw new LogicException(sprintf('This transaction cannot be resent, because the current status is %s', $this->status));
}

$response = $this->client->post(sprintf('/me/cards/%s/transactions/%s/resend', $this->origin['CardId'], $this->id));

$this->updateFields($response->getContent());
}
}
7 changes: 7 additions & 0 deletions lib/Bitreserve/Model/TransactionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,11 @@ public function cancel();
* @return $this
*/
public function commit();

/**
* Resend current transaction.
*
* @return $this
*/
public function resend();
}
21 changes: 18 additions & 3 deletions lib/Bitreserve/Model/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Bitreserve\Model;

use Bitreserve\BitreserveClient;
use Bitreserve\Exception\AuthenticationRequiredException;
use Bitreserve\Paginator\Paginator;

/**
Expand Down Expand Up @@ -36,7 +37,7 @@ class User extends BaseModel implements UserInterface
*
* @var string
*/
protected $fistName;
protected $firstName;

/**
* Last name.
Expand Down Expand Up @@ -284,9 +285,9 @@ public function getTotalBalance()
/**
* {@inheritdoc}
*/
public function getTransactions()
public function getTransactions($limit = null)
{
$pager = new Paginator($this->client, '/me/transactions');
$pager = new Paginator($this->client, '/me/transactions', array(), array(), $limit);
$pager->setModel('Bitreserve\Model\Transaction');

return $pager;
Expand Down Expand Up @@ -321,4 +322,18 @@ public function update(array $params)

return $this;
}

/**
* {@inheritdoc}
*/
public function revokeToken()
{
$bearerToken = $this->client->getOption('bearer');

if (!$bearerToken) {
throw new AuthenticationRequiredException('Missing bearer authorization');
}

return $this->client->get(sprintf('/me/tokens/%s', $bearerToken));
}
}
11 changes: 10 additions & 1 deletion lib/Bitreserve/Model/UserInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,11 @@ public function getTotalBalance();
/**
* Gets all transactions associated with the current user.
*
* @param string $limit Number of transactions.
*
* @return $transactions
*/
public function getTransactions();
public function getTransactions($limit = null);

/**
* Gets user username.
Expand All @@ -155,4 +157,11 @@ public function createCard($label, $currency);
* @return $this
*/
public function update(array $params);

/**
* Revoke current token.
*
* @return Response
*/
public function revokeToken();
}
8 changes: 6 additions & 2 deletions lib/Bitreserve/Paginator/Paginator.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
*/
class Paginator
{
CONST PAGINATOR_LIMIT = 50;

/**
* Bitreserve client.
*
Expand Down Expand Up @@ -61,7 +63,7 @@ class Paginator
*
* @var int
*/
protected $limit = 50;
protected $limit;

/**
* Constructor.
Expand All @@ -70,13 +72,15 @@ class Paginator
* @param string $path Request path.
* @param array $parameters Request parameters.
* @param array $headers Request headers.
* @param int $limit Limit.
*/
public function __construct($client, $path, $parameters = array(), $headers = array())
public function __construct($client, $path, $parameters = array(), $headers = array(), $limit = self::PAGINATOR_LIMIT)
{
$this->client = $client;
$this->path = $path;
$this->parameters = $parameters;
$this->headers = $headers;
$this->limit = $limit;
}

/**
Expand Down
103 changes: 102 additions & 1 deletion test/Bitreserve/Tests/Unit/BitreserveClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,106 @@ public function shouldReturnUser()
$this->assertEquals($data['username'], $user->getUsername());
}

/**
* @test
* @expectedException Bitreserve\Exception\AuthenticationRequiredException
* @expectedExceptionMessage Missing `client_id` option
*/
public function shouldThrowAuthenticationRequiredExceptionOnAuthorizeUserWhenClientIdIsMissing()
{
$client = $this->getBitreserveClientMock();

$client
->expects($this->any())
->method('getOption')
->withConsecutive(array('client_id'), array('client_secret'))
->will($this->returnValue(null))
;

$client->authorizeUser('foobar');
}

/**
* @test
* @expectedException Bitreserve\Exception\AuthenticationRequiredException
* @expectedExceptionMessage Missing `client_secret` option
*/
public function shouldThrowAuthenticationRequiredExceptionOnAuthorizeUserWhenClientSecretIsMissing()
{
$client = $this->getBitreserveClientMock();

$client
->expects($this->any())
->method('getOption')
->withConsecutive(array('client_id'), array('client_secret'))
->will($this->onConsecutiveCalls('qux', null))
;

$client->authorizeUser('foobar');
}

/**
* @test
*/
public function shouldReturnAuthorizedUserWhenResponseReturnsBearerToken()
{
$clientId = 'qux';
$clientSecret = 'waldo';
$code = 'foobar';

$expectedHeaders = array(
'Accept' => 'application/x-www-form-urlencoded',
'Authorization' => sprintf('Basic %s', base64_encode(sprintf('%s:%s', $clientId, $clientSecret))),
'Content-Type' => 'application/x-www-form-urlencoded',
'foo' => 'bar',
);

$expectedParameters = http_build_query(array(
'code' => $code,
'grant_type' => 'authorization_code',
));

$response = $this->getResponseMock('xyzzy');

$httpClient = $this->getHttpClientMock();

$httpClient
->expects($this->once())
->method('post')
->with('/oauth2/token', $expectedParameters, $expectedHeaders)
->will($this->returnValue($response))
;

$client = $this->getBitreserveClientMock(array('getDefaultHeaders', 'getHttpClient', 'getUser'));

$client
->expects($this->any())
->method('getOption')
->withConsecutive(array('client_id'), array('client_secret'))
->will($this->onConsecutiveCalls($clientId, $clientSecret))
;

$client->expects($this->any())
->method('getDefaultHeaders')
->will($this->returnValue(array('foo' => 'bar')))
;

$client
->expects($this->once())
->method('getHttpClient')
->will($this->returnValue($httpClient))
;

$client
->expects($this->once())
->method('getUser')
->with('xyzzy')
->will($this->returnValue('fred'))
;

$this->assertEquals('fred', $client->authorizeUser($code));
}

/**
* @test
*/
Expand Down Expand Up @@ -457,7 +557,8 @@ protected function getBitreserveClientMock(array $methods = array())

return $this->getMockBuilder('Bitreserve\BitreserveClient')
->setMethods($methods)
->getMock();
->getMock()
;
}

/**
Expand Down
40 changes: 40 additions & 0 deletions test/Bitreserve/Tests/Unit/Model/TransactionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ public function shouldThrowAnErrorOnCancelWhenStatusIsPending()
/**
* @test
* @expectedException Bitreserve\Exception\LogicException
* @expectedExceptionMessage Origin `CardId` is missing from this transaction
*/
public function shouldThrowAnErrorOnCancelWhenCardIdIsNotDefined()
{
Expand All @@ -313,6 +314,45 @@ public function shouldThrowAnErrorOnCancelWhenCardIdIsNotDefined()
$transaction->cancel();
}

/**
* @test
* @expectedException Bitreserve\Exception\LogicException
* @expectedExceptionMessage Origin `CardId` is missing from this transaction
*/
public function shouldThrowAnErrorOnResendWhenCardIdIsNotDefined()
{
$data = array(
'id' => 'a97bb994-6e24-4a89-b653-e0a6d0bcf634',
);

$client = $this->getBitreserveClientMock();

$transaction = new Transaction($client, $data);
$transaction->resend();
}

/**
* @test
* @expectedException Bitreserve\Exception\LogicException
* @expectedExceptionMessage This transaction cannot be resent, because the current status is pending
*/
public function shouldThrowAnErrorOnResendWhenStatusIsNotWaiting()
{
$data = array(
'id' => 'a97bb994-6e24-4a89-b653-e0a6d0bcf634',
'origin' => array(
'CardId' => '91380a1f-c6f1-4d81-a204-8b40538c1f0d',
),
'signature' => '1d326154e7a68c64a650af9d3233d77b8a385ce0',
'status' => 'pending',
);

$client = $this->getBitreserveClientMock();

$transaction = new Transaction($client, $data);
$transaction->resend();
}

protected function getModelClass()
{
return 'Bitreserve\Model\Transaction';
Expand Down
Loading

0 comments on commit bdcf925

Please sign in to comment.