diff --git a/.editorconfig b/.editorconfig index c1e2c64..e795376 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,3 +10,6 @@ end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true + +[*.yaml] +indent_size = 2 diff --git a/.github/workflows/static-analysis.yaml b/.github/workflows/static-analysis.yaml new file mode 100644 index 0000000..f763077 --- /dev/null +++ b/.github/workflows/static-analysis.yaml @@ -0,0 +1,14 @@ +name: static analysis + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + +jobs: + tests: + uses: laravel/.github/.github/workflows/static-analysis.yml@main diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 0000000..33e6e49 --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,24 @@ +name: Tests + +on: ["push", "pull_request"] + +jobs: + ci: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.2 + tools: composer:v2 + coverage: xdebug + + - name: Install Dependencies + run: composer install --no-interaction --prefer-dist --optimize-autoloader + + - name: Tests + run: ./vendor/bin/pest diff --git a/.gitignore b/.gitignore index b840dac..2328e65 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ vendor +tools test.php *.cache +*.txt +*.lock diff --git a/README.md b/README.md new file mode 100644 index 0000000..5721ee1 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +## IPay Unoffical Client + +```php +guest()->login([ + 'userName' => 'yourUsername', + 'accessCode' => 'yourPassword' + ]); + + foreach ($session->historyTransactions([ + 'accountNumber' => $session->customer->accountNumber, + 'startDate' => new \DateTimeImmutable('-5 days'), + ]) as $transaction) { + echo $transaction->remark.PHP_EOL; + } +} catch (Throwable $e) { + echo $e->getMessage(); +} +``` diff --git a/composer.json b/composer.json index 62382b4..9405a6e 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,8 @@ "type": "library", "license": "MIT", "autoload": { - "classmap": ["src"] + "classmap": ["src"], + "files": ["src/functions.php"] }, "authors": [ { @@ -12,22 +13,28 @@ "email": "thanh1101dev@gmail.com" } ], - "minimum-stability": "dev", + "minimum-stability": "stable", "prefer-stable": true, "require": { "php-http/httplug": "^2.4", "php-http/client-common": "^2.7", "nette/utils": "^4.0", - "league/object-mapper": "dev-main" + "eventsauce/object-hydrator": "^1.4", + "symfony/options-resolver": "^7.1", + "symfony/dom-crawler": "^7.1", + "phpseclib/phpseclib": "^2.0", + "symfony/var-exporter": "^7.1" }, "require-dev": { "php-http/curl-client": "^2.3", "nyholm/psr7": "^1.8", - "phpstan/phpstan": "^1.11" + "phpstan/phpstan": "^1.11", + "pestphp/pest": "^2.34" }, "config": { "allow-plugins": { - "php-http/discovery": true + "php-http/discovery": true, + "pestphp/pest-plugin": true } } } diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 569b372..0000000 --- a/composer.lock +++ /dev/null @@ -1,1140 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "aea4d0667f4344934e73e1531cdcdf2e", - "packages": [ - { - "name": "clue/stream-filter", - "version": "v1.7.0", - "source": { - "type": "git", - "url": "https://github.com/clue/stream-filter.git", - "reference": "049509fef80032cb3f051595029ab75b49a3c2f7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/clue/stream-filter/zipball/049509fef80032cb3f051595029ab75b49a3c2f7", - "reference": "049509fef80032cb3f051595029ab75b49a3c2f7", - "shasum": "" - }, - "require": { - "php": ">=5.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "Clue\\StreamFilter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering" - } - ], - "description": "A simple and modern approach to stream filtering in PHP", - "homepage": "https://github.com/clue/stream-filter", - "keywords": [ - "bucket brigade", - "callback", - "filter", - "php_user_filter", - "stream", - "stream_filter_append", - "stream_filter_register" - ], - "support": { - "issues": "https://github.com/clue/stream-filter/issues", - "source": "https://github.com/clue/stream-filter/tree/v1.7.0" - }, - "funding": [ - { - "url": "https://clue.engineering/support", - "type": "custom" - }, - { - "url": "https://github.com/clue", - "type": "github" - } - ], - "time": "2023-12-20T15:40:13+00:00" - }, - { - "name": "league/object-mapper", - "version": "dev-main", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/object-mapper.git", - "reference": "9cbcd21f3ce81aa2d614f65347f6abc901941ea7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/object-mapper/zipball/9cbcd21f3ce81aa2d614f65347f6abc901941ea7", - "reference": "9cbcd21f3ce81aa2d614f65347f6abc901941ea7", - "shasum": "" - }, - "require": { - "ext-fileinfo": "*", - "php": "^8.1" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.4", - "league/construct-finder": "^1.1", - "phpbench/phpbench": "^1.2", - "phpstan/phpstan": "^1.7", - "phpunit/phpunit": "^10.0.0", - "ramsey/uuid": "^4.2" - }, - "suggest": { - "league/construct-finder": "Find all classes in a directory for the best dumped hydrators." - }, - "default-branch": true, - "type": "library", - "autoload": { - "psr-4": { - "League\\ObjectMapper\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Frank de Jonge", - "email": "info@frankdejonge.nl" - } - ], - "description": "Converts structured data into strict objects.", - "keywords": [ - "construction", - "constructor", - "hydration", - "mapper" - ], - "support": { - "issues": "https://github.com/thephpleague/object-mapper/issues", - "source": "https://github.com/thephpleague/object-mapper/tree/main" - }, - "funding": [ - { - "url": "https://github.com/frankdejonge", - "type": "github" - } - ], - "time": "2023-12-16T09:26:10+00:00" - }, - { - "name": "nette/utils", - "version": "v4.0.4", - "source": { - "type": "git", - "url": "https://github.com/nette/utils.git", - "reference": "d3ad0aa3b9f934602cb3e3902ebccf10be34d218" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/d3ad0aa3b9f934602cb3e3902ebccf10be34d218", - "reference": "d3ad0aa3b9f934602cb3e3902ebccf10be34d218", - "shasum": "" - }, - "require": { - "php": ">=8.0 <8.4" - }, - "conflict": { - "nette/finder": "<3", - "nette/schema": "<1.2.2" - }, - "require-dev": { - "jetbrains/phpstorm-attributes": "dev-master", - "nette/tester": "^2.5", - "phpstan/phpstan": "^1.0", - "tracy/tracy": "^2.9" - }, - "suggest": { - "ext-gd": "to use Image", - "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", - "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", - "ext-json": "to use Nette\\Utils\\Json", - "ext-mbstring": "to use Strings::lower() etc...", - "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause", - "GPL-2.0-only", - "GPL-3.0-only" - ], - "authors": [ - { - "name": "David Grudl", - "homepage": "https://davidgrudl.com" - }, - { - "name": "Nette Community", - "homepage": "https://nette.org/contributors" - } - ], - "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", - "homepage": "https://nette.org", - "keywords": [ - "array", - "core", - "datetime", - "images", - "json", - "nette", - "paginator", - "password", - "slugify", - "string", - "unicode", - "utf-8", - "utility", - "validation" - ], - "support": { - "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.4" - }, - "time": "2024-01-17T16:50:36+00:00" - }, - { - "name": "php-http/client-common", - "version": "2.7.1", - "source": { - "type": "git", - "url": "https://github.com/php-http/client-common.git", - "reference": "1e19c059b0e4d5f717bf5d524d616165aeab0612" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/client-common/zipball/1e19c059b0e4d5f717bf5d524d616165aeab0612", - "reference": "1e19c059b0e4d5f717bf5d524d616165aeab0612", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0", - "php-http/httplug": "^2.0", - "php-http/message": "^1.6", - "psr/http-client": "^1.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0 || ^2.0", - "symfony/options-resolver": "~4.0.15 || ~4.1.9 || ^4.2.1 || ^5.0 || ^6.0 || ^7.0", - "symfony/polyfill-php80": "^1.17" - }, - "require-dev": { - "doctrine/instantiator": "^1.1", - "guzzlehttp/psr7": "^1.4", - "nyholm/psr7": "^1.2", - "phpspec/phpspec": "^5.1 || ^6.3 || ^7.1", - "phpspec/prophecy": "^1.10.2", - "phpunit/phpunit": "^7.5.20 || ^8.5.33 || ^9.6.7" - }, - "suggest": { - "ext-json": "To detect JSON responses with the ContentTypePlugin", - "ext-libxml": "To detect XML responses with the ContentTypePlugin", - "php-http/cache-plugin": "PSR-6 Cache plugin", - "php-http/logger-plugin": "PSR-3 Logger plugin", - "php-http/stopwatch-plugin": "Symfony Stopwatch plugin" - }, - "type": "library", - "autoload": { - "psr-4": { - "Http\\Client\\Common\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - } - ], - "description": "Common HTTP Client implementations and tools for HTTPlug", - "homepage": "http://httplug.io", - "keywords": [ - "client", - "common", - "http", - "httplug" - ], - "support": { - "issues": "https://github.com/php-http/client-common/issues", - "source": "https://github.com/php-http/client-common/tree/2.7.1" - }, - "time": "2023-11-30T10:31:25+00:00" - }, - { - "name": "php-http/httplug", - "version": "2.4.0", - "source": { - "type": "git", - "url": "https://github.com/php-http/httplug.git", - "reference": "625ad742c360c8ac580fcc647a1541d29e257f67" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/httplug/zipball/625ad742c360c8ac580fcc647a1541d29e257f67", - "reference": "625ad742c360c8ac580fcc647a1541d29e257f67", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0", - "php-http/promise": "^1.1", - "psr/http-client": "^1.0", - "psr/http-message": "^1.0 || ^2.0" - }, - "require-dev": { - "friends-of-phpspec/phpspec-code-coverage": "^4.1 || ^5.0 || ^6.0", - "phpspec/phpspec": "^5.1 || ^6.0 || ^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Http\\Client\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Eric GELOEN", - "email": "geloen.eric@gmail.com" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://sagikazarmark.hu" - } - ], - "description": "HTTPlug, the HTTP client abstraction for PHP", - "homepage": "http://httplug.io", - "keywords": [ - "client", - "http" - ], - "support": { - "issues": "https://github.com/php-http/httplug/issues", - "source": "https://github.com/php-http/httplug/tree/2.4.0" - }, - "time": "2023-04-14T15:10:03+00:00" - }, - { - "name": "php-http/message", - "version": "1.16.1", - "source": { - "type": "git", - "url": "https://github.com/php-http/message.git", - "reference": "5997f3289332c699fa2545c427826272498a2088" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/message/zipball/5997f3289332c699fa2545c427826272498a2088", - "reference": "5997f3289332c699fa2545c427826272498a2088", - "shasum": "" - }, - "require": { - "clue/stream-filter": "^1.5", - "php": "^7.2 || ^8.0", - "psr/http-message": "^1.1 || ^2.0" - }, - "provide": { - "php-http/message-factory-implementation": "1.0" - }, - "require-dev": { - "ergebnis/composer-normalize": "^2.6", - "ext-zlib": "*", - "guzzlehttp/psr7": "^1.0 || ^2.0", - "laminas/laminas-diactoros": "^2.0 || ^3.0", - "php-http/message-factory": "^1.0.2", - "phpspec/phpspec": "^5.1 || ^6.3 || ^7.1", - "slim/slim": "^3.0" - }, - "suggest": { - "ext-zlib": "Used with compressor/decompressor streams", - "guzzlehttp/psr7": "Used with Guzzle PSR-7 Factories", - "laminas/laminas-diactoros": "Used with Diactoros Factories", - "slim/slim": "Used with Slim Framework PSR-7 implementation" - }, - "type": "library", - "autoload": { - "files": [ - "src/filters.php" - ], - "psr-4": { - "Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - } - ], - "description": "HTTP Message related tools", - "homepage": "http://php-http.org", - "keywords": [ - "http", - "message", - "psr-7" - ], - "support": { - "issues": "https://github.com/php-http/message/issues", - "source": "https://github.com/php-http/message/tree/1.16.1" - }, - "time": "2024-03-07T13:22:09+00:00" - }, - { - "name": "php-http/promise", - "version": "1.3.1", - "source": { - "type": "git", - "url": "https://github.com/php-http/promise.git", - "reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/promise/zipball/fc85b1fba37c169a69a07ef0d5a8075770cc1f83", - "reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "friends-of-phpspec/phpspec-code-coverage": "^4.3.2 || ^6.3", - "phpspec/phpspec": "^5.1.2 || ^6.2 || ^7.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Http\\Promise\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Joel Wurtz", - "email": "joel.wurtz@gmail.com" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - } - ], - "description": "Promise used for asynchronous HTTP requests", - "homepage": "http://httplug.io", - "keywords": [ - "promise" - ], - "support": { - "issues": "https://github.com/php-http/promise/issues", - "source": "https://github.com/php-http/promise/tree/1.3.1" - }, - "time": "2024-03-15T13:55:21+00:00" - }, - { - "name": "psr/http-client", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-client.git", - "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", - "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", - "shasum": "" - }, - "require": { - "php": "^7.0 || ^8.0", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Client\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP clients", - "homepage": "https://github.com/php-fig/http-client", - "keywords": [ - "http", - "http-client", - "psr", - "psr-18" - ], - "support": { - "source": "https://github.com/php-fig/http-client" - }, - "time": "2023-09-23T14:17:50+00:00" - }, - { - "name": "psr/http-factory", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "shasum": "" - }, - "require": { - "php": ">=7.1", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", - "keywords": [ - "factory", - "http", - "message", - "psr", - "psr-17", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-factory" - }, - "time": "2024-04-15T12:06:14+00:00" - }, - { - "name": "psr/http-message", - "version": "2.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/2.0" - }, - "time": "2023-04-04T09:54:51+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v3.5.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-04-18T09:32:20+00:00" - }, - { - "name": "symfony/options-resolver", - "version": "v7.1.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/options-resolver.git", - "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/47aa818121ed3950acd2b58d1d37d08a94f9bf55", - "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\OptionsResolver\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides an improved replacement for the array_replace PHP function", - "homepage": "https://symfony.com", - "keywords": [ - "config", - "configuration", - "options" - ], - "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.1.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-05-31T14:57:53+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.30.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-05-31T15:07:36+00:00" - } - ], - "packages-dev": [ - { - "name": "nyholm/psr7", - "version": "1.8.1", - "source": { - "type": "git", - "url": "https://github.com/Nyholm/psr7.git", - "reference": "aa5fc277a4f5508013d571341ade0c3886d4d00e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Nyholm/psr7/zipball/aa5fc277a4f5508013d571341ade0c3886d4d00e", - "reference": "aa5fc277a4f5508013d571341ade0c3886d4d00e", - "shasum": "" - }, - "require": { - "php": ">=7.2", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.1 || ^2.0" - }, - "provide": { - "php-http/message-factory-implementation": "1.0", - "psr/http-factory-implementation": "1.0", - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "http-interop/http-factory-tests": "^0.9", - "php-http/message-factory": "^1.0", - "php-http/psr7-integration-tests": "^1.0", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.4", - "symfony/error-handler": "^4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.8-dev" - } - }, - "autoload": { - "psr-4": { - "Nyholm\\Psr7\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com" - }, - { - "name": "Martijn van der Ven", - "email": "martijn@vanderven.se" - } - ], - "description": "A fast PHP7 implementation of PSR-7", - "homepage": "https://tnyholm.se", - "keywords": [ - "psr-17", - "psr-7" - ], - "support": { - "issues": "https://github.com/Nyholm/psr7/issues", - "source": "https://github.com/Nyholm/psr7/tree/1.8.1" - }, - "funding": [ - { - "url": "https://github.com/Zegnat", - "type": "github" - }, - { - "url": "https://github.com/nyholm", - "type": "github" - } - ], - "time": "2023-11-13T09:31:12+00:00" - }, - { - "name": "php-http/curl-client", - "version": "2.3.2", - "source": { - "type": "git", - "url": "https://github.com/php-http/curl-client.git", - "reference": "0b869922458b1cde9137374545ed4fff7ac83623" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/curl-client/zipball/0b869922458b1cde9137374545ed4fff7ac83623", - "reference": "0b869922458b1cde9137374545ed4fff7ac83623", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "php": "^7.4 || ^8.0", - "php-http/discovery": "^1.6", - "php-http/httplug": "^2.0", - "php-http/message": "^1.2", - "psr/http-client": "^1.0", - "psr/http-factory-implementation": "^1.0", - "symfony/options-resolver": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "provide": { - "php-http/async-client-implementation": "1.0", - "php-http/client-implementation": "1.0", - "psr/http-client-implementation": "1.0" - }, - "require-dev": { - "guzzlehttp/psr7": "^2.0", - "laminas/laminas-diactoros": "^2.0", - "php-http/client-integration-tests": "^3.0", - "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^7.5 || ^9.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Http\\Client\\Curl\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Михаил Красильников", - "email": "m.krasilnikov@yandex.ru" - } - ], - "description": "PSR-18 and HTTPlug Async client with cURL", - "homepage": "http://php-http.org", - "keywords": [ - "curl", - "http", - "psr-18" - ], - "support": { - "issues": "https://github.com/php-http/curl-client/issues", - "source": "https://github.com/php-http/curl-client/tree/2.3.2" - }, - "time": "2024-03-03T08:21:07+00:00" - }, - { - "name": "php-http/discovery", - "version": "1.19.4", - "source": { - "type": "git", - "url": "https://github.com/php-http/discovery.git", - "reference": "0700efda8d7526335132360167315fdab3aeb599" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/discovery/zipball/0700efda8d7526335132360167315fdab3aeb599", - "reference": "0700efda8d7526335132360167315fdab3aeb599", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0|^2.0", - "php": "^7.1 || ^8.0" - }, - "conflict": { - "nyholm/psr7": "<1.0", - "zendframework/zend-diactoros": "*" - }, - "provide": { - "php-http/async-client-implementation": "*", - "php-http/client-implementation": "*", - "psr/http-client-implementation": "*", - "psr/http-factory-implementation": "*", - "psr/http-message-implementation": "*" - }, - "require-dev": { - "composer/composer": "^1.0.2|^2.0", - "graham-campbell/phpspec-skip-example-extension": "^5.0", - "php-http/httplug": "^1.0 || ^2.0", - "php-http/message-factory": "^1.0", - "phpspec/phpspec": "^5.1 || ^6.1 || ^7.3", - "sebastian/comparator": "^3.0.5 || ^4.0.8", - "symfony/phpunit-bridge": "^6.4.4 || ^7.0.1" - }, - "type": "composer-plugin", - "extra": { - "class": "Http\\Discovery\\Composer\\Plugin", - "plugin-optional": true - }, - "autoload": { - "psr-4": { - "Http\\Discovery\\": "src/" - }, - "exclude-from-classmap": [ - "src/Composer/Plugin.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - } - ], - "description": "Finds and installs PSR-7, PSR-17, PSR-18 and HTTPlug implementations", - "homepage": "http://php-http.org", - "keywords": [ - "adapter", - "client", - "discovery", - "factory", - "http", - "message", - "psr17", - "psr7" - ], - "support": { - "issues": "https://github.com/php-http/discovery/issues", - "source": "https://github.com/php-http/discovery/tree/1.19.4" - }, - "time": "2024-03-29T13:00:05+00:00" - }, - { - "name": "phpstan/phpstan", - "version": "1.11.5", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "490f0ae1c92b082f154681d7849aee776a7c1443" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/490f0ae1c92b082f154681d7849aee776a7c1443", - "reference": "490f0ae1c92b082f154681d7849aee776a7c1443", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": [ - "phpstan", - "phpstan.phar" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan - PHP Static Analysis Tool", - "keywords": [ - "dev", - "static analysis" - ], - "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" - }, - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://github.com/phpstan", - "type": "github" - } - ], - "time": "2024-06-17T15:10:54+00:00" - } - ], - "aliases": [], - "minimum-stability": "dev", - "stability-flags": { - "league/object-mapper": 20 - }, - "prefer-stable": true, - "prefer-lowest": false, - "platform": [], - "platform-dev": [], - "plugin-api-version": "2.6.0" -} diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000..aab4991 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,2 @@ +parameters: + ignoreErrors: [] diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 6e451fa..b9ca222 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,4 +1,7 @@ parameters: - level: 6 + level: 8 paths: - src + +includes: + - phpstan-baseline.neon diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..0c12bb9 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,17 @@ + + + + + ./tests + + + + + ./src + + + diff --git a/src/Api/AbstractApi.php b/src/Api/AbstractApi.php index 04ca40c..1f97ba1 100644 --- a/src/Api/AbstractApi.php +++ b/src/Api/AbstractApi.php @@ -2,52 +2,64 @@ namespace IPay\Api; +use EventSauce\ObjectHydrator\DefinitionProvider; +use EventSauce\ObjectHydrator\KeyFormatterWithoutConversion; +use EventSauce\ObjectHydrator\ObjectMapper; +use EventSauce\ObjectHydrator\ObjectMapperUsingReflection; use IPay\IPayClient; -use League\ObjectMapper\KeyFormatterWithoutConversion; -use League\ObjectMapper\ObjectMapper; -use League\ObjectMapper\ObjectMapperUsingReflection; -use League\ObjectMapper\ReflectionDefinitionProvider; use Nette\Utils\Json; +use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @template T of SessionInterface + */ abstract class AbstractApi { - private ObjectMapper $objectMapper; + protected ObjectMapper $objectMapper; + /** + * @param T $session + */ public function __construct( - protected IPayClient $client, + protected IPayClient $iPayClient, + private SessionInterface $session, ) { $this->objectMapper = new ObjectMapperUsingReflection( - new ReflectionDefinitionProvider( + new DefinitionProvider( keyFormatter: new KeyFormatterWithoutConversion(), ), ); } /** - * @param string[] $data + * @param string[] $parameters * * @return mixed[] */ - protected function post(string $uri, array $data = []): array + protected function post(string $uri, array $parameters = []): array { - $response = $this->client->getClient()->post( - $uri, + $response = $this->iPayClient->getClient()->post( + sprintf('ipay/wa/%s', $uri), [], - $this->configureFieldBuilder( - FieldBuilder::with($data) - )->encrypt() + BodyBuilder::from($parameters) + ->enhance($this->getSession()->getRequestParameters()) + ->build() + ->encrypt() ); return Json::decode((string) $response->getBody(), true); } - protected function configureFieldBuilder(FieldBuilder $builder): FieldBuilder + protected static function createOptionsResolver(): OptionsResolver { - return $builder->withRequiredFields(); + return new OptionsResolver(); } - public function getObjectMapper(): ObjectMapper + /** + * @return T + */ + public function getSession(): SessionInterface { - return $this->objectMapper; + return $this->session; } } diff --git a/src/Api/Auth.php b/src/Api/Auth.php deleted file mode 100644 index e6dbcde..0000000 --- a/src/Api/Auth.php +++ /dev/null @@ -1,17 +0,0 @@ -post('/signIn', get_defined_vars()); - - return new Session($result['sessionId'], $this->client); - } -} diff --git a/src/Api/AuthenticatedApi.php b/src/Api/AuthenticatedApi.php new file mode 100644 index 0000000..6202fad --- /dev/null +++ b/src/Api/AuthenticatedApi.php @@ -0,0 +1,122 @@ + + */ +final class AuthenticatedApi extends AbstractApi +{ + use LazyGhostTrait; + + public Customer $customer; + + /** @var list */ + public array $accounts; + + public function __construct(IPayClient $iPayClient, AuthenticatedSession $session) + { + parent::__construct($iPayClient, $session); + self::createLazyGhost( + initializer: $this->populateLazyProperties(...), + instance: $this, + ); + } + + private function populateLazyProperties(): void + { + $this->customer = $this->customer(); + $this->accounts = $this->accounts(); + } + + /** + * @throws \IPay\Exception\SessionException + */ + private function customer(): Customer + { + return $this->objectMapper->hydrateObject( + Customer::class, + $this->post('getCustomerDetails')['customerInfo'], + ); + } + + /** + * @return list + * + * @throws \IPay\Exception\SessionException + */ + private function accounts(): array + { + return $this->objectMapper->hydrateObjects( + Account::class, + $this->post('getEntitiesAndAccounts')['accounts'], + )->toArray(); + } + + /** + * @param array{ + * accountNumber?: string, + * tranType?: 'Credit'|'Debit'|'', + * startDate?: \DateTimeInterface, + * endDate?: \DateTimeInterface, + * } $parameters + * + * @return \Iterator + * + * @throws \IPay\Exception\SessionException + */ + public function historyTransactions(array $parameters): \Iterator + { + $datetimeNormalizer = static function ( + Options $resolver, + \DateTimeInterface $value + ): string { + return $value->format('Y-m-d'); + }; + + $resolver = self::createOptionsResolver() + ->setRequired([ + 'accountNumber', + 'tranType', + 'startDate', + 'endDate', + ]) + ->setAllowedTypes('accountNumber', 'string') + ->setAllowedValues('tranType', ['Credit', 'Debit', '']) + ->setAllowedTypes('startDate', \DateTimeInterface::class) + ->setAllowedTypes('endDate', \DateTimeInterface::class) + ->setNormalizer('startDate', $datetimeNormalizer) + ->setNormalizer('endDate', $datetimeNormalizer) + ->setDefaults([ + 'accountNumber' => $this->customer->accountNumber, + 'tranType' => 'Credit', + 'startDate' => new \DateTimeImmutable(), + 'endDate' => new \DateTimeImmutable(), + ]) + ; + + $parameters = $resolver->resolve($parameters); + + $parameters['pageNumber'] = 0; + do { + $transactions = $this->post( + 'getHistTransactions', + $parameters + )['transactions']; + foreach ($this->objectMapper->hydrateObjects( + Transaction::class, + $transactions + )->getIterator() as $transaction) { + yield $transaction; + } + ++$parameters['pageNumber']; + } while (count($transactions) > 0); + } +} diff --git a/src/Api/AuthenticatedSession.php b/src/Api/AuthenticatedSession.php new file mode 100644 index 0000000..edd8640 --- /dev/null +++ b/src/Api/AuthenticatedSession.php @@ -0,0 +1,15 @@ + $this->id, ...parent::getRequestParameters()]; + } +} diff --git a/src/Api/FieldBuilder.php b/src/Api/BodyBuilder.php similarity index 65% rename from src/Api/FieldBuilder.php rename to src/Api/BodyBuilder.php index f013b4c..42b3db2 100644 --- a/src/Api/FieldBuilder.php +++ b/src/Api/BodyBuilder.php @@ -4,12 +4,11 @@ use IPay\Encryption\Encrypter; use Nette\Utils\Json; -use Nette\Utils\Random; /** * @extends \ArrayObject */ -final class FieldBuilder extends \ArrayObject implements \Stringable, \JsonSerializable +final class BodyBuilder extends \ArrayObject implements \Stringable, \JsonSerializable { /** * @param string[] $data @@ -22,17 +21,17 @@ private function __construct(array $data) /** * @param string[] $data */ - public static function with(array $data): static + public static function from(array $data): static { return new static($data); } - public function withRequiredFields(): self + /** + * @param string[] $parameters + */ + public function enhance(array $parameters): static { - $this['lang'] = 'en'; - $this['requestId'] = Random::generate(12, '0-9A-Z').'|'.time(); - - return $this; + return static::from($this->getArrayCopy() + $parameters); } public function build(): self @@ -46,9 +45,7 @@ public function build(): self public function encrypt(): string { - return new static([ - 'encrypted' => Encrypter::encrypt($this->build()), - ]); + return static::from(['encrypted' => Encrypter::encrypt($this)]); } public function __toString(): string diff --git a/src/Api/Session.php b/src/Api/Session.php deleted file mode 100644 index e8ed17e..0000000 --- a/src/Api/Session.php +++ /dev/null @@ -1,31 +0,0 @@ -getObjectMapper()->hydrateObject( - Customer::class, - $this->post('/getCustomerDetails'), - ); - } - - protected function configureFieldBuilder(FieldBuilder $builder): FieldBuilder - { - $builder['sessionId'] = $this->id; - - return parent::configureFieldBuilder($builder); - } -} diff --git a/src/Api/SessionInterface.php b/src/Api/SessionInterface.php new file mode 100644 index 0000000..bada074 --- /dev/null +++ b/src/Api/SessionInterface.php @@ -0,0 +1,11 @@ + + */ +final class UnauthenticatedApi extends AbstractApi +{ + /** + * @param array{ + * userName: string, + * accessCode: string, + * } $credentials + * + * @throws \IPay\Exception\LoginException + */ + public function login(array $credentials): AuthenticatedApi + { + $resolver = self::createOptionsResolver() + ->setRequired([ + 'userName', + 'accessCode', + ]) + ->setAllowedTypes('userName', 'string') + ->setAllowedTypes('accessCode', 'string') + ; + + $parameters = $resolver->resolve($credentials) + $this->bypassCaptcha(); + + /** @var array{sessionId: string, ...} */ + $result = $this->post('signIn', $parameters); + + return new AuthenticatedApi( + $this->iPayClient, + new AuthenticatedSession($result['sessionId']) + ); + } + + /** + * @return array{captchaId:string,captchaCode:string} + */ + private function bypassCaptcha(): array + { + $captchaId = Random::generate(9, '0-9a-zA-Z'); + $svg = (string) $this->iPayClient->getClient() + ->get(sprintf('api/get-captcha/%s', $captchaId)) + ->getBody(); + $captchaCode = CaptchaSolver::solve($svg); + + return compact('captchaId', 'captchaCode'); + } +} diff --git a/src/Api/UnauthenticatedSession.php b/src/Api/UnauthenticatedSession.php new file mode 100644 index 0000000..d6b5bd9 --- /dev/null +++ b/src/Api/UnauthenticatedSession.php @@ -0,0 +1,16 @@ + 'en', + 'requestId' => Random::generate(12, '0-9A-Z').'|'.time(), + ]; + } +} diff --git a/src/Captcha/CaptchaSolver.php b/src/Captcha/CaptchaSolver.php new file mode 100644 index 0000000..2370241 --- /dev/null +++ b/src/Captcha/CaptchaSolver.php @@ -0,0 +1,42 @@ + 0, + 49 => 1, + 53 => 2, + 70 => 3, + 76 => 4, + 58 => 5, + 64 => 6, + 50 => 7, + 75 => 8, + 69 => 9, + ]; + + public static function solve(string $svg): string + { + /** @var string[] */ + $svgPathCommands = (new Crawler($svg)) + ->filterXPath('//path[@fill!="none"]') + ->each(function (Crawler $node): string { + return (string) $node->attr('d'); + }); + + sort($svgPathCommands, SORT_NATURAL); + + $result = ''; + foreach ($svgPathCommands as $svgPathCommand) { + /** @var string */ + $symbolicPath = preg_replace('/[^A-Z]/', '', $svgPathCommand); + $result .= static::LENGTH_TO_NUMBER_MAPPING[strlen($symbolicPath)]; + } + + return $result; + } +} diff --git a/src/Encryption/Encrypter.php b/src/Encryption/Encrypter.php index da4d9db..c20a8f1 100644 --- a/src/Encryption/Encrypter.php +++ b/src/Encryption/Encrypter.php @@ -2,38 +2,24 @@ namespace IPay\Encryption; -const IPAY_PUBLIC_KEY = <<loadKey(static::IPAY_PUBLIC_KEY); - return base64_encode($result); + return base64_encode($rsa->encrypt($message)); } } diff --git a/src/Entity/Account.php b/src/Entity/Account.php new file mode 100644 index 0000000..a2153a3 --- /dev/null +++ b/src/Entity/Account.php @@ -0,0 +1,23 @@ + 'name', @@ -10,29 +10,13 @@ 'jobTitle' => 'job', 'feeAcctNo' => 'accountNumber', ])] -readonly class Info +readonly class Customer { - /** - * @internal - */ public function __construct( public string $name, public string $phone, public string $job, - public string $accountNumber - ) { - } -} - -readonly class Customer -{ - /** - * @internal - */ - public function __construct( - public string $userName, - #[MapFrom('customerInfo')] - public Info $info, + public string $accountNumber, ) { } } diff --git a/src/Entity/Transaction.php b/src/Entity/Transaction.php new file mode 100644 index 0000000..4e9d0d5 --- /dev/null +++ b/src/Entity/Transaction.php @@ -0,0 +1,21 @@ +then(function (ResponseInterface $response): ResponseInterface { if (200 !== $response->getStatusCode()) { - /** @var object{errorCode:string} */ $error = Json::decode((string) $response->getBody()); - throw self::createException($error->errorCode); + throw self::createException($error); } return $response; }); } - private static function createException(string $code): \Throwable + /** + * @param \stdClass&object{errorCode: string, errorMessage?: string} $error + */ + private static function createException(\stdClass $error): \Throwable { - return match ($code) { - '96', '99' => new SessionExpiredException('The session has expired.'), - default => new \RuntimeException('Unknown error.'), + /** @var class-string<\Exception> */ + $class = match ($error->errorCode) { + 'LOGON_CREDENTIALS_REJECTED' => LoginException::class, + '96', '99' => SessionException::class, + default => \RuntimeException::class, }; + + return new $class($error->errorMessage ?? 'Unknown error.'); } } diff --git a/src/IPayClient.php b/src/IPayClient.php index 960a79d..e1bdf9f 100644 --- a/src/IPayClient.php +++ b/src/IPayClient.php @@ -9,7 +9,10 @@ use Http\Client\Common\PluginClient; use Http\Discovery\Psr17FactoryDiscovery; use Http\Discovery\Psr18ClientDiscovery; -use IPay\Api\Auth; +use IPay\Api\AuthenticatedApi; +use IPay\Api\AuthenticatedSession; +use IPay\Api\UnauthenticatedApi; +use IPay\Api\UnauthenticatedSession; use IPay\Http\Plugin\ExceptionThrower; final class IPayClient @@ -20,7 +23,7 @@ public static function create(): static new HttpMethodsClient( new PluginClient(Psr18ClientDiscovery::find(), [ new BaseUriPlugin(Psr17FactoryDiscovery::findUriFactory() - ->createUri('https://api-ipay.vietinbank.vn/ipay/wa') + ->createUri('https://api-ipay.vietinbank.vn') ), new ContentTypePlugin(), new ExceptionThrower(), @@ -41,8 +44,13 @@ public function getClient(): HttpMethodsClientInterface return $this->client; } - public function auth(): Auth + public function guest(): UnauthenticatedApi { - return new Auth($this); + return new UnauthenticatedApi($this, new UnauthenticatedSession()); + } + + public function session(string $id): AuthenticatedApi + { + return new AuthenticatedApi($this, new AuthenticatedSession($id)); } } diff --git a/src/functions.php b/src/functions.php new file mode 100644 index 0000000..844e2b7 --- /dev/null +++ b/src/functions.php @@ -0,0 +1,10 @@ +toBe($result); +})->with([ + 'captcha 1' => [__DIR__.'/Fixture/1.svg', '540701'], + 'captcha 2' => [__DIR__.'/Fixture/2.svg', '826778'], + 'captcha 3' => [__DIR__.'/Fixture/3.svg', '835697'], +]); diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php new file mode 100644 index 0000000..eba6be3 --- /dev/null +++ b/tests/Feature/ExampleTest.php @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/tests/Feature/Fixture/2.svg b/tests/Feature/Fixture/2.svg new file mode 100644 index 0000000..d261e9e --- /dev/null +++ b/tests/Feature/Fixture/2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/Feature/Fixture/3.svg b/tests/Feature/Fixture/3.svg new file mode 100644 index 0000000..80718fd --- /dev/null +++ b/tests/Feature/Fixture/3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 0000000..5949c61 --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,45 @@ +in('Feature'); + +/* +|-------------------------------------------------------------------------- +| Expectations +|-------------------------------------------------------------------------- +| +| When you're writing tests, you often need to check that values meet certain conditions. The +| "expect()" function gives you access to a set of "expectations" methods that you can use +| to assert different things. Of course, you may extend the Expectation API at any time. +| +*/ + +expect()->extend('toBeOne', function () { + return $this->toBe(1); +}); + +/* +|-------------------------------------------------------------------------- +| Functions +|-------------------------------------------------------------------------- +| +| While Pest is very powerful out-of-the-box, you may have some testing code specific to your +| project that you don't want to repeat in every file. Here you can also expose helpers as +| global functions to help you to reduce the number of lines of code in your test files. +| +*/ + +function something() +{ + // .. +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..cfb05b6 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,10 @@ +