From 57073744ff7c4351b7801a5a9b6042bf2f0b6791 Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Wed, 30 Dec 2015 23:41:05 +0000 Subject: [PATCH 01/21] Initial rewrite commit --- .editorconfig | 13 ++ .gitignore | 1 + .php_cs | 77 +++++++++++ .pre-commit-config.yaml | 7 + .travis.yml | 8 +- README.md | 34 +---- composer.json | 17 +-- {src/config => config}/config.php | 0 demo/index.php | 44 ++++++ src/Client.php | 81 +++++++++++ src/Entity/Entity.php | 116 ++++++++++++++++ src/Entity/Poniverse/User.php | 40 ++++++ src/Entity/Ponyfm/Track.php | 13 ++ src/Errors/ApiException.php | 45 ++++++ src/Errors/Error.php | 30 ++++ src/OAuth2/PoniverseProvider.php | 113 ++++++++++++++++ src/Poniverse/Api/Facades/Poniverse.php | 16 --- src/Poniverse/Api/Poniverse.php | 128 ------------------ src/Poniverse/Api/Resource/Resource.php | 16 --- src/Poniverse/Api/Resource/User.php | 15 -- ...vider.php => PoniverseServiceProvider.php} | 33 ++--- src/Serializer/JsonApi.php | 21 +++ src/Service/JsonApiService.php | 30 ++++ src/Service/Poniverse/User.php | 38 ++++++ src/Service/PonyfmService.php | 32 +++++ src/Service/Service.php | 52 +++++++ tests/Poniverse/Api/PoniverseTest.php | 45 ------ tests/Poniverse/Api/Resource/User.php | 38 ------ 28 files changed, 785 insertions(+), 318 deletions(-) create mode 100644 .editorconfig create mode 100644 .php_cs create mode 100644 .pre-commit-config.yaml rename {src/config => config}/config.php (100%) create mode 100644 demo/index.php create mode 100644 src/Client.php create mode 100644 src/Entity/Entity.php create mode 100644 src/Entity/Poniverse/User.php create mode 100644 src/Entity/Ponyfm/Track.php create mode 100644 src/Errors/ApiException.php create mode 100644 src/Errors/Error.php create mode 100644 src/OAuth2/PoniverseProvider.php delete mode 100644 src/Poniverse/Api/Facades/Poniverse.php delete mode 100644 src/Poniverse/Api/Poniverse.php delete mode 100644 src/Poniverse/Api/Resource/Resource.php delete mode 100644 src/Poniverse/Api/Resource/User.php rename src/{Poniverse/Api/ApiServiceProvider.php => PoniverseServiceProvider.php} (50%) create mode 100644 src/Serializer/JsonApi.php create mode 100644 src/Service/JsonApiService.php create mode 100644 src/Service/Poniverse/User.php create mode 100644 src/Service/PonyfmService.php create mode 100644 src/Service/Service.php delete mode 100644 tests/Poniverse/Api/PoniverseTest.php delete mode 100644 tests/Poniverse/Api/Resource/User.php diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ab5456b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.{yml,yaml}] +indent_style = space +indent_size = 2 diff --git a/.gitignore b/.gitignore index 5826402..e8f16ba 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ composer.phar composer.lock .DS_Store +.php_cs.cache diff --git a/.php_cs b/.php_cs new file mode 100644 index 0000000..e8c5a2a --- /dev/null +++ b/.php_cs @@ -0,0 +1,77 @@ +finder(DefaultFinder::create()->in(__DIR__)) + ->fixers($fixers) + ->level(FixerInterface::NONE_LEVEL) + ->setUsingCache(true); diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..198aae0 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,7 @@ +- repo: git@github.com:hootsuite/pre-commit-php.git + sha: 1.2.0 + hooks: + - id: php-lint + - id: php-unit + - id: php-cs-fixer + args: ['--config-file=.php_cs'] diff --git a/.travis.yml b/.travis.yml index 6e977bf..7186e9a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,13 +4,9 @@ php: - 5.4 - 5.5 - 5.6 + - 7.0 - hhvm -matrix: - allow_failures: - - php: hhvm - - before_script: - composer self-update - composer install --prefer-source --no-interaction --dev @@ -26,4 +22,4 @@ after_script: - php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml #Coveralls - - php bin/coveralls -p \ No newline at end of file + - php bin/coveralls -p diff --git a/README.md b/README.md index ceba1b3..d218a84 100644 --- a/README.md +++ b/README.md @@ -6,41 +6,21 @@ Require this package in composer.json and update "poniverse/api": "dev-master" - -###Normal Setup - -Example Code: - $config = [ - 'client_id' => 'YOUR_CLIENT_ID' - 'client_secret' => 'YOUR_CLIENT_SECRET' - 'host_url' => 'https://api.poniverse.net' - ]; +###Normal Setup - $poniverse = new Poniverse( - $config['client_id'], - $config['client_secret'], - new Client([ - 'base_url' => [$config['host_url'], ['version' => 'v' . Poniverse::VERSION]] - ]) - ); - - $poniverse->setAccessToken('GRANTED_ACCESS_TOKEN'); - - $user = $poniverse->user->get(); - // $user['display_name']; - // $user['email']; +See `demo\index.php` for an example. -###Laravel 4 Setup +###Laravel 5 Setup -Open up `app/config/app.php` and add this line in your `providers` section +Add the service provider to your `providers` section, usually located in `config/app.php`. - 'Poniverse\Api\ApiServiceProvider', + Poniverse\Api\ApiServiceProvider::class, -In the same file add this line to the ```aliases``` section +If you want the facade, add this to the same file in the `aliases` section 'Poniverse' => 'Poniverse\Api\Facades\Poniverse', Publish the configuration and then edit it - php artisan config:publish poniverse/api + php artisan vendor:publish diff --git a/composer.json b/composer.json index 4ec9aac..1758270 100644 --- a/composer.json +++ b/composer.json @@ -11,18 +11,19 @@ } ], "require": { - "php": ">=5.4.0", - "illuminate/support": "4.1.*", - "guzzlehttp/guzzle": "4.*" + "php": ">=5.5.0", + "illuminate/support": "5.0.x|5.1.x|5.2.x", + "guzzlehttp/guzzle": "~6.0", + "league/oauth2-client": "^1.1" }, "require-dev": { - "phpunit/phpunit": "4.0.*", - "mockery/mockery": "dev-master", - "satooshi/php-coveralls": "dev-master" + "phpunit/phpunit": "~4.0", + "mockery/mockery": "0.9.*", + "satooshi/php-coveralls": "~1.0" }, "autoload": { - "psr-0": { - "Poniverse\\Api": "src/" + "psr-4": { + "Poniverse\\Lib\\": "src/" } }, "minimum-stability": "stable" diff --git a/src/config/config.php b/config/config.php similarity index 100% rename from src/config/config.php rename to config/config.php diff --git a/demo/index.php b/demo/index.php new file mode 100644 index 0000000..cfb23de --- /dev/null +++ b/demo/index.php @@ -0,0 +1,44 @@ + 'demo', + 'clientSecret' => 'demo', + 'redirectUri' => 'http://lib.pv/index.php', +]); + +try { + // FYI, This is for development use only, you will never be able to + // use the password grant on our production servers. + $accessToken = $oauthProvider->getAccessToken('password', [ + 'username' => 'test', + 'password' => 'test', + ]); + + $poniverseClient->setAccessToken($accessToken); +} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) { + dd($e->getMessage()); +} + +$resourceOwner = $oauthProvider->getResourceOwner($accessToken); + +// API TEST + +$userService = new \Poniverse\Lib\Service\Poniverse\User($poniverseClient); + +$anotherUser = $userService->get('5582ba3b-46ab-46f8-95e1-00bb1b8748c7'); + +$anotherUser->display_name = 'Test Dummy'; + +try { + $userService->update($anotherUser); +} catch (\Poniverse\Lib\Errors\ApiException $e) { + // TODO: Handle Error +} + +dd($resourceOwner, $anotherUser); diff --git a/src/Client.php b/src/Client.php new file mode 100644 index 0000000..60ccad2 --- /dev/null +++ b/src/Client.php @@ -0,0 +1,81 @@ +httpClient = $httpClient; + } + + /** + * Returns the set access key. + * + * @return string + */ + public function getAccessToken() + { + return $this->accessToken; + } + + /** + * Sets the access token to communicate to the api with. + * + * @param $accessToken + * + * @return $this + */ + public function setAccessToken(AccessToken $accessToken) + { + $this->accessToken = $accessToken->getToken(); + + return $this; + } + + /** + * Returns the http client. + * + * @return \GuzzleHttp\Client + */ + public function getHttpClient() + { + return $this->httpClient; + } + + public function getAuthHeader() + { + return ['Authorization' => 'Bearer '.$this->getAccessToken()]; + } + + public function getPoniverseUrl() + { + return $this->poniverseUrl; + } + + public function getPonyfmUrl() + { + return $this->ponyfmUrl; + } +} diff --git a/src/Entity/Entity.php b/src/Entity/Entity.php new file mode 100644 index 0000000..fbc0336 --- /dev/null +++ b/src/Entity/Entity.php @@ -0,0 +1,116 @@ +hydrate($attributes); + $this->checkDirty = true; + } + + /** + * Hydrate the entity with data. + * + * @param array $data + * + * @return array + */ + abstract protected function hydrate(array $data); + + /** + * Determine if any attributes have been modified. + * + * @return bool + */ + public function isDirty() + { + return count($this->dirty) > 0; + } + + public function getAttributes() + { + return $this->attributes; + } + + public function getDirtyAttributes() + { + $attributes = []; + + foreach ($this->dirty as $name) { + $attributes[$name] = $this->$name; + } + + return $attributes; + } + + public function __get($name) + { + if (! isset($this->attributes[$name]) && $name !== 'id') { + throw new \InvalidArgumentException('Property doesn\'t exist!'); + } + + return $name === 'id' ? $this->id : $this->attributes[$name]; + } + + /** + * Track modifications made to attributes. + * + * @param string $name + * @param mixed $value + */ + public function __set($name, $value) + { + if ($this->checkDirty && ($name === 'id' || in_array($name, $this->readOnlyProperties, true))) { + throw new \InvalidArgumentException("The '{$name}' property is read-only"); + } + + if ($this->checkDirty && ! in_array($name, $this->dirty, true)) { + $this->dirty[] = $name; + } + + $this->attributes[$name] = $value; + } +} diff --git a/src/Entity/Poniverse/User.php b/src/Entity/Poniverse/User.php new file mode 100644 index 0000000..81bebea --- /dev/null +++ b/src/Entity/Poniverse/User.php @@ -0,0 +1,40 @@ +id = $data['data']['id']; + $this->attributes = $data['data']['attributes']; + } + + /** + * {@inheritdoc} + */ + public function getId() + { + return $this->id; + } + + /** + * {@inheritdoc} + */ + public function toArray() + { + return array_merge(['id' => $this->id], $this->data); + } +} diff --git a/src/Entity/Ponyfm/Track.php b/src/Entity/Ponyfm/Track.php new file mode 100644 index 0000000..f643bc7 --- /dev/null +++ b/src/Entity/Ponyfm/Track.php @@ -0,0 +1,13 @@ +errors = $errors; + $this->statusCode = $statusCode; + + if ($errors && ! $message) { + $message = $errors['']; + } + + parent::__construct($message); + } + + public function getErrors() + { + return $this->errors; + } + + public function getStatusCode() + { + return $this->statusCode; + } +} diff --git a/src/Errors/Error.php b/src/Errors/Error.php new file mode 100644 index 0000000..bafa8b0 --- /dev/null +++ b/src/Errors/Error.php @@ -0,0 +1,30 @@ +detail; + } + + /** + * @return string + */ + public function getTitle() + { + return $this->title; + } +} diff --git a/src/OAuth2/PoniverseProvider.php b/src/OAuth2/PoniverseProvider.php new file mode 100644 index 0000000..23a59d1 --- /dev/null +++ b/src/OAuth2/PoniverseProvider.php @@ -0,0 +1,113 @@ +domain.'/oauth/authorize'; + } + + /** + * Returns the base URL for requesting an access token. + * + * Eg. https://oauth.service.com/token + * + * @param array $params + * + * @return string + */ + public function getBaseAccessTokenUrl(array $params) + { + return $this->apiDomain.'/oauth/access_token'; + } + + /** + * Returns the URL for requesting the resource owner's details. + * + * @param AccessToken $token + * + * @return string + */ + public function getResourceOwnerDetailsUrl(AccessToken $token) + { + return $this->apiDomain.'/user'; + } + + /** + * Returns the default scopes used by this provider. + * + * This should only be the scopes that are required to request the details + * of the resource owner, rather than all the available scopes. + * + * @return array + */ + protected function getDefaultScopes() + { + return ['basic']; + } + + /** + * Checks a provider response for errors. + * + * @throws IdentityProviderException + * + * @param ResponseInterface $response + * @param array|string $data Parsed response data + */ + protected function checkResponse(ResponseInterface $response, $data) + { + if ($response->getStatusCode() >= 400) { + throw new IdentityProviderException( + $data['message'] ?: $response->getReasonPhrase(), + $response->getStatusCode(), + $response + ); + } + } + + /** + * Generates a resource owner object from a successful resource owner + * details request. + * + * @param array $response + * @param AccessToken $token + * + * @return ResourceOwnerInterface + */ + protected function createResourceOwner(array $response, AccessToken $token) + { + return new User($response); + } +} diff --git a/src/Poniverse/Api/Facades/Poniverse.php b/src/Poniverse/Api/Facades/Poniverse.php deleted file mode 100644 index cbfa30f..0000000 --- a/src/Poniverse/Api/Facades/Poniverse.php +++ /dev/null @@ -1,16 +0,0 @@ -clientId = $clientId; - $this->clientSecret = $clientSecret; - $this->client = $client; - $this->host = $client->getBaseUrl(); - } - - /** - * Returns the set client id - * - * @return string - */ - public function getClientId() - { - return $this->clientId; - } - - /** - * Returns the set client secret - * - * @return string - */ - public function getClientSecret() - { - return $this->clientSecret; - } - - /** - * Returns the host being used - * - * @return string - */ - public function getHost() - { - return $this->host; - } - - /** - * Returns the set access key - * - * @return string - */ - public function getAccessToken() - { - return $this->accessToken; - } - - /** - * Sets the access token to communicate to the api with - * - * @param $accessToken - * @return $this - */ - public function setAccessToken($accessToken) - { - $this->client->setDefaultOption('headers/Authorization', $accessToken); - - $this->accessToken = $accessToken; - - return $this; - } - - /** - * Returns the http client - * - * @return Client - */ - public function getClient() - { - return $this->client; - } - - /** - * Returns the user resource class - * - * @return User - */ - public function user() - { - return new User($this); - } -} \ No newline at end of file diff --git a/src/Poniverse/Api/Resource/Resource.php b/src/Poniverse/Api/Resource/Resource.php deleted file mode 100644 index 640963a..0000000 --- a/src/Poniverse/Api/Resource/Resource.php +++ /dev/null @@ -1,16 +0,0 @@ -poniverse = $poniverse; - } -} \ No newline at end of file diff --git a/src/Poniverse/Api/Resource/User.php b/src/Poniverse/Api/Resource/User.php deleted file mode 100644 index a74af69..0000000 --- a/src/Poniverse/Api/Resource/User.php +++ /dev/null @@ -1,15 +0,0 @@ -poniverse->getClient()->get( 'users/' . ($id ?: 'me') )->json(); - } -} \ No newline at end of file diff --git a/src/Poniverse/Api/ApiServiceProvider.php b/src/PoniverseServiceProvider.php similarity index 50% rename from src/Poniverse/Api/ApiServiceProvider.php rename to src/PoniverseServiceProvider.php index d9df4a3..6573ec4 100644 --- a/src/Poniverse/Api/ApiServiceProvider.php +++ b/src/PoniverseServiceProvider.php @@ -1,11 +1,14 @@ -package('poniverse/api', 'poniverse/api'); } /** * Register the service provider. - * - * @return void */ public function register() { - $this->app['poniverse.api'] = $this->app->share(function(Container $app) { + $this->app->singleton('poniverse.api', function (Application $app) { $config = $app['config']->get('poniverse/api::config'); - return new Poniverse( - $config['client_id'], - $config['client_secret'], - new Client([ - 'base_url' => [$config['host_url'], ['version' => 'v' . Poniverse::VERSION]] - ]) - ); + $client = new Client(new HttpClient()); + + return $client; }); + + $this->app->bind(Client::class, 'poniverse.api'); } /** @@ -52,5 +48,4 @@ public function provides() { return ['poniverse.api']; } - } diff --git a/src/Serializer/JsonApi.php b/src/Serializer/JsonApi.php new file mode 100644 index 0000000..09844ce --- /dev/null +++ b/src/Serializer/JsonApi.php @@ -0,0 +1,21 @@ + [ + 'type' => $type, + 'id' => $entity->id, + 'attributes' => $dirtyOnly ? $entity->getDirtyAttributes() : $entity->getDirtyAttributes(), + ], + ]; + + return json_encode($base); + } +} diff --git a/src/Service/JsonApiService.php b/src/Service/JsonApiService.php new file mode 100644 index 0000000..d194a65 --- /dev/null +++ b/src/Service/JsonApiService.php @@ -0,0 +1,30 @@ +getBody(), true); + + $errors = []; + + if (isset($errors['errors'])) { + $errors = array_map(function ($error) { + return new Error($error['title'], $error['detail']); + }, $response['errors']); + } + + throw new ApiException($response->getStatusCode(), $errors); + } +} diff --git a/src/Service/Poniverse/User.php b/src/Service/Poniverse/User.php new file mode 100644 index 0000000..acc817c --- /dev/null +++ b/src/Service/Poniverse/User.php @@ -0,0 +1,38 @@ +request('get', $this->client->getPoniverseUrl().'/users/'.$id); + + $response = json_decode($request->getBody(), true); + + return new \Poniverse\Lib\Entity\Poniverse\User($response); + } + + public function update(\Poniverse\Lib\Entity\Poniverse\User $user) + { + if (! $user->isDirty()) { + throw new \Exception('Nothing has changed!'); + } + + $request = $this->request('patch', $this->client->getPoniverseUrl().'/users/'.$user->id, [ + 'body' => (new JsonApi())->serialize($user, 'users', true), + ]); + + dd((string) $request->getBody(), $request); + } +} diff --git a/src/Service/PonyfmService.php b/src/Service/PonyfmService.php new file mode 100644 index 0000000..6d0ca8c --- /dev/null +++ b/src/Service/PonyfmService.php @@ -0,0 +1,32 @@ +getBody(), true); + + $errorMessages = []; + + foreach ($response['errors'] as $type => $messages) { + $errorMessages = array_merge($errorMessages, $messages); + } + + $errors = array_map(function ($errorMessage) use ($response) { + return new Error($response['title'], $errorMessage); + }, $errorMessages); + + throw new ApiException($response->getStatusCode(), $errors); + } +} diff --git a/src/Service/Service.php b/src/Service/Service.php new file mode 100644 index 0000000..3b598bd --- /dev/null +++ b/src/Service/Service.php @@ -0,0 +1,52 @@ +client = $client; + } + + /** + * @param string $method + * @param string $url + * @param array $options + * + * @return \Psr\Http\Message\ResponseInterface + * + * @throws ApiException + */ + protected function request($method, $url, array $options = []) + { + $options = array_merge(['headers' => $this->client->getAuthHeader()], $options); + + try { + return $this->client->getHttpClient()->request( + $method, + $url, + $options + ); + } catch (RequestException $e) { + $this->handleError($e->getResponse()); + } + } + + /** + * @param ResponseInterface $response + * + * @throws ApiException + */ + abstract protected function handleError(ResponseInterface $response); +} diff --git a/tests/Poniverse/Api/PoniverseTest.php b/tests/Poniverse/Api/PoniverseTest.php deleted file mode 100644 index d7b3871..0000000 --- a/tests/Poniverse/Api/PoniverseTest.php +++ /dev/null @@ -1,45 +0,0 @@ -shouldReceive('getBaseUrl')->andReturn('https://api.poniverse.net/v1'); - - $poniverse = new \Poniverse\Api\Poniverse('123', 'abc', $guzzleMock); - - $this->assertEquals('https://api.poniverse.net/v1', $poniverse->getHost()); - $this->assertEquals('123', $poniverse->getClientId()); - $this->assertEquals('abc', $poniverse->getClientSecret()); - $this->assertInstanceOf('GuzzleHttp\Client', $poniverse->getClient()); - } - - public function testAccessTokenIsSet() - { - $guzzleMock = m::mock('GuzzleHttp\Client'); - $guzzleMock->shouldReceive('getBaseUrl')->once(); - $guzzleMock->shouldReceive('setDefaultOption')->with('headers/Authorization', '123')->once(); - - $poniverse = new \Poniverse\Api\Poniverse('123', 'abc', $guzzleMock); - $poniverse->setAccessToken('123'); - - $this->assertEquals('123', $poniverse->getAccessToken()); - } - - public function testUserMethodReturnsUser() - { - $guzzleMock = m::mock('GuzzleHttp\Client'); - $guzzleMock->shouldReceive('getBaseUrl')->once(); - - $poniverse = new \Poniverse\Api\Poniverse('123', 'abc', $guzzleMock); - - $this->assertInstanceOf('Poniverse\Api\Resource\User', $poniverse->user()); - } -} \ No newline at end of file diff --git a/tests/Poniverse/Api/Resource/User.php b/tests/Poniverse/Api/Resource/User.php deleted file mode 100644 index 13f5769..0000000 --- a/tests/Poniverse/Api/Resource/User.php +++ /dev/null @@ -1,38 +0,0 @@ -shouldReceive('get')->with('users/me')->once()->andReturn($guzzleMock)->mock(); - $guzzleMock->shouldReceive('json')->once()->andReturn(['success' => true]); - - $poniverse = m::mock('Poniverse\Api\Poniverse'); - $poniverse->shouldReceive('getClient')->andReturn($guzzleMock); - - $user = new \Poniverse\Api\Resource\User($poniverse); - - $this->assertArrayHasKey('success', $user->get()); - } - - public function testGetWithIdCallsIdEndpoint() - { - $guzzleMock = m::mock('GuzzleHttp\Client'); - $guzzleMock->shouldReceive('get')->with('users/23')->once()->andReturn($guzzleMock)->mock(); - $guzzleMock->shouldReceive('json')->once()->andReturn(['success' => true]); - - $poniverse = m::mock('Poniverse\Api\Poniverse'); - $poniverse->shouldReceive('getClient')->andReturn($guzzleMock); - - $user = new \Poniverse\Api\Resource\User($poniverse); - - $this->assertArrayHasKey('success', $user->get(23)); - } -} \ No newline at end of file From 0fb4ce873eb32524d03e0940df79d3f0458a2f95 Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Wed, 30 Dec 2015 23:46:34 +0000 Subject: [PATCH 02/21] The facade is a facade --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index d218a84..014af81 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,6 @@ Add the service provider to your `providers` section, usually located in `config Poniverse\Api\ApiServiceProvider::class, -If you want the facade, add this to the same file in the `aliases` section - - 'Poniverse' => 'Poniverse\Api\Facades\Poniverse', - Publish the configuration and then edit it php artisan vendor:publish From 7ce24b4ae7ffce2ecb1306feffcaf62896208bce Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Thu, 31 Dec 2015 00:08:24 +0000 Subject: [PATCH 03/21] Refactor OAuthProvider instantiation to PoniverseClient --- demo/index.php | 10 ++++++---- src/Client.php | 39 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/demo/index.php b/demo/index.php index cfb23de..f9562d5 100644 --- a/demo/index.php +++ b/demo/index.php @@ -2,13 +2,15 @@ require '../vendor/autoload.php'; -$poniverseClient = new \Poniverse\Lib\Client(new GuzzleHttp\Client()); +$poniverseClient = new \Poniverse\Lib\Client( + 'demo', + 'demo', + new GuzzleHttp\Client() +); // OAUTH DANCE -$oauthProvider = new \Poniverse\Lib\OAuth2\PoniverseProvider([ - 'clientId' => 'demo', - 'clientSecret' => 'demo', +$oauthProvider = $poniverseClient->getOAuthProvider([ 'redirectUri' => 'http://lib.pv/index.php', ]); diff --git a/src/Client.php b/src/Client.php index 60ccad2..9ac9891 100644 --- a/src/Client.php +++ b/src/Client.php @@ -4,11 +4,12 @@ use GuzzleHttp\Client as HttpClient; use League\OAuth2\Client\Token\AccessToken; +use Poniverse\Lib\OAuth2\PoniverseProvider; class Client { /** - * @var string|string + * @var string|null */ protected $accessToken = null; @@ -17,16 +18,34 @@ class Client */ protected $httpClient; + /** + * Poniverse.net Client ID. + * + * @var string + */ + private $clientId; + + /** + * Poniverse.net Client Secret. + * + * @var string + */ + private $clientSecret; + protected $poniverseUrl = 'http://api.poniverse.local'; protected $ponyfmUrl = 'https://pony.fm'; /** * Initializes the Poniverse Api client. * + * @param string $clientId + * @param string $clientSecret * @param \GuzzleHttp\Client $httpClient */ - public function __construct(HttpClient $httpClient) + public function __construct($clientId, $clientSecret, HttpClient $httpClient) { + $this->clientId = $clientId; + $this->clientSecret = $clientSecret; $this->httpClient = $httpClient; } @@ -78,4 +97,20 @@ public function getPonyfmUrl() { return $this->ponyfmUrl; } + + /** + * Returns the Poniverse OAuth Provider class. + * + * @param array $options + * @return PoniverseProvider + */ + public function getOAuthProvider(array $options = []) + { + $options = array_merge([ + 'clientId' => $this->clientId, + 'clientSecret' => $this->clientSecret, + ], $options); + + return new PoniverseProvider($options); + } } From 6a38b92f7fca0d4fdf05d3122333852ba47a1c68 Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Thu, 31 Dec 2015 00:09:41 +0000 Subject: [PATCH 04/21] Fix variable naming clash in error handlers --- src/Service/JsonApiService.php | 4 ++-- src/Service/PonyfmService.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Service/JsonApiService.php b/src/Service/JsonApiService.php index d194a65..8e61ecd 100644 --- a/src/Service/JsonApiService.php +++ b/src/Service/JsonApiService.php @@ -15,14 +15,14 @@ class JsonApiService extends Service */ protected function handleError(ResponseInterface $response) { - $response = json_decode($response->getBody(), true); + $body = json_decode($response->getBody(), true); $errors = []; if (isset($errors['errors'])) { $errors = array_map(function ($error) { return new Error($error['title'], $error['detail']); - }, $response['errors']); + }, $body['errors']); } throw new ApiException($response->getStatusCode(), $errors); diff --git a/src/Service/PonyfmService.php b/src/Service/PonyfmService.php index 6d0ca8c..8d477a2 100644 --- a/src/Service/PonyfmService.php +++ b/src/Service/PonyfmService.php @@ -15,16 +15,16 @@ class PonyfmService extends Service */ protected function handleError(ResponseInterface $response) { - $response = json_decode($response->getBody(), true); + $body = json_decode($response->getBody(), true); $errorMessages = []; - foreach ($response['errors'] as $type => $messages) { + foreach ($body['errors'] as $type => $messages) { $errorMessages = array_merge($errorMessages, $messages); } - $errors = array_map(function ($errorMessage) use ($response) { - return new Error($response['title'], $errorMessage); + $errors = array_map(function ($errorMessage) use ($body) { + return new Error($body['title'], $errorMessage); }, $errorMessages); throw new ApiException($response->getStatusCode(), $errors); From 22f21946033252ff578fe145a34bc47b0edacf43 Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Thu, 31 Dec 2015 01:00:29 +0000 Subject: [PATCH 05/21] Don't throw an exception when updating a user if there's nothing to update --- src/Service/Poniverse/User.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Service/Poniverse/User.php b/src/Service/Poniverse/User.php index acc817c..d6d75d5 100644 --- a/src/Service/Poniverse/User.php +++ b/src/Service/Poniverse/User.php @@ -25,10 +25,6 @@ public function get($id) public function update(\Poniverse\Lib\Entity\Poniverse\User $user) { - if (! $user->isDirty()) { - throw new \Exception('Nothing has changed!'); - } - $request = $this->request('patch', $this->client->getPoniverseUrl().'/users/'.$user->id, [ 'body' => (new JsonApi())->serialize($user, 'users', true), ]); From 49274ebbdd9426a7bee213c48e558c2139ae59dc Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Sun, 3 Jan 2016 19:20:36 +0000 Subject: [PATCH 06/21] Updated oauth error response checking --- src/OAuth2/PoniverseProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OAuth2/PoniverseProvider.php b/src/OAuth2/PoniverseProvider.php index 23a59d1..9f4a74f 100644 --- a/src/OAuth2/PoniverseProvider.php +++ b/src/OAuth2/PoniverseProvider.php @@ -90,7 +90,7 @@ protected function checkResponse(ResponseInterface $response, $data) { if ($response->getStatusCode() >= 400) { throw new IdentityProviderException( - $data['message'] ?: $response->getReasonPhrase(), + isset($data['error_description']) ? $data['error_description'] : $response->getReasonPhrase(), $response->getStatusCode(), $response ); From c351b23bcde4c9a913e5d4eeb8dbc0a86023105f Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Sun, 3 Jan 2016 19:23:23 +0000 Subject: [PATCH 07/21] Added Factory, updated demo and added some docblocks. --- demo/index.php | 8 ++++--- src/Client.php | 37 ++++++++++++++++++++++++++----- src/Entity/Entity.php | 10 +++++++++ src/Service/Poniverse/Factory.php | 28 +++++++++++++++++++++++ 4 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 src/Service/Poniverse/Factory.php diff --git a/demo/index.php b/demo/index.php index f9562d5..8c28500 100644 --- a/demo/index.php +++ b/demo/index.php @@ -31,9 +31,11 @@ // API TEST -$userService = new \Poniverse\Lib\Service\Poniverse\User($poniverseClient); - -$anotherUser = $userService->get('5582ba3b-46ab-46f8-95e1-00bb1b8748c7'); +try { + $anotherUser = $poniverseClient->poniverse()->users()->get('5582ba3b-46ab-46f8-95e1-00bb1b8748c7'); +} catch (\Poniverse\Lib\Errors\ApiException $e) { + dd($e->getMessage(), $e->getStatusCode()); +} $anotherUser->display_name = 'Test Dummy'; diff --git a/src/Client.php b/src/Client.php index 9ac9891..8212df6 100644 --- a/src/Client.php +++ b/src/Client.php @@ -32,8 +32,15 @@ class Client */ private $clientSecret; - protected $poniverseUrl = 'http://api.poniverse.local'; - protected $ponyfmUrl = 'https://pony.fm'; + /** + * Poniverse project url mappings. + * + * @var array + */ + protected $urlMappings = [ + 'poniverse' => 'https://api.poniverse.net', + 'ponyfm' => 'https://pony.fm', + ]; /** * Initializes the Poniverse Api client. @@ -41,12 +48,17 @@ class Client * @param string $clientId * @param string $clientSecret * @param \GuzzleHttp\Client $httpClient + * @param array $urlOverrides */ - public function __construct($clientId, $clientSecret, HttpClient $httpClient) + public function __construct($clientId, $clientSecret, HttpClient $httpClient, $urlOverrides = []) { $this->clientId = $clientId; $this->clientSecret = $clientSecret; $this->httpClient = $httpClient; + + if (count($urlOverrides) > 0) { + $this->urlMappings = array_merge($this->urlMappings, $urlOverrides); + } } /** @@ -83,6 +95,11 @@ public function getHttpClient() return $this->httpClient; } + /** + * Returns the Autho. + * + * @return array + */ public function getAuthHeader() { return ['Authorization' => 'Bearer '.$this->getAccessToken()]; @@ -90,12 +107,22 @@ public function getAuthHeader() public function getPoniverseUrl() { - return $this->poniverseUrl; + return $this->urlMappings['poniverse'][$this->environment]; } public function getPonyfmUrl() { - return $this->ponyfmUrl; + return $this->urlMappings['ponyfm'][$this->environment]; + } + + /** + * Returns the Poniverse.net service factory. + * + * @return Service\Poniverse\Factory + */ + public function poniverse() + { + return new Service\Poniverse\Factory($this); } /** diff --git a/src/Entity/Entity.php b/src/Entity/Entity.php index fbc0336..962af83 100644 --- a/src/Entity/Entity.php +++ b/src/Entity/Entity.php @@ -70,11 +70,21 @@ public function isDirty() return count($this->dirty) > 0; } + /** + * Returns all entity attributes. + * + * @return array + */ public function getAttributes() { return $this->attributes; } + /** + * Returns all changed attributes. + * + * @return array + */ public function getDirtyAttributes() { $attributes = []; diff --git a/src/Service/Poniverse/Factory.php b/src/Service/Poniverse/Factory.php new file mode 100644 index 0000000..ed0be61 --- /dev/null +++ b/src/Service/Poniverse/Factory.php @@ -0,0 +1,28 @@ +client = $client; + } + + /** + * Returns the user service. + * + * @return User + */ + public function users() + { + return new User($this->client); + } +} From ec25cb60b9e9f1e28da0f78b812608eaa66a3190 Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Sun, 3 Jan 2016 19:48:23 +0000 Subject: [PATCH 08/21] Fixed isset to wrong variable in JsonApiService --- src/Service/JsonApiService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Service/JsonApiService.php b/src/Service/JsonApiService.php index 8e61ecd..bbee23a 100644 --- a/src/Service/JsonApiService.php +++ b/src/Service/JsonApiService.php @@ -19,7 +19,7 @@ protected function handleError(ResponseInterface $response) $errors = []; - if (isset($errors['errors'])) { + if (isset($body['errors'])) { $errors = array_map(function ($error) { return new Error($error['title'], $error['detail']); }, $body['errors']); From 6b98f5936e5c2144d6b877c529c7ee704ddaac70 Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Sun, 3 Jan 2016 20:25:24 +0000 Subject: [PATCH 09/21] Whoops, forgot to remove the environment setting leftovers. --- src/Client.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Client.php b/src/Client.php index 8212df6..8f80b66 100644 --- a/src/Client.php +++ b/src/Client.php @@ -107,12 +107,12 @@ public function getAuthHeader() public function getPoniverseUrl() { - return $this->urlMappings['poniverse'][$this->environment]; + return $this->urlMappings['poniverse']; } public function getPonyfmUrl() { - return $this->urlMappings['ponyfm'][$this->environment]; + return $this->urlMappings['ponyfm']; } /** From ed45f6002ea2a074fdd0448914498ccf6fd7da35 Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Sun, 28 Aug 2016 00:43:01 +0100 Subject: [PATCH 10/21] Update OAuth2 provider to use production url --- src/OAuth2/PoniverseProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OAuth2/PoniverseProvider.php b/src/OAuth2/PoniverseProvider.php index 9f4a74f..d658cc2 100644 --- a/src/OAuth2/PoniverseProvider.php +++ b/src/OAuth2/PoniverseProvider.php @@ -25,7 +25,7 @@ class PoniverseProvider extends AbstractProvider * * @var string */ - public $apiDomain = 'http://api.poniverse.local'; + public $apiDomain = 'https://api.poniverse.net'; /** * Returns the base URL for authorizing a client. From 1786d94c1b99f412083051f6863ede027306a5eb Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Thu, 29 Dec 2016 09:44:05 +0000 Subject: [PATCH 11/21] Update laravel version constraints --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 1758270..d51f928 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ ], "require": { "php": ">=5.5.0", - "illuminate/support": "5.0.x|5.1.x|5.2.x", + "illuminate/support": "5.1.*|5.2.*|5.3.*|5.4.*", "guzzlehttp/guzzle": "~6.0", "league/oauth2-client": "^1.1" }, From 8f702ba53bdc5e762b0f6c88b242fa62fff994e4 Mon Sep 17 00:00:00 2001 From: Peter Deltchev Date: Thu, 29 Dec 2016 02:14:09 -0800 Subject: [PATCH 12/21] Corrected the autoloader namespace. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d51f928..7e32544 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ }, "autoload": { "psr-4": { - "Poniverse\\Lib\\": "src/" + "Poniverse\\Api\\": "src/" } }, "minimum-stability": "stable" From 4eac2f7ca1d3132636334e34f2fbefc8e93fe45c Mon Sep 17 00:00:00 2001 From: Peter Deltchev Date: Thu, 29 Dec 2016 03:35:33 -0800 Subject: [PATCH 13/21] Made the project's namespace consistently Poniverse\Lib in all files. --- composer.json | 2 +- src/PoniverseServiceProvider.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 7e32544..d51f928 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ }, "autoload": { "psr-4": { - "Poniverse\\Api\\": "src/" + "Poniverse\\Lib\\": "src/" } }, "minimum-stability": "stable" diff --git a/src/PoniverseServiceProvider.php b/src/PoniverseServiceProvider.php index 6573ec4..afcf3e2 100644 --- a/src/PoniverseServiceProvider.php +++ b/src/PoniverseServiceProvider.php @@ -1,6 +1,6 @@ Date: Thu, 29 Dec 2016 03:41:46 -0800 Subject: [PATCH 14/21] Removed PHP 5.4 from Travis's tests. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7186e9a..a6a81bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: php php: - - 5.4 - 5.5 - 5.6 - 7.0 From 0d28ae366717a59ac68d1007f54058be5b57bb5a Mon Sep 17 00:00:00 2001 From: Peter Deltchev Date: Thu, 29 Dec 2016 04:44:02 -0800 Subject: [PATCH 15/21] Made the library work against Poniverse API v1. --- src/Entity/Poniverse/User.php | 4 ++-- src/OAuth2/PoniverseProvider.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Entity/Poniverse/User.php b/src/Entity/Poniverse/User.php index 81bebea..1375991 100644 --- a/src/Entity/Poniverse/User.php +++ b/src/Entity/Poniverse/User.php @@ -18,8 +18,8 @@ class User extends Entity implements ResourceOwnerInterface public function hydrate(array $data) { - $this->id = $data['data']['id']; - $this->attributes = $data['data']['attributes']; + $this->id = $data['id']; + $this->attributes = $data; } /** diff --git a/src/OAuth2/PoniverseProvider.php b/src/OAuth2/PoniverseProvider.php index d658cc2..77bed49 100644 --- a/src/OAuth2/PoniverseProvider.php +++ b/src/OAuth2/PoniverseProvider.php @@ -25,7 +25,7 @@ class PoniverseProvider extends AbstractProvider * * @var string */ - public $apiDomain = 'https://api.poniverse.net'; + public $apiDomain = 'https://api.poniverse.net/v1'; /** * Returns the base URL for authorizing a client. @@ -50,7 +50,7 @@ public function getBaseAuthorizationUrl() */ public function getBaseAccessTokenUrl(array $params) { - return $this->apiDomain.'/oauth/access_token'; + return $this->domain.'/oauth/access_token'; } /** @@ -62,7 +62,7 @@ public function getBaseAccessTokenUrl(array $params) */ public function getResourceOwnerDetailsUrl(AccessToken $token) { - return $this->apiDomain.'/user'; + return $this->apiDomain.'/users/me'; } /** From 851f9ea1495142dcbf0307d48131cedc70d4e44e Mon Sep 17 00:00:00 2001 From: Peter Deltchev Date: Thu, 29 Dec 2016 08:04:47 -0800 Subject: [PATCH 16/21] Implemented the access token introspection endpoint. --- src/AccessToken.php | 218 +++++++++++++++++++++ src/Errors/InvalidAccessTokenException.php | 28 +++ src/Service/Poniverse/AccessTokenInfo.php | 72 +++++++ src/Service/Poniverse/Factory.php | 9 + 4 files changed, 327 insertions(+) create mode 100644 src/AccessToken.php create mode 100644 src/Errors/InvalidAccessTokenException.php create mode 100644 src/Service/Poniverse/AccessTokenInfo.php diff --git a/src/AccessToken.php b/src/AccessToken.php new file mode 100644 index 0000000..1c6ea77 --- /dev/null +++ b/src/AccessToken.php @@ -0,0 +1,218 @@ +token = $accessToken; + } + + /** + * @return mixed + */ + public function getToken() { + return $this->token; + } + + /** + * @return bool + */ + public function getIsActive() { + return $this->isActive; + } + + /** + * @param bool $isActive + * @return AccessToken + */ + public function setIsActive($isActive) { + $this->isActive = $isActive; + return $this; + } + + /** + * @return mixed + */ + public function getExpiresAt() { + return $this->expiresAt; + } + + /** + * @param mixed $expiresAt + * @return AccessToken + */ + public function setExpiresAt($expiresAt) { + $this->expiresAt = $expiresAt; + return $this; + } + + /** + * @return mixed + */ + public function getIssuedAt() { + return $this->issuedAt; + } + + /** + * @param mixed $issuedAt + * @return AccessToken + */ + public function setIssuedAt($issuedAt) { + $this->issuedAt = $issuedAt; + return $this; + } + + /** + * @return array + */ + public function getScopes() { + return $this->scopes; + } + + /** + * @param array|string $scopes + * @return AccessToken + */ + public function setScopes($scopes) { + if (is_array($scopes)) { + $this->scopes = $scopes; + } else { + $this->scopes = mb_split(' ', $scopes); + } + + return $this; + } + + /** + * @return mixed + */ + public function getClientId() { + return $this->clientId; + } + + /** + * @param mixed $clientId + * @return AccessToken + */ + public function setClientId($clientId) { + $this->clientId = $clientId; + return $this; + } + + /** + * @return mixed + */ + public function getSub() { + return $this->sub; + } + + /** + * @param mixed $sub + * @return AccessToken + */ + public function setSub($sub) { + $this->sub = $sub; + return $this; + } + + /** + * @return mixed + */ + public function getUserId() { + return $this->userId; + } + + /** + * @param mixed $userId + * @return AccessToken + */ + public function setUserId($userId) { + $this->userId = $userId; + return $this; + } + + /** + * @return mixed + */ + public function getIntendedAudience() { + return $this->intendedAudience; + } + + /** + * @param mixed $intendedAudience + * @return AccessToken + */ + public function setIntendedAudience($intendedAudience) { + $this->intendedAudience = $intendedAudience; + return $this; + } + + /** + * @return mixed + */ + public function getIssuer() { + return $this->issuer; + } + + /** + * @param mixed $issuer + * @return AccessToken + */ + public function setIssuer($issuer) { + $this->issuer = $issuer; + return $this; + } + + /** + * @return mixed + */ + public function getTokenType() { + return $this->tokenType; + } + + /** + * @param mixed $tokenType + * @return AccessToken + */ + public function setTokenType($tokenType) { + $this->tokenType = $tokenType; + return $this; + } +} diff --git a/src/Errors/InvalidAccessTokenException.php b/src/Errors/InvalidAccessTokenException.php new file mode 100644 index 0000000..cad83d6 --- /dev/null +++ b/src/Errors/InvalidAccessTokenException.php @@ -0,0 +1,28 @@ +getStatusCode()) { + throw new InvalidAccessTokenException('This access token is expired or invalid!'); + } else { + throw new \Poniverse\Lib\Errors\ApiException( + $response->getStatusCode(), + ['response' => var_export($response, true)], + 'An unknown error occurred while contacting the Poniverse API.'); + } + } + + /** + * Gets information about the given access token. + * + * @link https://tools.ietf.org/html/draft-richer-oauth-introspection-06 + * + * @param $accessTokenToIntrospect + * @return \Poniverse\Lib\AccessToken + */ + public function introspect($accessTokenToIntrospect) { + $clientToken = $this->client->getOAuthProvider()->getAccessToken('client_credentials'); + $this->client->setAccessToken($clientToken); + + $request = $this->request( + 'post', + $this->client->getPoniverseUrl() . "/v1/meta/introspect?token={$accessTokenToIntrospect}", + ['headers' => array_merge( + ['Accept' => 'application/json'], + $this->client->getAuthHeader() + )] + ); + + $response = json_decode($request->getBody(), true); + + $tokenInfo = new \Poniverse\Lib\AccessToken($accessTokenToIntrospect); + $tokenInfo + ->setIsActive($response['active']) + ->setScopes($response['scope']) + ->setClientId($response['client_id']); + return $tokenInfo; + } +} diff --git a/src/Service/Poniverse/Factory.php b/src/Service/Poniverse/Factory.php index ed0be61..921a6de 100644 --- a/src/Service/Poniverse/Factory.php +++ b/src/Service/Poniverse/Factory.php @@ -25,4 +25,13 @@ public function users() { return new User($this->client); } + + /** + * Returns the access token service. + * + * @return AccessTokenInfo + */ + public function accessTokenInfo() { + return new AccessTokenInfo($this->client); + } } From 241c32e32076eaa4c0cf4d2a33cddcda006f2ba8 Mon Sep 17 00:00:00 2001 From: Peter Deltchev Date: Fri, 30 Dec 2016 08:09:52 -0800 Subject: [PATCH 17/21] Added support for the account syncing endpoint. --- src/Service/Poniverse/Factory.php | 6 +-- .../{AccessTokenInfo.php => Meta.php} | 47 ++++++++++++++++++- 2 files changed, 48 insertions(+), 5 deletions(-) rename src/Service/Poniverse/{AccessTokenInfo.php => Meta.php} (56%) diff --git a/src/Service/Poniverse/Factory.php b/src/Service/Poniverse/Factory.php index 921a6de..5c34f48 100644 --- a/src/Service/Poniverse/Factory.php +++ b/src/Service/Poniverse/Factory.php @@ -29,9 +29,9 @@ public function users() /** * Returns the access token service. * - * @return AccessTokenInfo + * @return Meta */ - public function accessTokenInfo() { - return new AccessTokenInfo($this->client); + public function meta() { + return new Meta($this->client); } } diff --git a/src/Service/Poniverse/AccessTokenInfo.php b/src/Service/Poniverse/Meta.php similarity index 56% rename from src/Service/Poniverse/AccessTokenInfo.php rename to src/Service/Poniverse/Meta.php index 88ba638..25337a6 100644 --- a/src/Service/Poniverse/AccessTokenInfo.php +++ b/src/Service/Poniverse/Meta.php @@ -18,11 +18,11 @@ namespace Poniverse\Lib\Service\Poniverse; +use League\OAuth2\Client\Token\AccessToken; use Poniverse\Lib\Errors\InvalidAccessTokenException; use Poniverse\Lib\Service\Service; -class AccessTokenInfo extends Service { - +class Meta extends Service { /** * @param \Psr\Http\Message\ResponseInterface $response * @throws InvalidAccessTokenException @@ -69,4 +69,47 @@ public function introspect($accessTokenToIntrospect) { ->setClientId($response['client_id']); return $tokenInfo; } + + /** + * Generates a new refresh token for a user and updates their email address. + * + * @see \League\OAuth2\Client\Token\AccessToken + * + * @param int $poniverseUserId + * @param callable $tokenUpdater A callable that updates your stored access token + * and refresh token for the user. A League AccessToken + * object (see above) is passed as the callable's only argument. + * @param callable $emailAddressUpdater A callable that updates the user's locally + * stored email address. The user's current + * email address is passed as its only argument. + * @return void + */ + public function syncAccount($poniverseUserId, $tokenUpdater, $emailAddressUpdater) { + $clientToken = $this->client->getOAuthProvider()->getAccessToken('client_credentials'); + $this->client->setAccessToken($clientToken); + + $request = $this->request( + 'post', + $this->client->getPoniverseUrl() . "/v1/meta/sync-account?user_id={$poniverseUserId}", + [ + 'headers' => array_merge( + ['Accept' => 'application/json'], + $this->client->getAuthHeader() + ) + ] + ); + + $response = json_decode($request->getBody(), true); + $tokenDetails = $response['token_info']; + + $accessToken = new AccessToken([ + 'access_token' => $tokenDetails['access_token'], + 'expires_in' => $tokenDetails['expires_in'], + 'refresh_token' => $tokenDetails['refresh_token'], + 'resource_owner_id' => $poniverseUserId, + ]); + + $tokenUpdater($accessToken); + $emailAddressUpdater($response['email']); + } } From fe21f0345a9887376366939f7733f16d0ab0de7d Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Tue, 28 Nov 2017 05:55:33 +0000 Subject: [PATCH 18/21] Support Laravel 5.5 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d51f928..d207454 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ ], "require": { "php": ">=5.5.0", - "illuminate/support": "5.1.*|5.2.*|5.3.*|5.4.*", + "illuminate/support": "5.1.*|5.2.*|5.3.*|5.4.*|5.5.*", "guzzlehttp/guzzle": "~6.0", "league/oauth2-client": "^1.1" }, From 45d979286bd29b9db6d8828c3bcaa8acb53b2926 Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Tue, 28 Nov 2017 20:42:39 +0000 Subject: [PATCH 19/21] Update php testing matrix --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a6a81bb..9b8b9c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,9 @@ language: php php: - - 5.5 - 5.6 - 7.0 - - hhvm + - 7.1 before_script: - composer self-update From ff45a2a34ea2ff5b1fe49411d6d4ba3b96a67fdf Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Sun, 14 Feb 2021 03:30:49 +0000 Subject: [PATCH 20/21] Update supported laravel versions --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d207454..ba760e9 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ ], "require": { "php": ">=5.5.0", - "illuminate/support": "5.1.*|5.2.*|5.3.*|5.4.*|5.5.*", + "illuminate/support": "5.*|6.*|7.*", "guzzlehttp/guzzle": "~6.0", "league/oauth2-client": "^1.1" }, From ca5fb08750978ce9d1652a42cb106f5c15c8af56 Mon Sep 17 00:00:00 2001 From: Adam Lavin Date: Sun, 14 Feb 2021 19:24:08 +0000 Subject: [PATCH 21/21] Update dependencies N.B This probably doesn't work, I'm working on getting another app up and running that this will be tested against. Once this is done, I'll finally merge this into master and tag 1.0.0 of this library. (About 7 years too late!!!) --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index ba760e9..a683237 100644 --- a/composer.json +++ b/composer.json @@ -11,10 +11,10 @@ } ], "require": { - "php": ">=5.5.0", - "illuminate/support": "5.*|6.*|7.*", - "guzzlehttp/guzzle": "~6.0", - "league/oauth2-client": "^1.1" + "php": ">=7.4.0", + "illuminate/support": "^8.0", + "guzzlehttp/guzzle": "^7.0", + "league/oauth2-client": "^2.6" }, "require-dev": { "phpunit/phpunit": "~4.0",