13 Commits
0.1.0 ... 2.0.0

Author SHA1 Message Date
René Preuß
ca57ff1c65 Merge pull request #4 from 1elf-me/patch-1
Update to Laravel 7.x
2020-07-08 06:24:48 +02:00
1elf-me
9207f38f93 Update to Laravel 7.x 2020-06-21 14:08:53 +02:00
René Preuß
c182baab17 Add method to check if a email exists 2019-12-28 18:42:59 +01:00
René Preuß
0e07c295e3 Update composer 2019-12-11 11:41:52 +01:00
René Preuß
940617af2e Fix unit test 2019-12-11 11:37:48 +01:00
René Preuß
f2d064caef Fix oauth token generation 2019-12-09 22:46:23 +01:00
René Preuß
29a46a9ef9 Add oauth token method 2019-12-09 21:58:35 +01:00
René Preuß
553167d108 Fix user registration 2019-12-02 15:26:43 +01:00
René Preuß
918bcd4644 Add methods to change base url 2019-12-02 14:18:58 +01:00
René Preuß
2bd19efb3c Add create user method 2019-11-19 17:32:10 +01:00
René Preuß
b5ad7786f2 Fix parameter type and generate documentation 2019-11-19 17:21:13 +01:00
René Preuß
203dc18766 Add test implementation for charges, documents & payment intents 2019-11-19 17:12:27 +01:00
René Preuß
da1b6b7796 Fix Directory Path 2019-10-16 16:16:59 +02:00
27 changed files with 960 additions and 444 deletions

View File

@@ -155,14 +155,27 @@ BitinflowAccounts::withClientId('abc123')->withToken('abcdef123456')->getAuthedU
public function createCharge(array $parameters) public function createCharge(array $parameters)
public function getCharge(string $id) public function getCharge(string $id)
public function updateCharge(string $id, array $parameters) public function updateCharge(string $id, array $parameters)
public function captureCharge(string $id, array $parameters = []) public function captureCharge(string $id, array $parameters = array ())
``` ```
### CheckoutSessions ### Documents
```php ```php
public function getCheckoutSession(string $id) public function createDocument(array $parameters)
public function createCheckoutSession(array $parameters) public function createDocumentDownloadUrl(string $identifier, CarbonInterface $expiresAt = NULL)
```
### Oauth
```php
public function retrievingToken(string $grantType, array $attributes)
```
### PaymentIntents
```php
public function getPaymentIntent(string $id)
public function createPaymentIntent(array $parameters)
``` ```
### SshKeys ### SshKeys
@@ -177,6 +190,7 @@ public function deleteSshKey(int $id)
```php ```php
public function getAuthedUser() public function getAuthedUser()
public function createUser(array $parameters)
``` ```
[**OAuth Scopes Enums**](https://github.com/ghostzero/bitinflow-accounts/blob/master/src/Enums/Scope.php) [**OAuth Scopes Enums**](https://github.com/ghostzero/bitinflow-accounts/blob/master/src/Enums/Scope.php)
@@ -190,7 +204,7 @@ composer test
``` ```
```shell ```shell
CLIENT_ID=xxxx CLIENT_KEY=yyyy CLIENT_ACCESS_TOKEN=zzzz composer test BASE_URL=xxxx CLIENT_ID=xxxx CLIENT_KEY=yyyy CLIENT_ACCESS_TOKEN=zzzz composer test
``` ```
#### Generate Documentation #### Generate Documentation

View File

@@ -9,9 +9,10 @@ PHP bitinflow Accounts API Client for Laravel 5+
## Table of contents ## Table of contents
1. [Installation](#installation) 1. [Installation](#installation)
2. [Configuration](#configuration) 2. [Event Listener](#event-listener)
3. [Examples](#examples) 3. [Configuration](#configuration)
4. [Documentation](#documentation) 4. [Examples](#examples)
5. [Documentation](#documentation)
6. [Development](#Development) 6. [Development](#Development)
## Installation ## Installation
@@ -161,7 +162,7 @@ composer test
``` ```
```shell ```shell
CLIENT_ID=xxxx CLIENT_KEY=yyyy CLIENT_ACCESS_TOKEN=zzzz composer test BASE_URL=xxxx CLIENT_ID=xxxx CLIENT_KEY=yyyy CLIENT_ACCESS_TOKEN=zzzz composer test
``` ```
#### Generate Documentation #### Generate Documentation

View File

@@ -11,8 +11,8 @@
"require": { "require": {
"php": ">=7.2", "php": ">=7.2",
"ext-json": "*", "ext-json": "*",
"illuminate/support": "^6.0", "illuminate/support": "^7.0",
"illuminate/console": "^6.0", "illuminate/console": "^7.0",
"guzzlehttp/guzzle": "^6.3", "guzzlehttp/guzzle": "^6.3",
"socialiteproviders/manager": "^3.4" "socialiteproviders/manager": "^3.4"
}, },

789
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,4 +4,5 @@ return [
'client_id' => env('BITINFLOW_ACCOUNTS_KEY', ''), 'client_id' => env('BITINFLOW_ACCOUNTS_KEY', ''),
'client_secret' => env('BITINFLOW_ACCOUNTS_SECRET', ''), 'client_secret' => env('BITINFLOW_ACCOUNTS_SECRET', ''),
'redirect_url' => env('BITINFLOW_ACCOUNTS_REDIRECT_URI', ''), 'redirect_url' => env('BITINFLOW_ACCOUNTS_REDIRECT_URI', ''),
'base_url' => env('BITINFLOW_ACCOUNTS_BASE_URI', ''),
]; ];

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace GhostZero\BitinflowAccounts\ApiOperations; namespace GhostZero\BitinflowAccounts\ApiOperations;
use GhostZero\BitinflowAccounts\Helpers\Paginator; use GhostZero\BitinflowAccounts\Helpers\Paginator;
use GhostZero\BitinflowAccounts\Result;
/** /**
* @author René Preuß <rene@preuss.io> * @author René Preuß <rene@preuss.io>
@@ -12,5 +13,5 @@ use GhostZero\BitinflowAccounts\Helpers\Paginator;
trait Delete trait Delete
{ {
abstract public function delete(string $path = '', array $parameters = [], Paginator $paginator = null); abstract public function delete(string $path = '', array $parameters = [], Paginator $paginator = null): Result;
} }

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace GhostZero\BitinflowAccounts\ApiOperations; namespace GhostZero\BitinflowAccounts\ApiOperations;
use GhostZero\BitinflowAccounts\Helpers\Paginator; use GhostZero\BitinflowAccounts\Helpers\Paginator;
use GhostZero\BitinflowAccounts\Result;
/** /**
* @author René Preuß <rene@preuss.io> * @author René Preuß <rene@preuss.io>
@@ -12,5 +13,5 @@ use GhostZero\BitinflowAccounts\Helpers\Paginator;
trait Get trait Get
{ {
abstract public function get(string $path = '', array $parameters = [], Paginator $paginator = null); abstract public function get(string $path = '', array $parameters = [], Paginator $paginator = null): Result;
} }

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace GhostZero\BitinflowAccounts\ApiOperations; namespace GhostZero\BitinflowAccounts\ApiOperations;
use GhostZero\BitinflowAccounts\Helpers\Paginator; use GhostZero\BitinflowAccounts\Helpers\Paginator;
use GhostZero\BitinflowAccounts\Result;
/** /**
* @author René Preuß <rene@preuss.io> * @author René Preuß <rene@preuss.io>
@@ -12,5 +13,5 @@ use GhostZero\BitinflowAccounts\Helpers\Paginator;
trait Post trait Post
{ {
abstract public function post(string $path = '', array $parameters = [], Paginator $paginator = null); abstract public function post(string $path = '', array $parameters = [], Paginator $paginator = null): Result;
} }

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace GhostZero\BitinflowAccounts\ApiOperations; namespace GhostZero\BitinflowAccounts\ApiOperations;
use GhostZero\BitinflowAccounts\Helpers\Paginator; use GhostZero\BitinflowAccounts\Helpers\Paginator;
use GhostZero\BitinflowAccounts\Result;
/** /**
* @author René Preuß <rene@preuss.io> * @author René Preuß <rene@preuss.io>
@@ -12,5 +13,5 @@ use GhostZero\BitinflowAccounts\Helpers\Paginator;
trait Put trait Put
{ {
abstract public function put(string $path = '', array $parameters = [], Paginator $paginator = null); abstract public function put(string $path = '', array $parameters = [], Paginator $paginator = null): Result;
} }

View File

@@ -2,6 +2,7 @@
namespace GhostZero\BitinflowAccounts; namespace GhostZero\BitinflowAccounts;
use GhostZero\BitinflowAccounts\ApiOperations;
use GhostZero\BitinflowAccounts\Exceptions\RequestRequiresAuthenticationException; use GhostZero\BitinflowAccounts\Exceptions\RequestRequiresAuthenticationException;
use GhostZero\BitinflowAccounts\Exceptions\RequestRequiresClientIdException; use GhostZero\BitinflowAccounts\Exceptions\RequestRequiresClientIdException;
use GhostZero\BitinflowAccounts\Exceptions\RequestRequiresRedirectUriException; use GhostZero\BitinflowAccounts\Exceptions\RequestRequiresRedirectUriException;
@@ -18,12 +19,18 @@ class BitinflowAccounts
{ {
use Traits\ChargesTrait; use Traits\ChargesTrait;
use Traits\CheckoutSessionsTrait; use Traits\DocumentsTrait;
use Traits\OauthTrait;
use Traits\PaymentIntentsTrait;
use Traits\SshKeysTrait; use Traits\SshKeysTrait;
use Traits\UsersTrait; use Traits\UsersTrait;
const BASE_URI = 'https://accounts.bitinflow.com/api/'; use ApiOperations\Delete;
const OAUTH_BASE_URI = 'https://accounts.bitinflow.com/api/'; use ApiOperations\Get;
use ApiOperations\Post;
use ApiOperations\Put;
private static $baseUrl = 'https://accounts.bitinflow.com/api/';
/** /**
* Guzzle is used to make http requests. * Guzzle is used to make http requests.
@@ -75,11 +82,24 @@ class BitinflowAccounts
if ($redirectUri = config('bitinflow-accounts-api.redirect_url')) { if ($redirectUri = config('bitinflow-accounts-api.redirect_url')) {
$this->setRedirectUri($redirectUri); $this->setRedirectUri($redirectUri);
} }
if ($redirectUri = config('bitinflow-accounts-api.base_url')) {
self::setBaseUrl($redirectUri);
}
$this->client = new Client([ $this->client = new Client([
'base_uri' => self::BASE_URI, 'base_uri' => self::$baseUrl,
]); ]);
} }
/**
* @param string $baseUrl
*
* @internal only for internal and debug purposes.
*/
public static function setBaseUrl(string $baseUrl): void
{
self::$baseUrl = $baseUrl;
}
/** /**
* Get client id. * Get client id.
* @return string * @return string
@@ -97,7 +117,7 @@ class BitinflowAccounts
/** /**
* Set client id. * Set client id.
* *
* @param string $clientId bitinflow Accounts client id * @param string $clientId bitinflow Accounts client id
* *
* @return void * @return void
*/ */
@@ -109,7 +129,7 @@ class BitinflowAccounts
/** /**
* Fluid client id setter. * Fluid client id setter.
* *
* @param string $clientId bitinflow Accounts client id. * @param string $clientId bitinflow Accounts client id.
* *
* @return self * @return self
*/ */
@@ -137,7 +157,7 @@ class BitinflowAccounts
/** /**
* Set client secret. * Set client secret.
* *
* @param string $clientSecret bitinflow Accounts client secret * @param string $clientSecret bitinflow Accounts client secret
* *
* @return void * @return void
*/ */
@@ -149,7 +169,7 @@ class BitinflowAccounts
/** /**
* Fluid client secret setter. * Fluid client secret setter.
* *
* @param string $clientSecret bitinflow Accounts client secret * @param string $clientSecret bitinflow Accounts client secret
* *
* @return self * @return self
*/ */
@@ -177,7 +197,7 @@ class BitinflowAccounts
/** /**
* Set redirect url. * Set redirect url.
* *
* @param string $redirectUri * @param string $redirectUri
* *
* @return void * @return void
*/ */
@@ -189,7 +209,7 @@ class BitinflowAccounts
/** /**
* Fluid redirect url setter. * Fluid redirect url setter.
* *
* @param string $redirectUri * @param string $redirectUri
* *
* @return self * @return self
*/ */
@@ -218,7 +238,7 @@ class BitinflowAccounts
/** /**
* Set OAuth token. * Set OAuth token.
* *
* @param string $token bitinflow Accounts OAuth token * @param string $token bitinflow Accounts OAuth token
* *
* @return void * @return void
*/ */
@@ -230,7 +250,7 @@ class BitinflowAccounts
/** /**
* Fluid OAuth token setter. * Fluid OAuth token setter.
* *
* @param string $token bitinflow Accounts OAuth token * @param string $token bitinflow Accounts OAuth token
* *
* @return self * @return self
*/ */
@@ -250,7 +270,7 @@ class BitinflowAccounts
* @throws GuzzleException * @throws GuzzleException
* @throws RequestRequiresClientIdException * @throws RequestRequiresClientIdException
*/ */
public function get(string $path = '', array $parameters = [], Paginator $paginator = null) public function get(string $path = '', array $parameters = [], Paginator $paginator = null): Result
{ {
return $this->query('GET', $path, $parameters, $paginator); return $this->query('GET', $path, $parameters, $paginator);
} }
@@ -264,7 +284,7 @@ class BitinflowAccounts
* @throws GuzzleException * @throws GuzzleException
* @throws RequestRequiresClientIdException * @throws RequestRequiresClientIdException
*/ */
public function post(string $path = '', array $parameters = [], Paginator $paginator = null) public function post(string $path = '', array $parameters = [], Paginator $paginator = null): Result
{ {
return $this->query('POST', $path, $parameters, $paginator); return $this->query('POST', $path, $parameters, $paginator);
} }
@@ -278,7 +298,7 @@ class BitinflowAccounts
* @throws GuzzleException * @throws GuzzleException
* @throws RequestRequiresClientIdException * @throws RequestRequiresClientIdException
*/ */
public function delete(string $path = '', array $parameters = [], Paginator $paginator = null) public function delete(string $path = '', array $parameters = [], Paginator $paginator = null): Result
{ {
return $this->query('DELETE', $path, $parameters, $paginator); return $this->query('DELETE', $path, $parameters, $paginator);
} }
@@ -292,7 +312,7 @@ class BitinflowAccounts
* @throws GuzzleException * @throws GuzzleException
* @throws RequestRequiresClientIdException * @throws RequestRequiresClientIdException
*/ */
public function put(string $path = '', array $parameters = [], Paginator $paginator = null) public function put(string $path = '', array $parameters = [], Paginator $paginator = null): Result
{ {
return $this->query('PUT', $path, $parameters, $paginator); return $this->query('PUT', $path, $parameters, $paginator);
} }
@@ -306,7 +326,7 @@ class BitinflowAccounts
* @throws GuzzleException * @throws GuzzleException
* @throws RequestRequiresClientIdException * @throws RequestRequiresClientIdException
*/ */
public function json(string $method, string $path = '', array $body = null) public function json(string $method, string $path = '', array $body = null): Result
{ {
if ($body) { if ($body) {
$body = json_encode(['data' => $body]); $body = json_encode(['data' => $body]);
@@ -318,11 +338,11 @@ class BitinflowAccounts
/** /**
* Build query & execute. * Build query & execute.
* *
* @param string $method HTTP method * @param string $method HTTP method
* @param string $path Query path * @param string $path Query path
* @param array $parameters Query parameters * @param array $parameters Query parameters
* @param Paginator $paginator Paginator object * @param Paginator $paginator Paginator object
* @param mixed|null $jsonBody JSON data * @param mixed|null $jsonBody JSON data
* *
* @return Result Result object * @return Result Result object
* @throws GuzzleException * @throws GuzzleException
@@ -337,7 +357,7 @@ class BitinflowAccounts
$response = $this->client->request($method, $path, [ $response = $this->client->request($method, $path, [
'headers' => $this->buildHeaders($jsonBody ? true : false), 'headers' => $this->buildHeaders($jsonBody ? true : false),
'query' => $this->buildQuery($parameters), 'query' => $this->buildQuery($parameters),
'json' => $jsonBody ? $jsonBody : null, 'json' => $jsonBody ?: null,
]); ]);
$result = new Result($response, null, $paginator); $result = new Result($response, null, $paginator);
} catch (RequestException $exception) { } catch (RequestException $exception) {
@@ -351,7 +371,7 @@ class BitinflowAccounts
/** /**
* Build query with support for multiple smae first-dimension keys. * Build query with support for multiple smae first-dimension keys.
* *
* @param array $query * @param array $query
* *
* @return string * @return string
*/ */
@@ -371,7 +391,7 @@ class BitinflowAccounts
/** /**
* Build headers for request. * Build headers for request.
* *
* @param bool $json Body is JSON * @param bool $json Body is JSON
* *
* @return array * @return array
* @throws RequestRequiresClientIdException * @throws RequestRequiresClientIdException
@@ -380,13 +400,13 @@ class BitinflowAccounts
{ {
$headers = [ $headers = [
'Client-ID' => $this->getClientId(), 'Client-ID' => $this->getClientId(),
'Accept' => 'application/json',
]; ];
if ($this->token) { if ($this->token) {
$headers['Authorization'] = 'Bearer ' . $this->token; $headers['Authorization'] = 'Bearer ' . $this->token;
} }
if ($json) { if ($json) {
$headers['Content-Type'] = 'application/json'; $headers['Content-Type'] = 'application/json';
$headers['Accept'] = 'application/json';
} }
return $headers; return $headers;

View File

@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace GhostZero\BitinflowAccounts\Enums;
/**
* @author René Preuß <rene@preuss.io>
*/
class DocumentType
{
// Read authorized user´s email address.
public const TYPE_PDF_INVOICE = 'pdf.invoice';
// Manage a authorized user object.
public const TYPE_PDF_ORDER = 'pdf.order';
}

View File

@@ -15,24 +15,26 @@ class Scope
*/ */
// Deprecated scope. // Deprecated scope.
const API = 'api'; public const API = 'api';
// Read nonpublic user information, including email address. // Read nonpublic user information, including email address.
const READ_USER = 'read_user'; public const READ_USER = 'read_user';
/* /*
* v1 API * v1 API
*/ */
// Read authorized user´s email address. // Read authorized user´s email address.
const USERS_READ_EMAIL = 'users:read:email'; public const USERS_READ_EMAIL = 'users:read:email';
// Manage a authorized user object. // Manage a authorized user object.
const USERS_EDIT = 'users:edit'; public const USERS_EDIT = 'users:edit';
public const USERS_CREATE = 'users:create';
// Read authorized user´s transactions. // Read authorized user´s transactions.
const TRANSACTIONS_READ = 'transactions:read'; public const TRANSACTIONS_READ = 'transactions:read';
// Create a new charge for the authorized user. // Create a new charge for the authorized user.
const CHARGES_CREATE = 'charges:create'; public const CHARGES_CREATE = 'charges:create';
} }

View File

@@ -17,7 +17,7 @@ class BitinflowAccountsServiceProvider extends ServiceProvider
public function boot() public function boot()
{ {
$this->publishes([ $this->publishes([
dirname(__DIR__) . '/../config/bitinflow-accounts-api.php' => config_path('bitinflow-accounts-api.php'), dirname(__DIR__) . '/../../../config/bitinflow-accounts-api.php' => config_path('bitinflow-accounts-api.php'),
], 'config'); ], 'config');
} }
@@ -28,7 +28,7 @@ class BitinflowAccountsServiceProvider extends ServiceProvider
public function register() public function register()
{ {
$this->mergeConfigFrom( $this->mergeConfigFrom(
dirname(__DIR__) . '/../config/bitinflow-accounts-api.php', 'bitinflow-accounts-api' dirname(__DIR__) . '/../../../config/bitinflow-accounts-api.php', 'bitinflow-accounts-api'
); );
$this->app->singleton(BitinflowAccounts::class, function () { $this->app->singleton(BitinflowAccounts::class, function () {
return new BitinflowAccounts; return new BitinflowAccounts;
@@ -43,4 +43,4 @@ class BitinflowAccountsServiceProvider extends ServiceProvider
{ {
return [BitinflowAccounts::class]; return [BitinflowAccounts::class];
} }
} }

View File

@@ -6,7 +6,7 @@ namespace GhostZero\BitinflowAccounts;
use Exception; use Exception;
use GhostZero\BitinflowAccounts\Helpers\Paginator; use GhostZero\BitinflowAccounts\Helpers\Paginator;
use GuzzleHttp\Psr7\Response; use Psr\Http\Message\ResponseInterface;
use stdClass; use stdClass;
@@ -60,7 +60,7 @@ class Result
/** /**
* Original Guzzle HTTP Response. * Original Guzzle HTTP Response.
* @var Response * @var ResponseInterface|null
*/ */
public $response; public $response;
@@ -73,17 +73,17 @@ class Result
/** /**
* Constructor, * Constructor,
* *
* @param Response $response HTTP response * @param ResponseInterface|null $response HTTP response
* @param Exception|mixed $exception Exception, if present * @param Exception|mixed $exception Exception, if present
* @param null|Paginator $paginator Paginator, if present * @param null|Paginator $paginator Paginator, if present
*/ */
public function __construct(Response $response, Exception $exception = null, Paginator $paginator = null) public function __construct(?ResponseInterface $response, Exception $exception = null, Paginator $paginator = null)
{ {
$this->response = $response; $this->response = $response;
$this->success = $exception === null; $this->success = $exception === null;
$this->exception = $exception; $this->exception = $exception;
$this->status = $response->getStatusCode(); $this->status = $response ? $response->getStatusCode() : 500;
$jsonResponse = @json_decode($response->getBody()->getContents()); $jsonResponse = $response ? @json_decode($response->getBody()->getContents(), false) : null;
if ($jsonResponse !== null) { if ($jsonResponse !== null) {
$this->setProperty($jsonResponse, 'data'); $this->setProperty($jsonResponse, 'data');
$this->setProperty($jsonResponse, 'total'); $this->setProperty($jsonResponse, 'total');
@@ -99,10 +99,10 @@ class Result
* @param string $responseProperty Response property name * @param string $responseProperty Response property name
* @param string|null $attribute Class property name * @param string|null $attribute Class property name
*/ */
private function setProperty(stdClass $jsonResponse, string $responseProperty, string $attribute = null) private function setProperty(stdClass $jsonResponse, string $responseProperty, string $attribute = null): void
{ {
$classAttribute = $attribute ?? $responseProperty; $classAttribute = $attribute ?? $responseProperty;
if (!empty($jsonResponse) && property_exists($jsonResponse, $responseProperty)) { if ($jsonResponse !== null && property_exists($jsonResponse, $responseProperty)) {
$this->{$classAttribute} = $jsonResponse->{$responseProperty}; $this->{$classAttribute} = $jsonResponse->{$responseProperty};
} elseif ($responseProperty === 'data') { } elseif ($responseProperty === 'data') {
$this->{$classAttribute} = $jsonResponse; $this->{$classAttribute} = $jsonResponse;
@@ -174,7 +174,7 @@ class Result
* Set the Paginator to fetch the first set of results. * Set the Paginator to fetch the first set of results.
* @return null|Paginator * @return null|Paginator
*/ */
public function first() public function first(): ?Paginator
{ {
return $this->paginator !== null ? $this->paginator->first() : null; return $this->paginator !== null ? $this->paginator->first() : null;
} }
@@ -183,7 +183,7 @@ class Result
* Set the Paginator to fetch the next set of results. * Set the Paginator to fetch the next set of results.
* @return null|Paginator * @return null|Paginator
*/ */
public function next() public function next(): ?Paginator
{ {
return $this->paginator !== null ? $this->paginator->next() : null; return $this->paginator !== null ? $this->paginator->next() : null;
} }
@@ -192,7 +192,7 @@ class Result
* Set the Paginator to fetch the last set of results. * Set the Paginator to fetch the last set of results.
* @return null|Paginator * @return null|Paginator
*/ */
public function back() public function back(): ?Paginator
{ {
return $this->paginator !== null ? $this->paginator->back() : null; return $this->paginator !== null ? $this->paginator->back() : null;
} }
@@ -200,7 +200,7 @@ class Result
/** /**
* Get rate limit information. * Get rate limit information.
* *
* @param string|null $key Get defined index * @param string|null $key Get defined index
* *
* @return string|array|null * @return string|array|null
*/ */
@@ -224,8 +224,8 @@ class Result
/** /**
* Insert users in data response. * Insert users in data response.
* *
* @param string $identifierAttribute Attribute to identify the users * @param string $identifierAttribute Attribute to identify the users
* @param string $insertTo Data index to insert user data * @param string $insertTo Data index to insert user data
* *
* @return self * @return self
*/ */
@@ -235,7 +235,7 @@ class Result
$userIds = collect($data)->map(function ($item) use ($identifierAttribute) { $userIds = collect($data)->map(function ($item) use ($identifierAttribute) {
return $item->{$identifierAttribute}; return $item->{$identifierAttribute};
})->toArray(); })->toArray();
if (count($userIds) == 0) { if (count($userIds) === 0) {
return $this; return $this;
} }
$users = collect($this->bitinflow->getUsersByIds($userIds)->data); $users = collect($this->bitinflow->getUsersByIds($userIds)->data);

View File

@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace GhostZero\BitinflowAccounts\Traits;
use Carbon\CarbonInterface;
use GhostZero\BitinflowAccounts\ApiOperations\Get;
use GhostZero\BitinflowAccounts\ApiOperations\Post;
use GhostZero\BitinflowAccounts\Result;
/**
* @author René Preuß <rene@preuss.io>
*/
trait DocumentsTrait
{
use Get, Post;
/**
* Create a Documents object
*
* @param array $parameters
*
* @return Result
*/
public function createDocument(array $parameters): Result
{
return $this->post('documents', $parameters);
}
/**
* Create a Documents download url
*
* @param string $identifier
* @param CarbonInterface|null $expiresAt
*
* @return Result
*/
public function createDocumentDownloadUrl(string $identifier, ?CarbonInterface $expiresAt = null): Result
{
return $this->post("documents/$identifier/download-url", [
'expires_at' => $expiresAt
? $expiresAt->toDateTimeString()
: now()->addHour()->toDateTimeString(),
]);
}
}

View File

@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace GhostZero\BitinflowAccounts\Traits;
use GhostZero\BitinflowAccounts\Result;
use GuzzleHttp\Exception\RequestException;
/**
* @author René Preuß <rene@preuss.io>
*/
trait OauthTrait
{
/**
* Retrieving a oauth token using a given grant type.
*
* @param string $grantType
* @param array $attributes
*
* @return Result
*/
public function retrievingToken(string $grantType, array $attributes): Result
{
try {
$response = $this->client->request('POST', '/oauth/token', [
'form_params' => $attributes + [
'grant_type' => $grantType,
'client_id' => $this->getClientId(),
'client_secret' => $this->getClientSecret(),
],
]);
$result = new Result($response, null);
} catch (RequestException $exception) {
$result = new Result($exception->getResponse(), $exception);
}
$result->bitinflow = $this;
return $result;
}
}

View File

@@ -11,32 +11,32 @@ use GhostZero\BitinflowAccounts\Result;
/** /**
* @author René Preuß <rene@preuss.io> * @author René Preuß <rene@preuss.io>
*/ */
trait CheckoutSessionsTrait trait PaymentIntentsTrait
{ {
use Get, Post; use Get, Post;
/** /**
* Get a Session object * Get a Payment Intent object
* *
* @param string $id * @param string $id
* *
* @return Result Result object * @return Result Result object
*/ */
public function getCheckoutSession(string $id): Result public function getPaymentIntent(string $id): Result
{ {
return $this->get("checkout/sessions/$id"); return $this->get("payment-intents/$id");
} }
/** /**
* Create a Session object * Create a Payment Intent object
* *
* @param array $parameters * @param array $parameters
* *
* @return Result * @return Result
*/ */
public function createCheckoutSession(array $parameters): Result public function createPaymentIntent(array $parameters): Result
{ {
return $this->post('payments/sessions', $parameters); return $this->post('payment-intents', $parameters);
} }
} }

View File

@@ -27,7 +27,7 @@ trait SshKeysTrait
} }
/** /**
* Get currently authed user with Bearer Token * Creates ssh key for the currently authed user
* *
* @param string $publicKey * @param string $publicKey
* @param string|null $name * @param string|null $name
@@ -43,7 +43,7 @@ trait SshKeysTrait
} }
/** /**
* Get currently authed user with Bearer Token * Deletes a given ssh key for the currently authed user
* *
* @param int $id * @param int $id
* *

View File

@@ -18,6 +18,32 @@ trait UsersTrait
*/ */
public function getAuthedUser(): Result public function getAuthedUser(): Result
{ {
return $this->get('users/me', [], null); return $this->get('users/me');
} }
}
/**
* Creates a new user on behalf of the current user.
*
* @param array $parameters
*
* @return Result
*/
public function createUser(array $parameters): Result
{
return $this->post('v2/users', $parameters);
}
/**
* Checks if the given email exists.
*
* @param string $email
*
* @return Result
*/
public function isEmailExisting(string $email): Result
{
return $this->post('v2/users/check-email', [
'email' => $email,
]);
}
}

View File

@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace GhostZero\BitinflowAccounts\Tests;
use GhostZero\BitinflowAccounts\Tests\TestCases\ApiTestCase;
/**
* @author René Preuß <rene@preuss.io>
*/
class ApiChargesTest extends ApiTestCase
{
public function testCaptureWithoutCapture(): void
{
$this->getClient()->withToken($this->getToken());
$result = $this->getClient()->createCharge([
'amount' => 2000,
'currency' => 'usd',
'source' => 'tok_visa',
'description' => 'Charge for jenny.rosen@example.com',
]);
$this->registerResult($result);
$this->assertTrue($result->success());
$this->assertArrayHasKey('id', $result->data());
$this->assertEquals(2000, $result->data()->amount);
$this->assertTrue($result->data()->captured);
}
public function testChargeWithCapture(): void
{
$this->getClient()->withToken($this->getToken());
$result = $this->getClient()->createCharge([
'amount' => 2000,
'currency' => 'usd',
'source' => 'tok_visa',
'description' => 'Charge for jenny.rosen@example.com',
'capture' => false, // default is true for instant capture
'metadata' => [
'foo' => 'bar',
],
'receipt_email' => 'rene+unittest@bitinflow.com',
]);
$this->registerResult($result);
$this->assertTrue($result->success());
$this->assertArrayHasKey('id', $result->data());
$this->assertEquals(2000, $result->data()->amount);
$this->assertFalse($result->data()->captured);
$charge = $result->data();
$result = $this->getClient()->captureCharge($charge->id);
$this->registerResult($result);
$this->assertTrue($result->success());
$this->assertArrayHasKey('id', $result->data());
$this->assertEquals(2000, $result->data()->amount);
$this->assertTrue($result->data()->captured);
}
}

View File

@@ -0,0 +1,87 @@
<?php
declare(strict_types=1);
namespace GhostZero\BitinflowAccounts\Tests;
use GhostZero\BitinflowAccounts\Enums\DocumentType;
use GhostZero\BitinflowAccounts\Tests\TestCases\ApiTestCase;
/**
* @author René Preuß <rene@preuss.io>
*/
class ApiDocumentsTest extends ApiTestCase
{
public function testCreateDocument(): void
{
$this->getClient()->withToken($this->getToken());
$result = $this->getClient()->createDocument([
'branding' => [
'primary_color' => '#8284df',
'watermark_url' => 'https://fbs.streamkit.gg/img/pdf/wm.png',
'logo_url' => 'https://fbs.streamkit.gg/img/pdf/logo_dark_small.png',
],
'locale' => 'de',
'type' => DocumentType::TYPE_PDF_INVOICE,
'data' => $this->createDummyInvoiceData(),
'receipt_email' => 'rene+unittest@bitinflow.com',
]);
$this->registerResult($result);
$this->assertTrue($result->success());
$this->assertArrayHasKey('id', $result->data());
$this->assertArrayHasKey('download_url', $result->data());
$this->assertEquals(
'rene+unittest@bitinflow.com',
$result->data()->receipt_email
);
}
public function testGenerateDocumentStoragePath(): void
{
$this->getClient()->withToken($this->getToken());
$expiresAt = now()->addHours(2);
$result = $this->getClient()->createDocumentDownloadUrl('1', $expiresAt);
$this->registerResult($result);
$this->assertTrue($result->success());
$this->assertArrayHasKey('download_url', $result->data());
$this->assertEquals(
$expiresAt->toDateTimeString(),
$result->data()->expires_at
);
}
private function createDummyInvoiceData(): array
{
return [
'id' => 'FBS-IN-1337',
'customer' => [
'name' => 'GhostZero',
'email' => 'rene@preuss.io',
'address' => [
'Example Street 123',
'50733 Cologne',
'GERMANY',
],
],
'line_items' => [
[
'name' => 'T-shirt',
'description' => 'Comfortable cotton t-shirt',
'unit' => 'T-shirt', // optional unit name
'amount' => 1500,
'currency' => 'usd',
'quantity' => 2,
],
],
'legal_notice' => 'According to the German §19 UStG no sales tax is calculated. However, the product is a digital good delivered via Internet we generally offer no refunds. The delivery date corresponds to the invoice date.',
'already_paid' => true,
'created_at' => now()->format('d.m.Y'),
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace GhostZero\BitinflowAccounts\Tests;
use GhostZero\BitinflowAccounts\Tests\TestCases\ApiTestCase;
/**
* @author René Preuß <rene@preuss.io>
*/
class ApiOauthTest extends ApiTestCase
{
public function testGetOauthToken(): void
{
$this->registerResult($result = $this->getClient()->retrievingToken('client_credentials', [
'scope' => '',
]));
$this->assertTrue($result->success());
$this->assertNotEmpty($result->data()->access_token);
}
}

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace GhostZero\BitinflowAccounts\Tests;
use GhostZero\BitinflowAccounts\Tests\TestCases\ApiTestCase;
/**
* @author René Preuß <rene@preuss.io>
*/
class ApiPaymentIntentsTest extends ApiTestCase
{
private $paymentIntent;
public function testCreatePaymentIntent(): void
{
$this->getClient()->withToken($this->getToken());
$result = $this->getClient()->createPaymentIntent([
'payment_method_types' => ['card'],
'amount' => 1000,
'currency' => 'usd',
'application_fee_amount' => 123,
]);
$this->registerResult($result);
$this->assertTrue($result->success());
$this->assertArrayHasKey('id', $result->data());
$this->assertArrayHasKey('redirect_url', $result->data());
$this->assertEquals(1000, $result->data()->amount);
// use this payment intent for our next tests
$this->paymentIntent = $result->data();
}
public function testGetPaymentIntent(): void
{
$this->getClient()->withToken($this->getToken());
$result = $this->getClient()->getPaymentIntent($this->paymentIntent->id);
$this->registerResult($result);
$this->assertTrue($result->success());
$this->assertArrayHasKey('id', $result->data());
$this->assertEquals(1000, $result->data()->amount);
}
}

View File

@@ -13,15 +13,14 @@ use GhostZero\BitinflowAccounts\Tests\TestCases\ApiTestCase;
class ApiSshKeysTest extends ApiTestCase class ApiSshKeysTest extends ApiTestCase
{ {
public function testGetSshKeyByUserId() public function testGetSshKeyByUserId(): void
{ {
$this->registerResult($result = $this->getClient()->getSshKeysByUserId(38)); $this->registerResult($result = $this->getClient()->getSshKeysByUserId(38));
$this->assertInstanceOf(Result::class, $result);
$this->assertEquals('rene.preuss@check24.de', $result->shift()->name); $this->assertEquals('rene.preuss@check24.de', $result->shift()->name);
$this->assertGreaterThanOrEqual(2, $result->count()); $this->assertGreaterThanOrEqual(2, $result->count());
} }
public function testSshKeyManagement() public function testSshKeyManagement(): void
{ {
$customName = 'Hello World!'; $customName = 'Hello World!';
$publicKey = 'ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3H7sYVrVCwwYIuRm3on3S9n/BCd2mBJrgCk6xTerbNmt0RyUZ+RtGsK6UYkgnRR2WWq9/Pv2s3RXJXPxbsIEYmKCcTdLUvDk56x9385cIVUX4w016mpe/8lyu+mIdqWYKsJMoab0oReCDX8Y9qBcaffDh8AgmYVN+86gXgoP1ITe9BDYrFiR6U571VyLDVN3OYOYPMF3/L9f0knMfM0T4LrS8oi6faVBCxZHRoBGtGmsTBkE0KwplYQFN2aa4Mxab+rTUFmJr3LYEcJF0J8wNJ3eEDFNOR0254jrjbGGAXGsc+cxJoNzech+GBkRMKMpNU0lds6VxP0ZB25VfzjEmQ== René Preuß'; $publicKey = 'ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3H7sYVrVCwwYIuRm3on3S9n/BCd2mBJrgCk6xTerbNmt0RyUZ+RtGsK6UYkgnRR2WWq9/Pv2s3RXJXPxbsIEYmKCcTdLUvDk56x9385cIVUX4w016mpe/8lyu+mIdqWYKsJMoab0oReCDX8Y9qBcaffDh8AgmYVN+86gXgoP1ITe9BDYrFiR6U571VyLDVN3OYOYPMF3/L9f0knMfM0T4LrS8oi6faVBCxZHRoBGtGmsTBkE0KwplYQFN2aa4Mxab+rTUFmJr3LYEcJF0J8wNJ3eEDFNOR0254jrjbGGAXGsc+cxJoNzech+GBkRMKMpNU0lds6VxP0ZB25VfzjEmQ== René Preuß';

View File

@@ -4,8 +4,9 @@ declare(strict_types=1);
namespace GhostZero\BitinflowAccounts\Tests; namespace GhostZero\BitinflowAccounts\Tests;
use GhostZero\BitinflowAccounts\Result; use GhostZero\BitinflowAccounts\Enums\Scope;
use GhostZero\BitinflowAccounts\Tests\TestCases\ApiTestCase; use GhostZero\BitinflowAccounts\Tests\TestCases\ApiTestCase;
use Illuminate\Support\Str;
/** /**
* @author René Preuß <rene@preuss.io> * @author René Preuß <rene@preuss.io>
@@ -13,11 +14,51 @@ use GhostZero\BitinflowAccounts\Tests\TestCases\ApiTestCase;
class ApiUsersTest extends ApiTestCase class ApiUsersTest extends ApiTestCase
{ {
public function testGetAuthedUser() public function testGetAuthedUser(): void
{ {
$this->getClient()->withToken($this->getToken()); $this->getClient()->withToken($this->getToken());
$this->registerResult($result = $this->getClient()->getAuthedUser()); $this->registerResult($result = $this->getClient()->getAuthedUser());
$this->assertInstanceOf(Result::class, $result); $this->assertTrue($result->success());
$this->assertEquals('rene@preuss.io', $result->data()->email); $this->assertEquals('rene@preuss.io', $result->data()->email);
} }
}
public function testEmailAvailabilityNonExisting(): void
{
$this->getClient()->withToken($this->getToken());
$this->registerResult($result = $this->getClient()->isEmailExisting('rene+non-existing@preuss.io'));
$this->assertTrue(!$result->success());
}
public function testEmailAvailabilityExisting(): void
{
$this->getClient()->withToken($this->getToken());
$this->registerResult($result = $this->getClient()->isEmailExisting('rene@preuss.io'));
$this->assertTrue($result->success());
}
public function testCreateUser(): void
{
$testEmailAddress = $this->createRandomEmail();
$this->registerResult($result = $this->getClient()->retrievingToken('client_credentials', [
'scope' => Scope::USERS_CREATE,
]));
$this->getClient()->withToken($result->data()->access_token);
$this->registerResult($result = $this->getClient()->createUser([
'first_name' => 'René',
'last_name' => 'Preuß',
'email' => $testEmailAddress,
'password' => 'Password1',
'password_confirmation' => 'Password1',
'terms_accepted' => true,
]));
$this->assertTrue($result->success(), $result->error());
$this->assertEquals($testEmailAddress, $result->data()->email);
}
private function createRandomEmail(): string
{
return sprintf('rene+unittest.%s@bitinflow.com', Str::random());
}
}

View File

@@ -14,12 +14,12 @@ use GhostZero\BitinflowAccounts\Tests\TestCases\TestCase;
class ServiceInstantiationTest extends TestCase class ServiceInstantiationTest extends TestCase
{ {
public function testInstance() public function testInstance(): void
{ {
$this->assertInstanceOf(BitinflowAccounts::class, app(BitinflowAccounts::class)); $this->assertInstanceOf(BitinflowAccounts::class, app(BitinflowAccounts::class));
} }
public function testFacade() public function testFacade(): void
{ {
$this->assertInstanceOf(BitinflowAccounts::class, BitinflowAccountsFacade::getFacadeRoot()); $this->assertInstanceOf(BitinflowAccounts::class, BitinflowAccountsFacade::getFacadeRoot());
} }

View File

@@ -18,6 +18,11 @@ abstract class ApiTestCase extends TestCase
protected function setUp(): void protected function setUp(): void
{ {
parent::setUp(); parent::setUp();
if ($this->getBaseUrl()) {
BitinflowAccounts::setBaseUrl($this->getBaseUrl());
}
if (!$this->getClientId()) { if (!$this->getClientId()) {
$this->markTestSkipped('No Client-ID given'); $this->markTestSkipped('No Client-ID given');
} }
@@ -34,6 +39,11 @@ abstract class ApiTestCase extends TestCase
return $result; return $result;
} }
protected function getBaseUrl()
{
return getenv('BASE_URL');
}
protected function getClientId() protected function getClientId()
{ {
return getenv('CLIENT_ID'); return getenv('CLIENT_ID');