From 5e1c694de0f2e1309ff3601553f854061b97fb1a Mon Sep 17 00:00:00 2001 From: Artem Dubinin <2788396+shoman4eg@users.noreply.github.com> Date: Mon, 30 May 2022 00:05:07 +0200 Subject: [PATCH] Release 0.3.1 (#20) --- CHANGELOG.md | 9 ++++ README.md | 16 ++++++- composer.json | 13 +++++- src/Api/BaseHttpApi.php | 23 +++------- src/ApiClient.php | 2 +- src/ErrorHandler.php | 43 +++++++++++++++++++ .../Domain/UnauthorizedException.php | 5 +++ src/Http/Authenticator.php | 7 ++- tests/ApiClientTest.php | 23 +++++----- 9 files changed, 104 insertions(+), 37 deletions(-) create mode 100644 src/ErrorHandler.php diff --git a/CHANGELOG.md b/CHANGELOG.md index c60ad96..2c14d8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file. +## [0.3.1](https://github.com/shoman4eg/moy-nalog/compare/v0.3.0...v0.3.1) (2022-05-29) +### Features +* Add throw `UnauthorizedException` if server respond 401 status #19 + +### Documentation +* Update README with exception +* Add donation link +--- + ## [0.3.0](https://github.com/shoman4eg/moy-nalog/compare/v0.2.3...v0.3.0) (2022-05-15) ### Features * Add new method for income with multiple items #14 diff --git a/README.md b/README.md index 913b711..fbe8f47 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ [![Total Downloads](https://img.shields.io/packagist/dt/shoman4eg/moy-nalog.svg?style=flat-square)](https://packagist.org/packages/shoman4eg/moy-nalog) [![Scrutinizer code quality](https://img.shields.io/scrutinizer/quality/g/shoman4eg/moy-nalog/master?style=flat-square)](https://scrutinizer-ci.com/g/shoman4eg/moy-nalog/?branch=master) [![Packagist License](https://img.shields.io/packagist/l/shoman4eg/moy-nalog?style=flat-square)](LICENSE) +[![Donate](https://img.shields.io/badge/Donate-Tinkoff-yellow?style=flat-square)](https://www.tinkoff.ru/cf/7rZnC7N4bOO) An unofficial wrapper client for [lknpd.nalog.ru](https://lknpd.nalog.ru/) API @@ -16,6 +17,10 @@ Via Composer $ composer require shoman4eg/moy-nalog ``` +Also you need one of packages suggests `psr/http-client-implementation` + +Recommends `symfony/http-client` or `guzzlehttp/guzzle` + ## Usage ### Settings @@ -32,7 +37,11 @@ use Shoman4eg\Nalog\ApiClient; $apiClient = ApiClient::create(); // If known accessToken skip this step -$accessToken = $apiClient->createNewAccessToken($username, $password); +try { + $accessToken = $apiClient->createNewAccessToken($username, $password); +} catch (\Shoman4eg\Nalog\Exception\Domain\UnauthorizedException $e) { + var_dump($e->getMessage()); +} // Access token MUST contains all json response from method createNewAccessToken() $accessToken = '...'; @@ -126,5 +135,10 @@ JS lib [alexstep/moy-nalog](https://github.com/alexstep/moy-nalog) ## Changelog [Changelog](CHANGELOG.md): A complete changelog +## Donation +If this project help you reduce time to develop, you can give me a cup of coffee :) + +[Link to donate](https://www.tinkoff.ru/cf/7rZnC7N4bOO) + ## License The MIT License (MIT). Please see [License File](LICENSE) for more information. diff --git a/composer.json b/composer.json index 8415df3..417b451 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "shoman4eg/moy-nalog", "description": "An unofficial wrapper client for lknpd.nalog.ru API", "license": "MIT", - "version": "0.3.0", + "version": "0.3.1", "keywords": [ "api", "nalog.ru" @@ -13,6 +13,12 @@ "email": "artem@dubinin.me" } ], + "funding": [ + { + "type": "other", + "url": "https://www.tinkoff.ru/cf/7rZnC7N4bOO" + } + ], "require": { "php": ">=7.4 || ^8.0", "ext-json": "*", @@ -25,7 +31,7 @@ "webmozart/assert": "^1.4" }, "require-dev": { - "guzzlehttp/guzzle": "^7.0", + "guzzlehttp/guzzle": "^7.4.3", "nyholm/nsa": "^1.3", "php-http/curl-client": "^2.0", "php-http/message": "^1.0", @@ -33,6 +39,9 @@ "phpunit/phpunit": "^9.5", "roave/security-advisories": "dev-latest" }, + "suggest": { + "psr/http-client-implementation": "Required for using this package" + }, "autoload": { "psr-4": { "Shoman4eg\\Nalog\\": "src/" diff --git a/src/Api/BaseHttpApi.php b/src/Api/BaseHttpApi.php index 6673b75..bddd39a 100644 --- a/src/Api/BaseHttpApi.php +++ b/src/Api/BaseHttpApi.php @@ -6,7 +6,7 @@ use Http\Client\HttpClient; use Psr\Http\Client\ClientExceptionInterface; use Psr\Http\Message\ResponseInterface; -use Shoman4eg\Nalog\Exception\Domain as DomainExceptions; +use Shoman4eg\Nalog\ErrorHandler; use Shoman4eg\Nalog\Exception\DomainException; use Shoman4eg\Nalog\RequestBuilder; use Shoman4eg\Nalog\Util\JSON; @@ -134,28 +134,15 @@ protected function httpDelete(string $path, array $params = [], array $requestHe * Handle HTTP errors. * * Call is controlled by the specific API methods. + * Use ErrorHandler::handle instead of this * * @throws DomainException + * + * @deprecated */ protected function handleErrors(ResponseInterface $response): void { - $body = (string)$response->getBody(); - switch ($response->getStatusCode()) { - case 400: - throw new DomainExceptions\ValidationException($body); - case 401: - throw new DomainExceptions\UnauthorizedException(); - case 403: - throw new DomainExceptions\ForbiddenException(); - case 404: - throw new DomainExceptions\NotFoundException(); - case 406: - throw new DomainExceptions\ClientException('Wrong Accept headers'); - case 500: - throw new DomainExceptions\ServerException(); - default: - throw new DomainExceptions\UnknownErrorException(); - } + (new ErrorHandler())->handleResponse($response); } /** diff --git a/src/ApiClient.php b/src/ApiClient.php index bf28c3f..631be57 100644 --- a/src/ApiClient.php +++ b/src/ApiClient.php @@ -1,5 +1,4 @@ + */ +final class ErrorHandler +{ + /** + * Handle HTTP errors. + * + * Call is controlled by the specific API methods. + * + * @throws DomainException + */ + public function handleResponse(ResponseInterface $response): void + { + $body = (string)$response->getBody(); + + switch ($response->getStatusCode()) { + case 400: + throw new DomainExceptions\ValidationException($body); + case 401: + throw new DomainExceptions\UnauthorizedException($body); + case 403: + throw new DomainExceptions\ForbiddenException(); + case 404: + throw new DomainExceptions\NotFoundException(); + case 406: + throw new DomainExceptions\ClientException('Wrong Accept headers'); + case 500: + throw new DomainExceptions\ServerException(); + default: + throw new DomainExceptions\UnknownErrorException(); + } + } +} diff --git a/src/Exception/Domain/UnauthorizedException.php b/src/Exception/Domain/UnauthorizedException.php index df475e5..f07d5e8 100644 --- a/src/Exception/Domain/UnauthorizedException.php +++ b/src/Exception/Domain/UnauthorizedException.php @@ -8,4 +8,9 @@ */ final class UnauthorizedException extends ClientException { + public function __construct($message = '') + { + $decodedMessage = json_decode($message, true); + parent::__construct($decodedMessage['message'] ?? ''); + } } diff --git a/src/Http/Authenticator.php b/src/Http/Authenticator.php index 83e398d..a0c2d18 100644 --- a/src/Http/Authenticator.php +++ b/src/Http/Authenticator.php @@ -6,6 +6,8 @@ use Http\Client\HttpClient; use Psr\Http\Client\ClientExceptionInterface; use Shoman4eg\Nalog\DTO\DeviceInfo; +use Shoman4eg\Nalog\ErrorHandler; +use Shoman4eg\Nalog\Exception\DomainException; use Shoman4eg\Nalog\RequestBuilder; use Shoman4eg\Nalog\Util\JSON; @@ -33,6 +35,7 @@ public function __construct(RequestBuilder $requestBuilder, HttpClient $httpClie /** * @throws ClientExceptionInterface * @throws \JsonException + * @throws DomainException */ public function createAccessToken(string $username, string $password): ?string { @@ -47,8 +50,8 @@ public function createAccessToken(string $username, string $password): ?string $response = $this->httpClient->sendRequest($request); - if ($response->getStatusCode() !== 200) { - return null; + if ($response->getStatusCode() >= 400) { + (new ErrorHandler())->handleResponse($response); } $this->accessToken = (string)$response->getBody(); diff --git a/tests/ApiClientTest.php b/tests/ApiClientTest.php index 694b8ef..89ab210 100644 --- a/tests/ApiClientTest.php +++ b/tests/ApiClientTest.php @@ -3,11 +3,8 @@ namespace Shoman4eg\Nalog\Tests; -use GuzzleHttp\Client; -use GuzzleHttp\Handler\MockHandler; -use GuzzleHttp\HandlerStack; use GuzzleHttp\Psr7\Response; -use Shoman4eg\Nalog\ApiClient; +use Shoman4eg\Nalog\Exception\Domain\UnauthorizedException; /** * @author Artem Dubinin @@ -20,23 +17,23 @@ class ApiClientTest extends ApiTestCase /** * @throws \Psr\Http\Client\ClientExceptionInterface * @throws \JsonException + * @throws \Shoman4eg\Nalog\Exception\DomainException */ public function testCreateNewAccessToken(): void { - $mock = new MockHandler([ + $this->mock->append( new Response(200, [], self::getAccessToken()), - new Response(400, []), - ]); - $client = ApiClient::createWithCustomClient(new Client(['handler' => HandlerStack::create($mock)])); + new Response(401, [], json_encode(['message' => 'Указанный Вами ИНН некорректен'])), + ); - self::assertJson($client->createNewAccessToken('validUserName', 'validPassword')); - self::assertNull($client->createNewAccessToken('invalidUserName', 'invalidPassword')); + self::assertJson($this->client->createNewAccessToken('validUserName', 'validPassword')); + $this->expectException(UnauthorizedException::class); + $this->client->createNewAccessToken('invalidUserName', 'invalidPassword'); } public function testGetAccessToken(): void { - $client = ApiClient::create(); - $client->authenticate(self::getAccessToken()); - self::assertJson($client->getAccessToken()); + $this->client->authenticate(self::getAccessToken()); + self::assertJson($this->client->getAccessToken()); } }