diff --git a/src/IO/ConnectionFactory.php b/src/IO/ConnectionFactory.php index b7e4284..32cf55f 100644 --- a/src/IO/ConnectionFactory.php +++ b/src/IO/ConnectionFactory.php @@ -32,12 +32,14 @@ public function __construct(string $application_url, string $application_product */ public function create(): Connection { + $application_token = $this->settings->load('static:application_token'); + $jwt = Jwt::encode([ 'application_id' => $this->settings->load('static:application_id'), 'application_url' => $this->application_url, 'application_product' => $this->application_product, 'application_language' => $this->settings->load('static:language') ?? 'en', - ], $this->settings->load('static:application_token')); + ], $application_token ?? ''); if ($jwt === null) { diff --git a/src/IO/ConnectionStream.php b/src/IO/ConnectionStream.php index e82492f..c27bee8 100644 --- a/src/IO/ConnectionStream.php +++ b/src/IO/ConnectionStream.php @@ -32,7 +32,8 @@ public function run(Request $request): Response 'method' => 'POST', 'header' => [ "Content-type: $request->content_type", - "Authorization: Bearer $this->jwt_token" + "Authorization: Bearer $this->jwt_token", + //"Cookie: XDEBUG_SESSION=10355" //debugging purpose only ], 'content' => $request->serialize(), 'ignore_errors' => true, diff --git a/src/IO/Request.php b/src/IO/Request.php index 8a63cc3..fc5711f 100644 --- a/src/IO/Request.php +++ b/src/IO/Request.php @@ -7,7 +7,7 @@ * @link https://www.bulkgate.com/ */ -use BulkGate\Plugin\{JsonException, Strict, Utils\Compress, Utils\Json}; +use BulkGate\Plugin\{JsonException, Strict, Utils\Json}; class Request { diff --git a/src/IO/Response.php b/src/IO/Response.php index 8e5bb7e..fc628e2 100644 --- a/src/IO/Response.php +++ b/src/IO/Response.php @@ -8,7 +8,7 @@ */ use BulkGate\Plugin\{AuthenticateException, Helpers, InvalidResponseException, Strict, Utils\JsonArray}; -use function is_string; +use function array_key_exists, is_string, array_key_first, is_array; class Response { @@ -49,10 +49,7 @@ private function setData(array $decoded): void throw new InvalidResponseException('empty_response'); } - if (isset($decoded['error'])) - { - throw new InvalidResponseException(is_string($decoded['error']) ? $decoded['error'] : 'unknown_error'); - } + $this->checkError($decoded); if (isset($decoded['signal']) && $decoded['signal'] === 'authenticate') { @@ -63,6 +60,32 @@ private function setData(array $decoded): void } + /** + * @param array $array + * @throws InvalidResponseException + */ + private function checkError(array $array): void + { + if (array_key_exists('error', $array)) + { + if (is_string($array['error'])) + { + throw new InvalidResponseException($array['error']); + } + else if (is_array($array['error']) && !empty($array['error'])) + { + $key = array_key_first($array['error']); + + throw new InvalidResponseException($array['error'][$key]); + } + else + { + throw new InvalidResponseException('unknown_error'); + } + } + } + + /** * @return mixed */ diff --git a/src/Settings/Repository/Entity/Setting.php b/src/Settings/Repository/Entity/Setting.php index f99996d..aef5cc1 100644 --- a/src/Settings/Repository/Entity/Setting.php +++ b/src/Settings/Repository/Entity/Setting.php @@ -41,12 +41,12 @@ class Setting implements Entity */ public function __construct(array $list = []) { - $this->scope = (string)($list['scope'] ?? 'main'); - $this->key = (string)($list['key'] ?? 'unknown'); - $this->type = (string)($list['type'] ?? Helpers::detectType($list['value'] ?? '') ?? 'string'); + $this->scope = (string) ($list['scope'] ?? 'main'); + $this->key = (string) ($list['key'] ?? 'unknown'); + $this->type = (string) ($list['type'] ?? Helpers::detectType($list['value'] ?? '') ?? 'string'); $this->value = is_string($list['value'] ?? '') ? Helpers::deserializeValue($list['value'] ?? '', $this->type) : $list['value'] ?? ''; - $this->datetime = (int)($list['datetime'] ?? time()); - $this->order = (int)($list['order'] ?? 0); - $this->synchronize_flag = Helpers::checkEnum((string)($list['synchronize_flag'] ?? self::SynchronizeDefault), self::SynchronizeFlags, self::SynchronizeDefault); + $this->datetime = (int) ($list['datetime'] ?? time()); + $this->order = (int) ($list['order'] ?? 0); + $this->synchronize_flag = Helpers::checkEnum((string) ($list['synchronize_flag'] ?? self::SynchronizeDefault), self::SynchronizeFlags, self::SynchronizeDefault); } } diff --git a/src/Settings/Repository/SettingsDatabase.php b/src/Settings/Repository/SettingsDatabase.php index 16e027e..7f5b333 100644 --- a/src/Settings/Repository/SettingsDatabase.php +++ b/src/Settings/Repository/SettingsDatabase.php @@ -78,7 +78,7 @@ public function createTable(): void "`key` varchar(50) NOT NULL," . "`type` varchar(50) NOT NULL DEFAULT 'string'," . "`value` longtext DEFAULT NULL," . - "`datetime` int(11) NOT NULL DEFAULT unix_timestamp(current_timestamp())," . + "`datetime` int(11) NOT NULL," . "`order` int(11) NOT NULL DEFAULT 0," . "`synchronize_flag` varchar(50) NOT NULL DEFAULT 'none' COMMENT 'none/add/change/delete'," . "PRIMARY KEY (`scope`,`key`)," . diff --git a/src/User/Sign.php b/src/User/Sign.php index 9974b16..994696d 100644 --- a/src/User/Sign.php +++ b/src/User/Sign.php @@ -7,8 +7,7 @@ * @link https://www.bulkgate.com/ */ -use BulkGate\Plugin\{InvalidResponseException, IO\Connection, IO\Request, IO\Url, Settings\Settings, Strict, Utils\Jwt}; -use function array_merge; +use BulkGate\{Plugin\Eshop\Configuration, Plugin\InvalidResponseException, Plugin\IO\Connection, Plugin\IO\Request, Plugin\IO\Url, Plugin\Settings\Settings, Plugin\Strict, Plugin\Utils\Jwt}; class Sign { @@ -20,34 +19,35 @@ class Sign private Url $url; + private Configuration $configuration; - public function __construct(Settings $settings, Connection $connection, Url $url) + + public function __construct(Settings $settings, Connection $connection, Url $url, Configuration $configuration) { $this->settings = $settings; $this->connection = $connection; $this->url = $url; + $this->configuration = $configuration; } - /** - * @return array{token: string} - */ - public function authenticate(): array + public function authenticate(): ?string { - return [ - 'token' => Jwt::encode([ - 'application_id' => $this->settings->load('static:application_id'), - // todo - 'expire' => time() + 300 - ], - $this->settings->load('static:application_token') - ) ?? 'guest' - ]; + $token = $this->settings->load('static:application_token'); + + return Jwt::encode([ + 'application_id' => $this->settings->load('static:application_id'), + 'application_url' => $this->configuration->url(), + 'application_product' => $this->configuration->product(), + 'application_language' => $this->settings->load('main:language') ?? 'en', + 'guest' => $token === null, + 'expire' => time() + 300 + ], $token ?? ''); } /** - * @return array{token: string, redirect: string|null}|array{error: string} + * @return array{token: string|null, redirect: string|null}|array{error: list} */ public function in(string $email, string $password, ?string $eshop_name = null, ?string $success_redirect = null): array { @@ -63,7 +63,7 @@ public function in(string $email, string $password, ?string $eshop_name = null, if (!isset($login['application_id']) || !isset($login['application_token'])) { - return ['error' => 'unknown_error']; + return ['error' => ['unknown_error']]; } $this->settings->install(); @@ -72,11 +72,11 @@ public function in(string $email, string $password, ?string $eshop_name = null, $this->settings->set('static:application_token', $login['application_token'], ['type' => 'string']); $this->settings->set('static:synchronize', 0, ['type' => 'int']); - return array_merge($this->authenticate(), ['redirect' => $success_redirect]); + return ['token' => $this->authenticate(), 'redirect' => $success_redirect]; } catch (InvalidResponseException $e) { - return ['error' => $e->getMessage()]; + return ['error' => [$e->getMessage()]]; } } diff --git a/tests/Settings/Repository/SettingsDatabaseTest.phpt b/tests/Settings/Repository/SettingsDatabaseTest.phpt index b5c2bcc..bc5ece5 100644 --- a/tests/Settings/Repository/SettingsDatabaseTest.phpt +++ b/tests/Settings/Repository/SettingsDatabaseTest.phpt @@ -101,7 +101,7 @@ class SettingsDatabaseTest extends TestCase { $repository = new SettingsDatabase($connection = Mockery::mock(Connection::class)); $connection->shouldReceive('table')->with('bulkgate_module')->twice()->andReturn('prefix_bulkgate_module'); - $connection->shouldReceive('execute')->with('CREATE TABLE IF NOT EXISTS `prefix_bulkgate_module` (`scope` varchar(50) NOT NULL DEFAULT \'main\',`key` varchar(50) NOT NULL,`type` varchar(50) NOT NULL DEFAULT \'string\',`value` longtext DEFAULT NULL,`datetime` int(11) NOT NULL DEFAULT unix_timestamp(current_timestamp()),`order` int(11) NOT NULL DEFAULT 0,`synchronize_flag` varchar(50) NOT NULL DEFAULT \'none\' COMMENT \'none/add/change/delete\',PRIMARY KEY (`scope`,`key`),KEY `synchronize_flag` (`synchronize_flag`),KEY `scope_synchronize_flag` (`scope`,`synchronize_flag`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;')->once()->andReturnNull(); + $connection->shouldReceive('execute')->with('CREATE TABLE IF NOT EXISTS `prefix_bulkgate_module` (`scope` varchar(50) NOT NULL DEFAULT \'main\',`key` varchar(50) NOT NULL,`type` varchar(50) NOT NULL DEFAULT \'string\',`value` longtext DEFAULT NULL,`datetime` int(11) NOT NULL,`order` int(11) NOT NULL DEFAULT 0,`synchronize_flag` varchar(50) NOT NULL DEFAULT \'none\' COMMENT \'none/add/change/delete\',PRIMARY KEY (`scope`,`key`),KEY `synchronize_flag` (`synchronize_flag`),KEY `scope_synchronize_flag` (`scope`,`synchronize_flag`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;')->once()->andReturnNull(); $connection->shouldReceive('execute')->with('ALTER TABLE `prefix_bulkgate_module` ENGINE=InnoDB;')->once(); $repository->createTable(); diff --git a/tests/User/SignTest.phpt b/tests/User/SignTest.phpt index 1f21e52..4e04f71 100644 --- a/tests/User/SignTest.phpt +++ b/tests/User/SignTest.phpt @@ -9,7 +9,7 @@ namespace BulkGate\Plugin\User\Test; use Mockery; use Tester\{Assert, Expect, TestCase}; -use BulkGate\Plugin\{InvalidResponseException, IO\Connection, IO\Request, IO\Response, IO\Url, Settings\Settings, User\Sign}; +use BulkGate\Plugin\{Eshop\ConfigurationDefault, InvalidResponseException, IO\Connection, IO\Request, IO\Response, IO\Url, Settings\Settings, User\Sign}; use function json_encode; require_once __DIR__ . '/../bootstrap.php'; @@ -18,21 +18,19 @@ class SignTest extends TestCase { public function testAuthenticate(): void { - $sign = new Sign($settings = Mockery::mock(Settings::class), Mockery::mock(Connection::class), new Url()); + $sign = new Sign($settings = Mockery::mock(Settings::class), Mockery::mock(Connection::class), new Url(), new ConfigurationDefault('url', 'eshop', '1.0')); - $settings->shouldReceive('load')->with('static:application_id')->andReturn(12345); - $settings->shouldReceive('load')->with('static:application_token')->andReturn('test_application_token'); - - $result = $sign->authenticate(); + $settings->shouldReceive('load')->with('static:application_token')->once()->andReturn('test_application_token'); + $settings->shouldReceive('load')->with('static:application_id')->once()->andReturn(12345); + $settings->shouldReceive('load')->with('main:language')->once()->andReturn('cs'); - Assert::count(1, $result); - Assert::match('~^[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+$~', $result['token']); + Assert::match('~^[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+$~', $sign->authenticate()); } public function testIn(): void { - $sign = new Sign($settings = Mockery::mock(Settings::class), $connection = Mockery::mock(Connection::class), new Url()); + $sign = new Sign($settings = Mockery::mock(Settings::class), $connection = Mockery::mock(Connection::class), new Url(), new ConfigurationDefault('url', 'eshop', '1.0')); $settings->shouldReceive('install')->withNoArgs()->once(); $connection->shouldReceive('run')->with(Mockery::on(function (Request $request): bool { @@ -43,8 +41,9 @@ class SignTest extends TestCase 'application_id' => 12345, 'application_token' => 'test_application_token', ]]]]]))); - $settings->shouldReceive('set')->with('static:application_id', 12345, ['type' => 'int']); $settings->shouldReceive('set')->with('static:application_token', 'test_application_token', ['type' => 'string']); + $settings->shouldReceive('set')->with('static:application_id', 12345, ['type' => 'int']); + $settings->shouldReceive('load')->with('main:language')->once()->andReturn('cs'); $settings->shouldReceive('set')->with('static:synchronize', 0, ['type' => 'int']); $settings->shouldReceive('load')->with('static:application_id')->andReturn(12345); @@ -63,33 +62,33 @@ class SignTest extends TestCase public function testInInvalid(): void { - $sign = new Sign($settings = Mockery::mock(Settings::class), $connection = Mockery::mock(Connection::class), new Url()); + $sign = new Sign(Mockery::mock(Settings::class), $connection = Mockery::mock(Connection::class), new Url(), new ConfigurationDefault('url', 'eshop', '1.0')); $connection->shouldReceive('run')->with(Mockery::on(function (Request $request): bool { Assert::same('{"email":"test@example.com","password":"test_password","eshop_name":"Test Eshop"}', $request->serialize()); return true; }))->andReturn(new Response(json_encode(['data' => ['_generic' => ['server' => ['login' => []]]]]))); - Assert::same(['error' => 'unknown_error'], $sign->in('test@example.com', 'test_password', 'Test Eshop', 'test_success_redirect')); + Assert::same(['error' => ['unknown_error']], $sign->in('test@example.com', 'test_password', 'Test Eshop', 'test_success_redirect')); } public function testInError(): void { - $sign = new Sign($settings = Mockery::mock(Settings::class), $connection = Mockery::mock(Connection::class), new Url()); + $sign = new Sign(Mockery::mock(Settings::class), $connection = Mockery::mock(Connection::class), new Url(), new ConfigurationDefault('url', 'eshop', '1.0')); $connection->shouldReceive('run')->with(Mockery::on(function (Request $request): bool { Assert::same('{"email":"test@example.com","password":"test_password","eshop_name":"Test Eshop"}', $request->serialize()); return true; }))->andThrow(InvalidResponseException::class, 'test_error'); - Assert::same(['error' => 'test_error'], $sign->in('test@example.com', 'test_password', 'Test Eshop', 'test_success_redirect')); + Assert::same(['error' => ['test_error']], $sign->in('test@example.com', 'test_password', 'Test Eshop', 'test_success_redirect')); } public function testOut(): void { - $sign = new Sign($setting = Mockery::mock(Settings::class), Mockery::mock(Connection::class), new Url()); + $sign = new Sign($setting = Mockery::mock(Settings::class), Mockery::mock(Connection::class), new Url(), new ConfigurationDefault('url', 'eshop', '1.0')); $setting->shouldReceive('delete')->with('static:application_token')->andReturnNull(); $sign->out();