diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6d2f9abd..c53601210 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,6 +77,9 @@ jobs: - name: Execute Trigger Tests run: set -e && vendor/bin/codecept run trigger + - name: Execute API Tests + run: set -e && vendor/bin/codecept run api + - name: Persist Test Artifacts uses: actions/upload-artifact@v1 if: always() diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 3539fe1d1..cb4ea817c 100755 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -35,6 +35,7 @@ class Kernel extends HttpKernel ], 'api' => [ + \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, 'throttle:60,1', 'bindings', ], diff --git a/composer.json b/composer.json index 249ff63f4..8d2b18833 100755 --- a/composer.json +++ b/composer.json @@ -9,11 +9,10 @@ "type": "project", "require": { "php": "^7.4|^8.0", - "algolia/algoliasearch-client-php": "^2.2", "astrotomic/laravel-translatable": "^11.0.0", "aws/aws-sdk-php": "^3.171", - "babenkoivan/elastic-scout-driver": "^1.1", "bagisto/legacy-api": "^1.0", + "bagisto/rest-api": "dev-master", "bagistobrasil/bagisto-product-social-share": "^0.1.2", "barryvdh/laravel-debugbar": "^3.1", "barryvdh/laravel-dompdf": "^0.8.5|^0.9.0", @@ -31,6 +30,7 @@ "khaled.alshamaa/ar-php": "^6.0.0", "konekt/concord": "^1.2", "laravel/framework": "^8.75", + "laravel/sanctum": "^2.12", "laravel/scout": "^8.0", "laravel/socialite": "^5.0", "laravel/tinker": "^2.0", @@ -45,6 +45,7 @@ "codeception/module-asserts": "^1.1", "codeception/module-filesystem": "^1.0", "codeception/module-laravel": "^2.0", + "codeception/module-rest": "^1.4", "codeception/module-webdriver": "^1.0", "filp/whoops": "^2.0", "mockery/mockery": "^1.3.1", @@ -108,10 +109,10 @@ }, "autoload-dev": { "psr-4": { - "Tests\\Acceptance\\": "tests/acceptance/", + "Tests\\API\\": "tests/api/", "Tests\\Functional\\": "tests/functional/", - "Tests\\Unit\\": "tests/unit/", - "Tests\\Trigger\\": "tests/trigger/" + "Tests\\Trigger\\": "tests/trigger/", + "Tests\\Unit\\": "tests/unit/" } }, "extra": { diff --git a/composer.lock b/composer.lock index 02dfd2994..8791df5e0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,82 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "07c290115c0da4ecdc099d46f3f780b7", + "content-hash": "426a3a0ec0e0d6c372ff22eb6a97f104", "packages": [ - { - "name": "algolia/algoliasearch-client-php", - "version": "2.8.0", - "source": { - "type": "git", - "url": "https://github.com/algolia/algoliasearch-client-php.git", - "reference": "d9781147ae433f5bdbfd902497d748d60e70d693" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/algolia/algoliasearch-client-php/zipball/d9781147ae433f5bdbfd902497d748d60e70d693", - "reference": "d9781147ae433f5bdbfd902497d748d60e70d693", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "ext-json": "*", - "ext-mbstring": "*", - "php": "^5.3 || ^7.0 || ^8.0", - "psr/http-message": "^1.0", - "psr/log": "^1.0", - "psr/simple-cache": "^1.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.0", - "fzaninotto/faker": "^1.8", - "julienbourdeau/phpunit": "4.8.37", - "symfony/yaml": "^2.0 || ^4.0" - }, - "suggest": { - "guzzlehttp/guzzle": "If you prefer to use Guzzle HTTP client instead of the Http Client implementation provided by the package" - }, - "bin": [ - "bin/algolia-doctor" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-2.0": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Algolia\\AlgoliaSearch\\": "src/" - }, - "files": [ - "src/Http/Psr7/functions.php", - "src/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Algolia Team", - "email": "contact@algolia.com" - } - ], - "description": "Algolia Search API Client for PHP", - "keywords": [ - "algolia", - "api", - "client", - "php", - "search" - ], - "support": { - "issues": "https://github.com/algolia/algoliasearch-client-php/issues", - "source": "https://github.com/algolia/algoliasearch-client-php/tree/2.8.0" - }, - "time": "2021-04-07T16:50:58+00:00" - }, { "name": "astrotomic/laravel-translatable", "version": "v11.9.1", @@ -217,16 +143,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.208.7", + "version": "3.209.2", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "41a800dd7cf5c4ac0ef9bf8db01e838ab6a3698c" + "reference": "77c14dd84704d2db6c5c4d6a8c1226337e4e6783" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/41a800dd7cf5c4ac0ef9bf8db01e838ab6a3698c", - "reference": "41a800dd7cf5c4ac0ef9bf8db01e838ab6a3698c", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/77c14dd84704d2db6c5c4d6a8c1226337e4e6783", + "reference": "77c14dd84704d2db6c5c4d6a8c1226337e4e6783", "shasum": "" }, "require": { @@ -302,219 +228,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.208.7" + "source": "https://github.com/aws/aws-sdk-php/tree/3.209.2" }, - "time": "2021-12-21T19:16:39+00:00" - }, - { - "name": "babenkoivan/elastic-adapter", - "version": "v1.17.0", - "source": { - "type": "git", - "url": "https://github.com/babenkoivan/elastic-adapter.git", - "reference": "6e6461c6988cf1bc655fcec2c2aa2beeb3163f55" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/babenkoivan/elastic-adapter/zipball/6e6461c6988cf1bc655fcec2c2aa2beeb3163f55", - "reference": "6e6461c6988cf1bc655fcec2c2aa2beeb3163f55", - "shasum": "" - }, - "require": { - "elasticsearch/elasticsearch": "^7.3", - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16", - "phpstan/phpstan": "^0.12.32", - "phpunit/phpunit": "^9.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "ElasticAdapter\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ivan Babenko", - "email": "babenko.i.a@gmail.com" - } - ], - "description": "Adapter for official PHP Elasticsearch client", - "keywords": [ - "adapter", - "client", - "elastic", - "elasticsearch", - "php" - ], - "support": { - "issues": "https://github.com/babenkoivan/elastic-adapter/issues", - "source": "https://github.com/babenkoivan/elastic-adapter/tree/v1.17.0" - }, - "funding": [ - { - "url": "https://www.buymeacoffee.com/ivanbabenko", - "type": "buymeacoffee" - }, - { - "url": "https://paypal.me/babenkoi", - "type": "paypal" - } - ], - "time": "2021-07-19T17:33:35+00:00" - }, - { - "name": "babenkoivan/elastic-client", - "version": "v1.2.0", - "source": { - "type": "git", - "url": "https://github.com/babenkoivan/elastic-client.git", - "reference": "a1e818b444c5e64afd33a578aa4a009c54aff065" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/babenkoivan/elastic-client/zipball/a1e818b444c5e64afd33a578aa4a009c54aff065", - "reference": "a1e818b444c5e64afd33a578aa4a009c54aff065", - "shasum": "" - }, - "require": { - "elasticsearch/elasticsearch": "^7.3", - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16", - "orchestra/testbench": "^6.12", - "phpstan/phpstan": "^0.12.32", - "phpunit/phpunit": "^9.5" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "ElasticClient\\ServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "ElasticClient\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ivan Babenko", - "email": "babenko.i.a@gmail.com" - } - ], - "description": "The official PHP Elasticsearch client integrated with Laravel", - "keywords": [ - "client", - "elastic", - "elasticsearch", - "laravel", - "php" - ], - "support": { - "issues": "https://github.com/babenkoivan/elastic-client/issues", - "source": "https://github.com/babenkoivan/elastic-client/tree/v1.2.0" - }, - "funding": [ - { - "url": "https://www.buymeacoffee.com/ivanbabenko", - "type": "buymeacoffee" - }, - { - "url": "https://paypal.me/babenkoi", - "type": "paypal" - } - ], - "time": "2021-02-16T07:28:08+00:00" - }, - { - "name": "babenkoivan/elastic-scout-driver", - "version": "v1.6.0", - "source": { - "type": "git", - "url": "https://github.com/babenkoivan/elastic-scout-driver.git", - "reference": "2f7751085f385c17154a29f3553071d3be1ca205" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/babenkoivan/elastic-scout-driver/zipball/2f7751085f385c17154a29f3553071d3be1ca205", - "reference": "2f7751085f385c17154a29f3553071d3be1ca205", - "shasum": "" - }, - "require": { - "babenkoivan/elastic-adapter": "^1.13", - "babenkoivan/elastic-client": "^1.2", - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "babenkoivan/elastic-migrations": "^1.4", - "friendsofphp/php-cs-fixer": "^3.0", - "laravel/legacy-factories": "^1.1", - "laravel/scout": "^9.0", - "orchestra/testbench": "^6.12", - "phpstan/phpstan": "^0.12.32", - "phpunit/phpunit": "^9.5" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "ElasticScoutDriver\\ServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "ElasticScoutDriver\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ivan Babenko", - "email": "babenko.i.a@gmail.com" - } - ], - "description": "Elasticsearch driver for Laravel Scout", - "keywords": [ - "driver", - "elastic", - "elasticsearch", - "laravel", - "php", - "scout" - ], - "support": { - "issues": "https://github.com/babenkoivan/elastic-scout-driver/issues", - "source": "https://github.com/babenkoivan/elastic-scout-driver/tree/v1.6.0" - }, - "funding": [ - { - "url": "https://www.buymeacoffee.com/ivanbabenko", - "type": "buymeacoffee" - }, - { - "url": "https://paypal.me/babenkoi", - "type": "paypal" - } - ], - "time": "2021-08-09T21:09:19+00:00" + "time": "2022-01-10T19:14:32+00:00" }, { "name": "bagisto/legacy-api", @@ -566,6 +282,50 @@ }, "time": "2021-11-19T07:54:39+00:00" }, + { + "name": "bagisto/rest-api", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/bagisto/rest-api.git", + "reference": "8f1ebb70840d2080cca6906e5c39ca92d906c81d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bagisto/rest-api/zipball/8f1ebb70840d2080cca6906e5c39ca92d906c81d", + "reference": "8f1ebb70840d2080cca6906e5c39ca92d906c81d", + "shasum": "" + }, + "default-branch": true, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Webkul\\RestApi\\Providers\\RestApiServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Webkul\\RestApi\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Devansh Bawari", + "email": "devansh.bawari419@webkul.com" + } + ], + "support": { + "issues": "https://github.com/bagisto/rest-api/issues", + "source": "https://github.com/bagisto/rest-api/tree/master" + }, + "time": "2022-01-11T13:17:27+00:00" + }, { "name": "bagistobrasil/bagisto-product-social-share", "version": "0.1.3", @@ -1068,16 +828,16 @@ }, { "name": "doctrine/dbal", - "version": "2.13.6", + "version": "2.13.7", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "67ef6d0327ccbab1202b39e0222977a47ed3ef2f" + "reference": "6e22f6012b42d7932674857989fcf184e9e9b1c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/67ef6d0327ccbab1202b39e0222977a47ed3ef2f", - "reference": "67ef6d0327ccbab1202b39e0222977a47ed3ef2f", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/6e22f6012b42d7932674857989fcf184e9e9b1c3", + "reference": "6e22f6012b42d7932674857989fcf184e9e9b1c3", "shasum": "" }, "require": { @@ -1090,13 +850,13 @@ "require-dev": { "doctrine/coding-standard": "9.0.0", "jetbrains/phpstorm-stubs": "2021.1", - "phpstan/phpstan": "1.2.0", - "phpunit/phpunit": "^7.5.20|^8.5|9.5.10", + "phpstan/phpstan": "1.3.0", + "phpunit/phpunit": "^7.5.20|^8.5|9.5.11", "psalm/plugin-phpunit": "0.16.1", - "squizlabs/php_codesniffer": "3.6.1", + "squizlabs/php_codesniffer": "3.6.2", "symfony/cache": "^4.4", "symfony/console": "^2.0.5|^3.0|^4.0|^5.0", - "vimeo/psalm": "4.13.0" + "vimeo/psalm": "4.16.1" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -1157,7 +917,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/2.13.6" + "source": "https://github.com/doctrine/dbal/tree/2.13.7" }, "funding": [ { @@ -1173,7 +933,7 @@ "type": "tidelift" } ], - "time": "2021-11-26T20:11:05+00:00" + "time": "2022-01-06T09:08:04+00:00" }, { "name": "doctrine/deprecations", @@ -1552,16 +1312,16 @@ }, { "name": "dragonmantank/cron-expression", - "version": "v3.1.0", + "version": "v3.2.3", "source": { "type": "git", "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "7a8c6e56ab3ffcc538d05e8155bb42269abf1a0c" + "reference": "47c53bbb260d3c398fba9bfa9683dcf67add2579" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/7a8c6e56ab3ffcc538d05e8155bb42269abf1a0c", - "reference": "7a8c6e56ab3ffcc538d05e8155bb42269abf1a0c", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/47c53bbb260d3c398fba9bfa9683dcf67add2579", + "reference": "47c53bbb260d3c398fba9bfa9683dcf67add2579", "shasum": "" }, "require": { @@ -1601,7 +1361,7 @@ ], "support": { "issues": "https://github.com/dragonmantank/cron-expression/issues", - "source": "https://github.com/dragonmantank/cron-expression/tree/v3.1.0" + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.2.3" }, "funding": [ { @@ -1609,7 +1369,7 @@ "type": "github" } ], - "time": "2020-11-24T19:55:57+00:00" + "time": "2022-01-06T05:35:07+00:00" }, { "name": "egulias/email-validator", @@ -1679,73 +1439,6 @@ ], "time": "2020-12-29T14:50:06+00:00" }, - { - "name": "elasticsearch/elasticsearch", - "version": "v7.16.0", - "source": { - "type": "git", - "url": "https://github.com/elastic/elasticsearch-php.git", - "reference": "f87f93f71f564d4bbdc5f008d296d1c37d828e10" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/elastic/elasticsearch-php/zipball/f87f93f71f564d4bbdc5f008d296d1c37d828e10", - "reference": "f87f93f71f564d4bbdc5f008d296d1c37d828e10", - "shasum": "" - }, - "require": { - "ext-json": ">=1.3.7", - "ezimuel/ringphp": "^1.1.2", - "php": "^7.3 || ^8.0", - "psr/log": "^1|^2" - }, - "require-dev": { - "ext-yaml": "*", - "ext-zip": "*", - "mockery/mockery": "^1.2", - "phpstan/phpstan": "^0.12", - "phpunit/phpunit": "^9.3", - "squizlabs/php_codesniffer": "^3.4", - "symfony/finder": "~4.0" - }, - "suggest": { - "ext-curl": "*", - "monolog/monolog": "Allows for client-level logging and tracing" - }, - "type": "library", - "autoload": { - "files": [ - "src/autoload.php" - ], - "psr-4": { - "Elasticsearch\\": "src/Elasticsearch/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0", - "LGPL-2.1-only" - ], - "authors": [ - { - "name": "Zachary Tong" - }, - { - "name": "Enrico Zimuel" - } - ], - "description": "PHP Client for Elasticsearch", - "keywords": [ - "client", - "elasticsearch", - "search" - ], - "support": { - "issues": "https://github.com/elastic/elasticsearch-php/issues", - "source": "https://github.com/elastic/elasticsearch-php/tree/v7.16.0" - }, - "time": "2021-12-09T20:04:01+00:00" - }, { "name": "enshrined/svg-sanitize", "version": "0.14.1", @@ -1792,116 +1485,6 @@ }, "time": "2021-08-09T23:46:54+00:00" }, - { - "name": "ezimuel/guzzlestreams", - "version": "3.0.1", - "source": { - "type": "git", - "url": "https://github.com/ezimuel/guzzlestreams.git", - "reference": "abe3791d231167f14eb80d413420d1eab91163a8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ezimuel/guzzlestreams/zipball/abe3791d231167f14eb80d413420d1eab91163a8", - "reference": "abe3791d231167f14eb80d413420d1eab91163a8", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Stream\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Fork of guzzle/streams (abandoned) to be used with elasticsearch-php", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "Guzzle", - "stream" - ], - "support": { - "source": "https://github.com/ezimuel/guzzlestreams/tree/3.0.1" - }, - "time": "2020-02-14T23:11:50+00:00" - }, - { - "name": "ezimuel/ringphp", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/ezimuel/ringphp.git", - "reference": "92b8161404ab1ad84059ebed41d9f757e897ce74" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ezimuel/ringphp/zipball/92b8161404ab1ad84059ebed41d9f757e897ce74", - "reference": "92b8161404ab1ad84059ebed41d9f757e897ce74", - "shasum": "" - }, - "require": { - "ezimuel/guzzlestreams": "^3.0.1", - "php": ">=5.4.0", - "react/promise": "~2.0" - }, - "replace": { - "guzzlehttp/ringphp": "self.version" - }, - "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "~9.0" - }, - "suggest": { - "ext-curl": "Guzzle will use specific adapters if cURL is present" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Ring\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Fork of guzzle/RingPHP (abandoned) to be used with elasticsearch-php", - "support": { - "source": "https://github.com/ezimuel/ringphp/tree/1.2.0" - }, - "time": "2021-11-16T11:51:30+00:00" - }, { "name": "ezyang/htmlpurifier", "version": "v4.14.0", @@ -3168,16 +2751,16 @@ }, { "name": "laravel/framework", - "version": "v8.77.1", + "version": "v8.78.1", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "994dbac5c6da856c77c81a411cff5b7d31519ca8" + "reference": "16359b5ebafba6579b397d7505b082a6d1bb2e31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/994dbac5c6da856c77c81a411cff5b7d31519ca8", - "reference": "994dbac5c6da856c77c81a411cff5b7d31519ca8", + "url": "https://api.github.com/repos/laravel/framework/zipball/16359b5ebafba6579b397d7505b082a6d1bb2e31", + "reference": "16359b5ebafba6579b397d7505b082a6d1bb2e31", "shasum": "" }, "require": { @@ -3336,7 +2919,71 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-12-21T20:22:29+00:00" + "time": "2022-01-05T14:52:50+00:00" + }, + { + "name": "laravel/sanctum", + "version": "v2.13.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/sanctum.git", + "reference": "b4c07d0014b78430a3c827064217f811f0708eaa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sanctum/zipball/b4c07d0014b78430a3c827064217f811f0708eaa", + "reference": "b4c07d0014b78430a3c827064217f811f0708eaa", + "shasum": "" + }, + "require": { + "ext-json": "*", + "illuminate/contracts": "^6.9|^7.0|^8.0", + "illuminate/database": "^6.9|^7.0|^8.0", + "illuminate/support": "^6.9|^7.0|^8.0", + "php": "^7.2|^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "orchestra/testbench": "^4.0|^5.0|^6.0", + "phpunit/phpunit": "^8.0|^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + }, + "laravel": { + "providers": [ + "Laravel\\Sanctum\\SanctumServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Sanctum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.", + "keywords": [ + "auth", + "laravel", + "sanctum" + ], + "support": { + "issues": "https://github.com/laravel/sanctum/issues", + "source": "https://github.com/laravel/sanctum" + }, + "time": "2021-12-14T17:49:47+00:00" }, { "name": "laravel/scout", @@ -4212,16 +3859,16 @@ }, { "name": "maatwebsite/excel", - "version": "3.1.34", + "version": "3.1.35", "source": { "type": "git", "url": "https://github.com/SpartnerNL/Laravel-Excel.git", - "reference": "d7446f0e808d83be128835c4b403c9e4a65b20f3" + "reference": "6f171c8b79e1c0fb254f3ec40f7a11ac79289eaa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/d7446f0e808d83be128835c4b403c9e4a65b20f3", - "reference": "d7446f0e808d83be128835c4b403c9e4a65b20f3", + "url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/6f171c8b79e1c0fb254f3ec40f7a11ac79289eaa", + "reference": "6f171c8b79e1c0fb254f3ec40f7a11ac79289eaa", "shasum": "" }, "require": { @@ -4274,7 +3921,7 @@ ], "support": { "issues": "https://github.com/SpartnerNL/Laravel-Excel/issues", - "source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.34" + "source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.35" }, "funding": [ { @@ -4286,7 +3933,7 @@ "type": "github" } ], - "time": "2021-12-02T16:17:16+00:00" + "time": "2022-01-04T15:05:43+00:00" }, { "name": "maennchen/zipstream-php", @@ -5597,16 +5244,16 @@ }, { "name": "phpoffice/phpspreadsheet", - "version": "1.20.0", + "version": "1.21.0", "source": { "type": "git", "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", - "reference": "44436f270bb134b4a94670f3d020a85dfa0a3c02" + "reference": "1a359d2ccbb89c05f5dffb32711a95f4afc67964" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/44436f270bb134b4a94670f3d020a85dfa0a3c02", - "reference": "44436f270bb134b4a94670f3d020a85dfa0a3c02", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/1a359d2ccbb89c05f5dffb32711a95f4afc67964", + "reference": "1a359d2ccbb89c05f5dffb32711a95f4afc67964", "shasum": "" }, "require": { @@ -5695,9 +5342,9 @@ ], "support": { "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", - "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.20.0" + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.21.0" }, - "time": "2021-11-23T15:23:42+00:00" + "time": "2022-01-06T11:10:08+00:00" }, { "name": "phpoption/phpoption", @@ -6609,56 +6256,6 @@ ], "time": "2021-09-25T23:10:38+00:00" }, - { - "name": "react/promise", - "version": "v2.8.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/promise.git", - "reference": "f3cff96a19736714524ca0dd1d4130de73dbbbc4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/f3cff96a19736714524ca0dd1d4130de73dbbbc4", - "reference": "f3cff96a19736714524ca0dd1d4130de73dbbbc4", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^7.0 || ^6.5 || ^5.7 || ^4.8.36" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\Promise\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com" - } - ], - "description": "A lightweight implementation of CommonJS Promises/A for PHP", - "keywords": [ - "promise", - "promises" - ], - "support": { - "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v2.8.0" - }, - "time": "2020-05-12T15:16:56+00:00" - }, { "name": "sabberworm/php-css-parser", "version": "8.4.0", @@ -7656,21 +7253,24 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + "reference": "30885182c981ab175d4d034db0f6f469898070ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-ctype": "*" + }, "suggest": { "ext-ctype": "For best performance" }, @@ -7715,7 +7315,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0" }, "funding": [ { @@ -7731,25 +7331,28 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-10-20T20:35:02+00:00" }, { "name": "symfony/polyfill-iconv", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "63b5bb7db83e5673936d6e3b8b3e022ff6474933" + "reference": "f1aed619e28cb077fc83fac8c4c0383578356e40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/63b5bb7db83e5673936d6e3b8b3e022ff6474933", - "reference": "63b5bb7db83e5673936d6e3b8b3e022ff6474933", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/f1aed619e28cb077fc83fac8c4c0383578356e40", + "reference": "f1aed619e28cb077fc83fac8c4c0383578356e40", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-iconv": "*" + }, "suggest": { "ext-iconv": "For best performance" }, @@ -7795,7 +7398,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.24.0" }, "funding": [ { @@ -7811,20 +7414,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:27:20+00:00" + "time": "2022-01-04T09:04:05+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.23.1", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "16880ba9c5ebe3642d1995ab866db29270b36535" + "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/16880ba9c5ebe3642d1995ab866db29270b36535", - "reference": "16880ba9c5ebe3642d1995ab866db29270b36535", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", + "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", "shasum": "" }, "require": { @@ -7876,7 +7479,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.1" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.24.0" }, "funding": [ { @@ -7892,20 +7495,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T12:26:48+00:00" + "time": "2021-11-23T21:10:46+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65" + "reference": "749045c69efb97c70d25d7463abba812e91f3a44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/65bd267525e82759e7d8c4e8ceea44f398838e65", - "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/749045c69efb97c70d25d7463abba812e91f3a44", + "reference": "749045c69efb97c70d25d7463abba812e91f3a44", "shasum": "" }, "require": { @@ -7963,7 +7566,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.24.0" }, "funding": [ { @@ -7979,11 +7582,11 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:27:20+00:00" + "time": "2021-09-14T14:02:44+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -8047,7 +7650,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.24.0" }, "funding": [ { @@ -8067,21 +7670,24 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.23.1", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6" + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6", - "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-mbstring": "*" + }, "suggest": { "ext-mbstring": "For best performance" }, @@ -8127,7 +7733,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.24.0" }, "funding": [ { @@ -8143,7 +7749,7 @@ "type": "tidelift" } ], - "time": "2021-05-27T12:26:48+00:00" + "time": "2021-11-30T18:21:41+00:00" }, { "name": "symfony/polyfill-php56", @@ -8215,7 +7821,7 @@ }, { "name": "symfony/polyfill-php72", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", @@ -8271,7 +7877,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.24.0" }, "funding": [ { @@ -8291,16 +7897,16 @@ }, { "name": "symfony/polyfill-php73", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010" + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010", - "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", "shasum": "" }, "require": { @@ -8350,7 +7956,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.24.0" }, "funding": [ { @@ -8366,20 +7972,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-06-05T21:20:04+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.23.1", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be" + "reference": "57b712b08eddb97c762a8caa32c84e037892d2e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be", - "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/57b712b08eddb97c762a8caa32c84e037892d2e9", + "reference": "57b712b08eddb97c762a8caa32c84e037892d2e9", "shasum": "" }, "require": { @@ -8433,7 +8039,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.24.0" }, "funding": [ { @@ -8449,20 +8055,20 @@ "type": "tidelift" } ], - "time": "2021-07-28T13:41:28+00:00" + "time": "2021-09-13T13:58:33+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "e66119f3de95efc359483f810c4c3e6436279436" + "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/e66119f3de95efc359483f810c4c3e6436279436", - "reference": "e66119f3de95efc359483f810c4c3e6436279436", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", + "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", "shasum": "" }, "require": { @@ -8512,7 +8118,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.24.0" }, "funding": [ { @@ -8528,7 +8134,7 @@ "type": "tidelift" } ], - "time": "2021-05-21T13:25:03+00:00" + "time": "2021-09-13T13:58:11+00:00" }, { "name": "symfony/process", @@ -9447,16 +9053,16 @@ }, { "name": "codeception/codeception", - "version": "4.1.27", + "version": "4.1.28", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "2d9a11e6f487e3bcc17e22b7552fb6a10cec5c7c" + "reference": "e9bc22a3819f9d356068c0e372193ebcc9b06014" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/2d9a11e6f487e3bcc17e22b7552fb6a10cec5c7c", - "reference": "2d9a11e6f487e3bcc17e22b7552fb6a10cec5c7c", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/e9bc22a3819f9d356068c0e372193ebcc9b06014", + "reference": "e9bc22a3819f9d356068c0e372193ebcc9b06014", "shasum": "" }, "require": { @@ -9533,7 +9139,7 @@ ], "support": { "issues": "https://github.com/Codeception/Codeception/issues", - "source": "https://github.com/Codeception/Codeception/tree/4.1.27" + "source": "https://github.com/Codeception/Codeception/tree/4.1.28" }, "funding": [ { @@ -9541,7 +9147,7 @@ "type": "open_collective" } ], - "time": "2021-12-22T06:40:46+00:00" + "time": "2022-01-05T16:41:25+00:00" }, { "name": "codeception/lib-asserts", @@ -9826,6 +9432,60 @@ }, "time": "2021-12-18T14:12:51+00:00" }, + { + "name": "codeception/module-rest", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-rest.git", + "reference": "9cd7a87fd9343494e7782f7bdb51687c25046917" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-rest/zipball/9cd7a87fd9343494e7782f7bdb51687c25046917", + "reference": "9cd7a87fd9343494e7782f7bdb51687c25046917", + "shasum": "" + }, + "require": { + "codeception/codeception": "^4.0", + "justinrainbow/json-schema": "~5.2.9", + "php": ">=5.6.6 <9.0", + "softcreatr/jsonpath": "^0.5 || ^0.7" + }, + "require-dev": { + "codeception/lib-innerbrowser": "^1.0", + "codeception/util-universalframework": "^1.0" + }, + "suggest": { + "aws/aws-sdk-php": "For using AWS Auth" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gintautas Miselis" + } + ], + "description": "REST module for Codeception", + "homepage": "http://codeception.com/", + "keywords": [ + "codeception", + "rest" + ], + "support": { + "issues": "https://github.com/Codeception/module-rest/issues", + "source": "https://github.com/Codeception/module-rest/tree/1.4.2" + }, + "time": "2021-11-18T18:58:15+00:00" + }, { "name": "codeception/module-webdriver", "version": "1.4.0", @@ -9933,16 +9593,16 @@ }, { "name": "codeception/stub", - "version": "4.0.0", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/Codeception/Stub.git", - "reference": "4c9cf3e19bd5f064e08e7f3ba6be651c218dc6ae" + "reference": "ce0a9e418c775ca8b737d50c2b4ac1132f3990d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Stub/zipball/4c9cf3e19bd5f064e08e7f3ba6be651c218dc6ae", - "reference": "4c9cf3e19bd5f064e08e7f3ba6be651c218dc6ae", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/ce0a9e418c775ca8b737d50c2b4ac1132f3990d8", + "reference": "ce0a9e418c775ca8b737d50c2b4ac1132f3990d8", "shasum": "" }, "require": { @@ -9965,9 +9625,9 @@ "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", "support": { "issues": "https://github.com/Codeception/Stub/issues", - "source": "https://github.com/Codeception/Stub/tree/4.0.0" + "source": "https://github.com/Codeception/Stub/tree/4.0.1" }, - "time": "2021-12-07T14:39:17+00:00" + "time": "2022-01-08T09:35:36+00:00" }, { "name": "doctrine/instantiator", @@ -10040,16 +9700,16 @@ }, { "name": "filp/whoops", - "version": "2.14.4", + "version": "2.14.5", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "f056f1fe935d9ed86e698905a957334029899895" + "reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/f056f1fe935d9ed86e698905a957334029899895", - "reference": "f056f1fe935d9ed86e698905a957334029899895", + "url": "https://api.github.com/repos/filp/whoops/zipball/a63e5e8f26ebbebf8ed3c5c691637325512eb0dc", + "reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc", "shasum": "" }, "require": { @@ -10099,7 +9759,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.14.4" + "source": "https://github.com/filp/whoops/tree/2.14.5" }, "funding": [ { @@ -10107,7 +9767,7 @@ "type": "github" } ], - "time": "2021-10-03T12:00:00+00:00" + "time": "2022-01-07T12:00:00+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -10160,6 +9820,76 @@ }, "time": "2020-07-09T08:09:16+00:00" }, + { + "name": "justinrainbow/json-schema", + "version": "5.2.11", + "source": { + "type": "git", + "url": "https://github.com/justinrainbow/json-schema.git", + "reference": "2ab6744b7296ded80f8cc4f9509abbff393399aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2ab6744b7296ded80f8cc4f9509abbff393399aa", + "reference": "2ab6744b7296ded80f8cc4f9509abbff393399aa", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "json-schema/json-schema-test-suite": "1.2.0", + "phpunit/phpunit": "^4.8.35" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "support": { + "issues": "https://github.com/justinrainbow/json-schema/issues", + "source": "https://github.com/justinrainbow/json-schema/tree/5.2.11" + }, + "time": "2021-07-22T09:24:00+00:00" + }, { "name": "mockery/mockery", "version": "1.4.4", @@ -10292,16 +10022,16 @@ }, { "name": "nunomaduro/collision", - "version": "v5.10.0", + "version": "v5.11.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "3004cfa49c022183395eabc6d0e5207dfe498d00" + "reference": "8b610eef8582ccdc05d8f2ab23305e2d37049461" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/3004cfa49c022183395eabc6d0e5207dfe498d00", - "reference": "3004cfa49c022183395eabc6d0e5207dfe498d00", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/8b610eef8582ccdc05d8f2ab23305e2d37049461", + "reference": "8b610eef8582ccdc05d8f2ab23305e2d37049461", "shasum": "" }, "require": { @@ -10363,7 +10093,7 @@ }, "funding": [ { - "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", + "url": "https://www.paypal.com/paypalme/enunomaduro", "type": "custom" }, { @@ -10375,7 +10105,7 @@ "type": "patreon" } ], - "time": "2021-09-20T15:06:32+00:00" + "time": "2022-01-10T16:22:52+00:00" }, { "name": "phar-io/manifest", @@ -10665,16 +10395,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.5.1", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae" + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae", - "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706", + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706", "shasum": "" }, "require": { @@ -10709,9 +10439,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0" }, - "time": "2021-10-02T14:08:47+00:00" + "time": "2022-01-04T19:58:01+00:00" }, { "name": "phpspec/prophecy", @@ -12165,6 +11895,71 @@ ], "time": "2020-09-28T06:39:44+00:00" }, + { + "name": "softcreatr/jsonpath", + "version": "0.7.5", + "source": { + "type": "git", + "url": "https://github.com/SoftCreatR/JSONPath.git", + "reference": "008569bf80aa3584834f7890781576bc7b65afa7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SoftCreatR/JSONPath/zipball/008569bf80aa3584834f7890781576bc7b65afa7", + "reference": "008569bf80aa3584834f7890781576bc7b65afa7", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.1" + }, + "replace": { + "flow/jsonpath": "*" + }, + "require-dev": { + "phpunit/phpunit": ">=7.0", + "roave/security-advisories": "dev-master", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Flow\\JSONPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Stephen Frank", + "email": "stephen@flowsa.com", + "homepage": "https://prismaticbytes.com", + "role": "Developer" + }, + { + "name": "Sascha Greuel", + "email": "hello@1-2.dev", + "homepage": "http://1-2.dev", + "role": "Developer" + } + ], + "description": "JSONPath implementation for parsing, searching and flattening arrays", + "support": { + "email": "hello@1-2.dev", + "forum": "https://github.com/SoftCreatR/JSONPath/discussions", + "issues": "https://github.com/SoftCreatR/JSONPath/issues", + "source": "https://github.com/SoftCreatR/JSONPath" + }, + "funding": [ + { + "url": "https://github.com/softcreatr", + "type": "github" + } + ], + "time": "2021-06-02T22:15:26+00:00" + }, { "name": "symfony/browser-kit", "version": "v5.4.2", @@ -12440,7 +12235,9 @@ ], "aliases": [], "minimum-stability": "dev", - "stability-flags": [], + "stability-flags": { + "bagisto/rest-api": 20 + }, "prefer-stable": true, "prefer-lowest": false, "platform": { diff --git a/config/auth.php b/config/auth.php index 222c860df..e302a2347 100755 --- a/config/auth.php +++ b/config/auth.php @@ -2,60 +2,56 @@ return [ 'defaults' => [ - 'guard' => 'web', - 'passwords' => 'admins', + 'guard' => 'customer', + 'passwords' => 'customers', ], 'guards' => [ - 'web' => [ - 'driver' => 'session', + 'customer' => [ + 'driver' => 'session', + 'provider' => 'customers', + ], + + 'admin' => [ + 'driver' => 'session', 'provider' => 'admins', ], 'api' => [ - 'driver' => 'jwt', + 'driver' => 'jwt', 'provider' => 'customers', ], - 'customer' => [ - 'driver' => 'session', - 'provider' => 'customers' - ], - - 'admin' => [ - 'driver' => 'session', - 'provider' => 'admins' - ], - 'admin-api' => [ - 'driver' => 'jwt', + 'driver' => 'jwt', 'provider' => 'admins', - ] + ], ], 'providers' => [ 'customers' => [ 'driver' => 'eloquent', - 'model' => Webkul\Customer\Models\Customer::class, + 'model' => Webkul\Customer\Models\Customer::class, ], 'admins' => [ 'driver' => 'eloquent', - 'model' => Webkul\User\Models\Admin::class, - ] + 'model' => Webkul\User\Models\Admin::class, + ], ], 'passwords' => [ - 'admins' => [ - 'provider' => 'admins', - 'table' => 'admin_password_resets', - 'expire' => 60, - 'throttle' => 60, - ], 'customers' => [ 'provider' => 'customers', - 'table' => 'customer_password_resets', - 'expire' => 60, + 'table' => 'customer_password_resets', + 'expire' => 60, + 'throttle' => 60, + ], + + 'admins' => [ + 'provider' => 'admins', + 'table' => 'admin_password_resets', + 'expire' => 60, 'throttle' => 60, ], ], diff --git a/config/concord.php b/config/concord.php index a8905ae21..937a22ecc 100755 --- a/config/concord.php +++ b/config/concord.php @@ -5,6 +5,7 @@ return [ 'convention' => Webkul\Core\CoreConvention::class, 'modules' => [ + /** * Example: * VendorA\ModuleX\Providers\ModuleServiceProvider::class, @@ -37,5 +38,6 @@ return [ \Webkul\Ui\Providers\ModuleServiceProvider::class, \Webkul\User\Providers\ModuleServiceProvider::class, \Webkul\Velocity\Providers\ModuleServiceProvider::class, - ] -]; \ No newline at end of file + + ], +]; diff --git a/config/sanctum.php b/config/sanctum.php new file mode 100644 index 000000000..310412eda --- /dev/null +++ b/config/sanctum.php @@ -0,0 +1,65 @@ + explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( + '%s%s', + 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1', + env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : '' + ))), + + /* + |-------------------------------------------------------------------------- + | Sanctum Guards + |-------------------------------------------------------------------------- + | + | This array contains the authentication guards that will be checked when + | Sanctum is trying to authenticate a request. If none of these guards + | are able to authenticate the request, Sanctum will use the bearer + | token that's present on an incoming request for authentication. + | + */ + + 'guard' => ['customer'], + + /* + |-------------------------------------------------------------------------- + | Expiration Minutes + |-------------------------------------------------------------------------- + | + | This value controls the number of minutes until an issued token will be + | considered expired. If this value is null, personal access tokens do + | not expire. This won't tweak the lifetime of first-party sessions. + | + */ + + 'expiration' => null, + + /* + |-------------------------------------------------------------------------- + | Sanctum Middleware + |-------------------------------------------------------------------------- + | + | When authenticating your first-party SPA with Sanctum you may need to + | customize some of the middleware Sanctum uses while processing the + | request. You may change the middleware listed below as required. + | + */ + + 'middleware' => [ + 'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class, + 'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class, + ], + +]; diff --git a/config/scout.php b/config/scout.php new file mode 100644 index 000000000..3613666ca --- /dev/null +++ b/config/scout.php @@ -0,0 +1,119 @@ + env('SCOUT_DRIVER', null), + + /* + |-------------------------------------------------------------------------- + | Index Prefix + |-------------------------------------------------------------------------- + | + | Here you may specify a prefix that will be applied to all search index + | names used by Scout. This prefix may be useful if you have multiple + | "tenants" or applications sharing the same search infrastructure. + | + */ + + 'prefix' => env('SCOUT_PREFIX', ''), + + /* + |-------------------------------------------------------------------------- + | Queue Data Syncing + |-------------------------------------------------------------------------- + | + | This option allows you to control if the operations that sync your data + | with your search engines are queued. When this is set to "true" then + | all automatic data syncing will get queued for better performance. + | + */ + + 'queue' => env('SCOUT_QUEUE', false), + + /* + |-------------------------------------------------------------------------- + | Database Transactions + |-------------------------------------------------------------------------- + | + | This configuration option determines if your data will only be synced + | with your search indexes after every open database transaction has + | been committed, thus preventing any discarded data from syncing. + | + */ + + 'after_commit' => false, + + /* + |-------------------------------------------------------------------------- + | Chunk Sizes + |-------------------------------------------------------------------------- + | + | These options allow you to control the maximum chunk size when you are + | mass importing data into the search engine. This allows you to fine + | tune each of these chunk sizes based on the power of the servers. + | + */ + + 'chunk' => [ + 'searchable' => 500, + 'unsearchable' => 500, + ], + + /* + |-------------------------------------------------------------------------- + | Soft Deletes + |-------------------------------------------------------------------------- + | + | This option allows to control whether to keep soft deleted records in + | the search indexes. Maintaining soft deleted records can be useful + | if your application still needs to search for the records later. + | + */ + + 'soft_delete' => false, + + /* + |-------------------------------------------------------------------------- + | Identify User + |-------------------------------------------------------------------------- + | + | This option allows you to control whether to notify the search engine + | of the user performing the search. This is sometimes useful if the + | engine supports any analytics based on this application's users. + | + | Supported engines: "algolia" + | + */ + + 'identify' => env('SCOUT_IDENTIFY', false), + + /* + |-------------------------------------------------------------------------- + | Algolia Configuration + |-------------------------------------------------------------------------- + | + | Here you may configure your Algolia settings. Algolia is a cloud hosted + | search engine which works great with Scout out of the box. Just plug + | in your application ID and admin API key to get started searching. + | + */ + + 'algolia' => [ + 'id' => env('ALGOLIA_APP_ID', ''), + 'secret' => env('ALGOLIA_SECRET', ''), + ], + +]; diff --git a/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php b/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php new file mode 100644 index 000000000..3ce00023a --- /dev/null +++ b/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php @@ -0,0 +1,36 @@ +bigIncrements('id'); + $table->morphs('tokenable'); + $table->string('name'); + $table->string('token', 64)->unique(); + $table->text('abilities')->nullable(); + $table->timestamp('last_used_at')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('personal_access_tokens'); + } +} diff --git a/packages/Webkul/CartRule/src/Helpers/CartRule.php b/packages/Webkul/CartRule/src/Helpers/CartRule.php index 64b0654a5..3d1825522 100644 --- a/packages/Webkul/CartRule/src/Helpers/CartRule.php +++ b/packages/Webkul/CartRule/src/Helpers/CartRule.php @@ -150,8 +150,8 @@ class CartRule $customerGroupId = null; - if (Cart::getCurrentCustomer()->check()) { - $customerGroupId = Cart::getCurrentCustomer()->user()->customer_group_id; + if (auth()->guard()->check()) { + $customerGroupId = auth()->guard()->user()->customer_group_id; } else { $customerGuestGroup = $this->customerGroupRepository->getCustomerGuestGroup(); diff --git a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProductPrice.php b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProductPrice.php index 8420805e9..70a391056 100644 --- a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProductPrice.php +++ b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProductPrice.php @@ -50,18 +50,6 @@ class CatalogRuleProductPrice $this->customerGroupRepository = $customerGroupRepository; } - /** - * Return current logged in customer - * - * @return \Webkul\Customer\Contracts\Customer|bool - */ - public function getCurrentCustomer() - { - $guard = request()->has('token') ? 'api' : 'customer'; - - return auth()->guard($guard); - } - /** * Collect discount on cart * @@ -198,8 +186,8 @@ class CatalogRuleProductPrice */ public function getRulePrice($product) { - if ($this->getCurrentCustomer()->check()) { - $customerGroupId = $this->getCurrentCustomer()->user()->customer_group_id; + if (auth()->guard()->check()) { + $customerGroupId = auth()->guard()->user()->customer_group_id; } else { $customerGroup = $this->customerGroupRepository->getCustomerGuestGroup(); diff --git a/packages/Webkul/Checkout/src/Cart.php b/packages/Webkul/Checkout/src/Cart.php index d5cb8f504..5ea319e70 100755 --- a/packages/Webkul/Checkout/src/Cart.php +++ b/packages/Webkul/Checkout/src/Cart.php @@ -110,18 +110,6 @@ class Cart $this->customerAddressRepository = $customerAddressRepository; } - /** - * Return current logged in customer. - * - * @return \Webkul\Customer\Contracts\Customer|bool - */ - public function getCurrentCustomer() - { - $guard = request()->has('token') ? 'api' : 'customer'; - - return auth()->guard($guard); - } - /** * Returns cart. * @@ -131,9 +119,9 @@ class Cart { $cart = null; - if ($this->getCurrentCustomer()->check()) { + if (auth()->guard()->check()) { $cart = $this->cartRepository->findOneWhere([ - 'customer_id' => $this->getCurrentCustomer()->user()->id, + 'customer_id' => auth()->guard()->user()->id, 'is_active' => 1, ]); } else if (session()->has('cart')) { @@ -261,12 +249,12 @@ class Cart /** * Fill in the customer data, as far as possible. */ - if ($this->getCurrentCustomer()->check()) { - $cartData['customer_id'] = $this->getCurrentCustomer()->user()->id; + if (auth()->guard()->check()) { + $cartData['customer_id'] = auth()->guard()->user()->id; $cartData['is_guest'] = 0; - $cartData['customer_first_name'] = $this->getCurrentCustomer()->user()->first_name; - $cartData['customer_last_name'] = $this->getCurrentCustomer()->user()->last_name; - $cartData['customer_email'] = $this->getCurrentCustomer()->user()->email; + $cartData['customer_first_name'] = auth()->guard()->user()->first_name; + $cartData['customer_last_name'] = auth()->guard()->user()->last_name; + $cartData['customer_email'] = auth()->guard()->user()->email; } else { $cartData['is_guest'] = 1; } @@ -573,8 +561,8 @@ class Cart $address = $cart->billing_address; } - if ($address === null && auth()->guard('customer')->check()) { - $address = auth()->guard('customer')->user()->addresses() + if ($address === null && auth()->guard()->check()) { + $address = auth()->guard()->user()->addresses() ->where('default_address', 1)->first(); } @@ -670,7 +658,7 @@ class Cart 'customer_email' => $data['customer_email'], 'customer_first_name' => $data['customer_first_name'], 'customer_last_name' => $data['customer_last_name'], - 'customer' => $this->getCurrentCustomer()->check() ? $this->getCurrentCustomer()->user() : null, + 'customer' => auth()->guard()->check() ? auth()->guard()->user() : null, 'total_item_count' => $data['items_count'], 'total_qty_ordered' => $data['items_qty'], 'base_currency_code' => $data['base_currency_code'], @@ -809,8 +797,8 @@ class Cart private function assignCustomerFields(\Webkul\Checkout\Contracts\Cart $cart): void { if ( - $this->getCurrentCustomer()->check() - && ($user = $this->getCurrentCustomer()->user()) + auth()->guard()->check() + && ($user = auth()->guard()->user()) && $this->profileIsComplete($user) ) { $cart->customer_email = $user->email; @@ -880,7 +868,7 @@ class Cart { $attributes = []; - $user = $this->getCurrentCustomer()->user(); + $user = auth()->guard()->user(); if ($user) { $attributes['first_name'] = $user->first_name; diff --git a/packages/Webkul/Checkout/src/Database/Factories/CartFactory.php b/packages/Webkul/Checkout/src/Database/Factories/CartFactory.php index 3de690a15..f00b46d69 100644 --- a/packages/Webkul/Checkout/src/Database/Factories/CartFactory.php +++ b/packages/Webkul/Checkout/src/Database/Factories/CartFactory.php @@ -2,11 +2,9 @@ namespace Webkul\Checkout\Database\Factories; -use Illuminate\Support\Facades\DB; -use Webkul\Customer\Models\Customer; -use Webkul\Checkout\Models\Cart; -use Webkul\Checkout\Models\CartAddress; use Illuminate\Database\Eloquent\Factories\Factory; +use Webkul\Checkout\Models\Cart; +use Webkul\Customer\Models\Customer; class CartFactory extends Factory { @@ -24,34 +22,42 @@ class CartFactory extends Factory */ public function definition(): array { - $now = date("Y-m-d H:i:s"); - - $lastOrder = DB::table('orders') - ->orderBy('id', 'desc') - ->select('id') - ->first(); - - $customer = Customer::factory() - ->create(); + $now = date('Y-m-d H:i:s'); return [ - 'is_guest' => 0, - 'is_active' => 1, - 'customer_id' => $customer->id, - 'customer_email' => $customer->email, - 'customer_first_name' => $customer->first_name, - 'customer_last_name' => $customer->last_name, - 'is_gift' => 0, - 'base_currency_code' => 'EUR', + 'is_guest' => 0, + 'is_active' => 1, + 'is_gift' => 0, + 'base_currency_code' => 'EUR', 'channel_currency_code' => 'EUR', - 'grand_total' => 0.0000, - 'base_grand_total' => 0.0000, - 'sub_total' => 0.0000, - 'base_sub_total' => 0.0000, - 'channel_id' => 1, - 'created_at' => $now, - 'updated_at' => $now, + 'grand_total' => 0.0000, + 'base_grand_total' => 0.0000, + 'sub_total' => 0.0000, + 'base_sub_total' => 0.0000, + 'channel_id' => 1, + 'created_at' => $now, + 'updated_at' => $now, ]; } -} + /** + * Adjust customer. + * + * @return array + */ + public function adjustCustomer() + { + return $this->state(function (array $attributes) { + $customer = isset($attributes['customer_id']) + ? Customer::query()->where('id', $attributes['customer_id'])->first() + : Customer::factory()->create(); + + return [ + 'customer_id' => $customer->id, + 'customer_email' => $customer->email, + 'customer_first_name' => $customer->first_name, + 'customer_last_name' => $customer->last_name, + ]; + }); + } +} diff --git a/packages/Webkul/Checkout/src/Database/Factories/CartItemFactory.php b/packages/Webkul/Checkout/src/Database/Factories/CartItemFactory.php index dbb884c49..e293f5198 100644 --- a/packages/Webkul/Checkout/src/Database/Factories/CartItemFactory.php +++ b/packages/Webkul/Checkout/src/Database/Factories/CartItemFactory.php @@ -2,11 +2,10 @@ namespace Webkul\Checkout\Database\Factories; -use Faker\Generator as Faker; +use Illuminate\Database\Eloquent\Factories\Factory; use Webkul\Checkout\Models\Cart; use Webkul\Checkout\Models\CartItem; use Webkul\Product\Models\Product; -use Illuminate\Database\Eloquent\Factories\Factory; class CartItemFactory extends Factory { @@ -24,32 +23,40 @@ class CartItemFactory extends Factory */ public function definition(): array { - $now = date("Y-m-d H:i:s"); - - if (isset($attributes['product_id'])) { - $product = Product::query() - ->where('id', $attributes['product_id']) - ->first(); - } else { - $product = Product::factory() - ->create(); - } - - $fallbackPrice = $this->faker->randomFloat(4, 0, 1000); + $now = date('Y-m-d H:i:s'); return [ - 'quantity' => 1, - 'sku' => $product->sku, - 'type' => $product->type, - 'name' => $product->name, - 'price' => $product->price ?? $fallbackPrice, - 'base_price' => $product->price ?? $fallbackPrice, - 'total' => $product->price ?? $fallbackPrice, - 'base_total' => $product->price ?? $fallbackPrice, - 'product_id' => $product->id, - 'cart_id' => Cart::factory(), + 'quantity' => 1, + 'cart_id' => Cart::factory(), 'created_at' => $now, 'updated_at' => $now, ]; } + + /** + * Adjust product. + * + * @return array + */ + public function adjustProduct() + { + return $this->state(function (array $attributes) { + $product = isset($attributes['product_id']) + ? Product::query()->where('id', $attributes['product_id'])->first() + : Product::factory()->create(); + + $fallbackPrice = $this->faker->randomFloat(4, 0, 1000); + + return [ + 'sku' => $product->sku, + 'type' => $product->type, + 'name' => $product->name, + 'price' => $product->price ?? $fallbackPrice, + 'base_price' => $product->price ?? $fallbackPrice, + 'total' => $product->price ?? $fallbackPrice, + 'base_total' => $product->price ?? $fallbackPrice, + 'product_id' => $product->id, + ]; + }); + } } diff --git a/packages/Webkul/Checkout/src/Http/Requests/CustomerAddressForm.php b/packages/Webkul/Checkout/src/Http/Requests/CustomerAddressForm.php index 6c3d68944..49c8f6076 100755 --- a/packages/Webkul/Checkout/src/Http/Requests/CustomerAddressForm.php +++ b/packages/Webkul/Checkout/src/Http/Requests/CustomerAddressForm.php @@ -8,6 +8,8 @@ class CustomerAddressForm extends FormRequest { /** * Rules. + * + * @var array */ protected $rules = []; @@ -100,9 +102,7 @@ class CustomerAddressForm extends FormRequest */ private function getCustomerAddressIds(): string { - $guard = request()->has('token') ? 'api' : 'customer'; - - if ($customer = auth($guard)->user()) { + if ($customer = auth()->guard()->user()) { return $customer->addresses->pluck('id')->join(','); } diff --git a/packages/Webkul/Checkout/src/Providers/CheckoutServiceProvider.php b/packages/Webkul/Checkout/src/Providers/CheckoutServiceProvider.php index 011765ec6..e9233568c 100755 --- a/packages/Webkul/Checkout/src/Providers/CheckoutServiceProvider.php +++ b/packages/Webkul/Checkout/src/Providers/CheckoutServiceProvider.php @@ -2,21 +2,26 @@ namespace Webkul\Checkout\Providers; -use Illuminate\Support\ServiceProvider; use Illuminate\Foundation\AliasLoader; +use Illuminate\Support\ServiceProvider; use Webkul\Checkout\Facades\Cart; class CheckoutServiceProvider extends ServiceProvider { + /** + * Bootstrap services. + * + * @return void + */ public function boot(): void { include __DIR__ . '/../Http/helpers.php'; $this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations'); - $this->app->register(ModuleServiceProvider::class); - $this->app->register(EventServiceProvider::class); + + $this->app->register(ModuleServiceProvider::class); } /** @@ -30,22 +35,20 @@ class CheckoutServiceProvider extends ServiceProvider } /** - * Register Bouncer as a singleton. + * Register cart as a singleton. * * @return void */ protected function registerFacades(): void { - //to make the cart facade and bind the - //alias to the class needed to be called. $loader = AliasLoader::getInstance(); $loader->alias('cart', Cart::class); $this->app->singleton('cart', function () { - return new cart(); + return new Cart(); }); - $this->app->bind('cart', 'Webkul\Checkout\Cart'); + $this->app->bind('cart', \Webkul\Checkout\Cart::class); } -} \ No newline at end of file +} diff --git a/packages/Webkul/Checkout/src/Traits/CartTools.php b/packages/Webkul/Checkout/src/Traits/CartTools.php index fa65a30ab..c2cdbe630 100644 --- a/packages/Webkul/Checkout/src/Traits/CartTools.php +++ b/packages/Webkul/Checkout/src/Traits/CartTools.php @@ -19,7 +19,7 @@ trait CartTools */ public function putCart($cart) { - if (! $this->getCurrentCustomer()->check()) { + if (! auth()->guard()->check()) { session()->put('cart', $cart); } } @@ -33,7 +33,7 @@ trait CartTools { if (session()->has('cart')) { $cart = $this->cartRepository->findOneWhere([ - 'customer_id' => $this->getCurrentCustomer()->user()->id, + 'customer_id' => auth()->guard()->user()->id, 'is_active' => 1, ]); @@ -44,11 +44,11 @@ trait CartTools */ if (! $cart) { $this->cartRepository->update([ - 'customer_id' => $this->getCurrentCustomer()->user()->id, + 'customer_id' => auth()->guard()->user()->id, 'is_guest' => 0, - 'customer_first_name' => $this->getCurrentCustomer()->user()->first_name, - 'customer_last_name' => $this->getCurrentCustomer()->user()->last_name, - 'customer_email' => $this->getCurrentCustomer()->user()->email, + 'customer_first_name' => auth()->guard()->user()->first_name, + 'customer_last_name' => auth()->guard()->user()->last_name, + 'customer_email' => auth()->guard()->user()->email, ], $guestCart->id); session()->forget('cart'); @@ -204,7 +204,7 @@ trait CartTools } $wishlistItems = $this->wishlistRepository->findWhere([ - 'customer_id' => $this->getCurrentCustomer()->user()->id, + 'customer_id' => auth()->guard()->user()->id, 'product_id' => $cartItem->product_id, ]); @@ -225,7 +225,7 @@ trait CartTools if (! $found) { $this->wishlistRepository->create([ 'channel_id' => $cart->channel_id, - 'customer_id' => $this->getCurrentCustomer()->user()->id, + 'customer_id' => auth()->guard()->user()->id, 'product_id' => $cartItem->product_id, 'additional' => $cartItem->additional, ]); diff --git a/packages/Webkul/Checkout/src/Traits/CartValidators.php b/packages/Webkul/Checkout/src/Traits/CartValidators.php index f08720df8..c09323b05 100644 --- a/packages/Webkul/Checkout/src/Traits/CartValidators.php +++ b/packages/Webkul/Checkout/src/Traits/CartValidators.php @@ -19,7 +19,7 @@ trait CartValidators */ public function hasProduct($product): bool { - $cart = \Cart::getCart(); + $cart = $this->getCart(); if (! $cart) { return false; diff --git a/packages/Webkul/Core/src/Config/concord.php b/packages/Webkul/Core/src/Config/concord.php index a8905ae21..937a22ecc 100644 --- a/packages/Webkul/Core/src/Config/concord.php +++ b/packages/Webkul/Core/src/Config/concord.php @@ -5,6 +5,7 @@ return [ 'convention' => Webkul\Core\CoreConvention::class, 'modules' => [ + /** * Example: * VendorA\ModuleX\Providers\ModuleServiceProvider::class, @@ -37,5 +38,6 @@ return [ \Webkul\Ui\Providers\ModuleServiceProvider::class, \Webkul\User\Providers\ModuleServiceProvider::class, \Webkul\Velocity\Providers\ModuleServiceProvider::class, - ] -]; \ No newline at end of file + + ], +]; diff --git a/packages/Webkul/Core/src/Config/sanctum.php b/packages/Webkul/Core/src/Config/sanctum.php new file mode 100644 index 000000000..310412eda --- /dev/null +++ b/packages/Webkul/Core/src/Config/sanctum.php @@ -0,0 +1,65 @@ + explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( + '%s%s', + 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1', + env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : '' + ))), + + /* + |-------------------------------------------------------------------------- + | Sanctum Guards + |-------------------------------------------------------------------------- + | + | This array contains the authentication guards that will be checked when + | Sanctum is trying to authenticate a request. If none of these guards + | are able to authenticate the request, Sanctum will use the bearer + | token that's present on an incoming request for authentication. + | + */ + + 'guard' => ['customer'], + + /* + |-------------------------------------------------------------------------- + | Expiration Minutes + |-------------------------------------------------------------------------- + | + | This value controls the number of minutes until an issued token will be + | considered expired. If this value is null, personal access tokens do + | not expire. This won't tweak the lifetime of first-party sessions. + | + */ + + 'expiration' => null, + + /* + |-------------------------------------------------------------------------- + | Sanctum Middleware + |-------------------------------------------------------------------------- + | + | When authenticating your first-party SPA with Sanctum you may need to + | customize some of the middleware Sanctum uses while processing the + | request. You may change the middleware listed below as required. + | + */ + + 'middleware' => [ + 'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class, + 'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class, + ], + +]; diff --git a/packages/Webkul/Core/src/Config/scout.php b/packages/Webkul/Core/src/Config/scout.php index b2f0f4d22..3613666ca 100644 --- a/packages/Webkul/Core/src/Config/scout.php +++ b/packages/Webkul/Core/src/Config/scout.php @@ -41,7 +41,20 @@ return [ | */ - 'queue' => env('SCOUT_QUEUE', true), + 'queue' => env('SCOUT_QUEUE', false), + + /* + |-------------------------------------------------------------------------- + | Database Transactions + |-------------------------------------------------------------------------- + | + | This configuration option determines if your data will only be synced + | with your search indexes after every open database transaction has + | been committed, thus preventing any discarded data from syncing. + | + */ + + 'after_commit' => false, /* |-------------------------------------------------------------------------- @@ -72,6 +85,21 @@ return [ 'soft_delete' => false, + /* + |-------------------------------------------------------------------------- + | Identify User + |-------------------------------------------------------------------------- + | + | This option allows you to control whether to notify the search engine + | of the user performing the search. This is sometimes useful if the + | engine supports any analytics based on this application's users. + | + | Supported engines: "algolia" + | + */ + + 'identify' => env('SCOUT_IDENTIFY', false), + /* |-------------------------------------------------------------------------- | Algolia Configuration diff --git a/packages/Webkul/Core/src/Providers/CoreServiceProvider.php b/packages/Webkul/Core/src/Providers/CoreServiceProvider.php index b944fca58..8ed6c09d6 100755 --- a/packages/Webkul/Core/src/Providers/CoreServiceProvider.php +++ b/packages/Webkul/Core/src/Providers/CoreServiceProvider.php @@ -38,6 +38,7 @@ class CoreServiceProvider extends ServiceProvider $this->publishes([ dirname(__DIR__) . '/Config/concord.php' => config_path('concord.php'), + dirname(__DIR__) . '/Config/sanctum.php' => config_path('sanctum.php'), dirname(__DIR__) . '/Config/scout.php' => config_path('scout.php'), ]); diff --git a/packages/Webkul/Customer/src/Database/Factories/CustomerAddressFactory.php b/packages/Webkul/Customer/src/Database/Factories/CustomerAddressFactory.php index 4c0f3875c..f18fecf75 100644 --- a/packages/Webkul/Customer/src/Database/Factories/CustomerAddressFactory.php +++ b/packages/Webkul/Customer/src/Database/Factories/CustomerAddressFactory.php @@ -2,10 +2,10 @@ namespace Webkul\Customer\Database\Factories; -use Webkul\Customer\Models\Customer; -use Illuminate\Support\Arr; -use Webkul\Customer\Models\CustomerAddress; use Illuminate\Database\Eloquent\Factories\Factory; +use Illuminate\Support\Arr; +use Webkul\Customer\Models\Customer; +use Webkul\Customer\Models\CustomerAddress; class CustomerAddressFactory extends Factory { @@ -20,6 +20,7 @@ class CustomerAddressFactory extends Factory * Define the model's default state. * * @return array + * * @throws \Exception */ public function definition(): array @@ -46,7 +47,3 @@ class CustomerAddressFactory extends Factory ]; } } - - - - diff --git a/packages/Webkul/Customer/src/Database/Factories/CustomerFactory.php b/packages/Webkul/Customer/src/Database/Factories/CustomerFactory.php index 626889829..fc5a7c6fc 100644 --- a/packages/Webkul/Customer/src/Database/Factories/CustomerFactory.php +++ b/packages/Webkul/Customer/src/Database/Factories/CustomerFactory.php @@ -2,10 +2,10 @@ namespace Webkul\Customer\Database\Factories; -use Illuminate\Support\Facades\Hash; -use Illuminate\Support\Arr; -use Webkul\Customer\Models\Customer; use Illuminate\Database\Eloquent\Factories\Factory; +use Illuminate\Support\Arr; +use Illuminate\Support\Facades\Hash; +use Webkul\Customer\Models\Customer; class CustomerFactory extends Factory { @@ -17,6 +17,8 @@ class CustomerFactory extends Factory protected $model = Customer::class; /** + * States. + * * @var array */ protected $states = [ @@ -28,32 +30,35 @@ class CustomerFactory extends Factory * Define the model's default state. * * @return array + * * @throws \Exception */ public function definition(): array { - $now = date("Y-m-d H:i:s"); - $password = $this->faker->password; - return [ - 'first_name' => $this->faker->firstName(), - 'last_name' => $this->faker->lastName, - 'gender' => Arr::random([ + 'first_name' => $this->faker->firstName(), + 'last_name' => $this->faker->lastName, + 'gender' => Arr::random([ 'male', 'female', 'other', ]), - 'email' => $this->faker->email, - 'status' => 1, - 'password' => Hash::make($password), + 'email' => $this->faker->email, + 'status' => 1, + 'password' => Hash::make($password = $this->faker->password), 'customer_group_id' => 2, - 'is_verified' => 1, - 'created_at' => $now, - 'updated_at' => $now, - 'notes' => json_encode(['plain_password' => $password], JSON_THROW_ON_ERROR), + 'is_verified' => 1, + 'created_at' => $now = date('Y-m-d H:i:s'), + 'updated_at' => $now, + 'notes' => json_encode(['plain_password' => $password], JSON_THROW_ON_ERROR), ]; } + /** + * Male. + * + * @return \Webkul\Customer\Database\Factories\CustomerFactory + */ public function male(): CustomerFactory { return $this->state(function (array $attributes) { @@ -63,6 +68,11 @@ class CustomerFactory extends Factory }); } + /** + * Female. + * + * @return \Webkul\Customer\Database\Factories\CustomerFactory + */ public function female(): CustomerFactory { return $this->state(function (array $attributes) { diff --git a/packages/Webkul/Customer/src/Database/Factories/CustomerWishlistFactory.php b/packages/Webkul/Customer/src/Database/Factories/CustomerWishlistFactory.php new file mode 100644 index 000000000..2699369d2 --- /dev/null +++ b/packages/Webkul/Customer/src/Database/Factories/CustomerWishlistFactory.php @@ -0,0 +1,35 @@ + Channel::factory(), + 'product_id' => Product::factory(), + 'customer_id' => Customer::factory(), + ]; + } +} diff --git a/packages/Webkul/Customer/src/Helpers/Wishlist.php b/packages/Webkul/Customer/src/Helpers/Wishlist.php index 5f336850f..473941c5d 100644 --- a/packages/Webkul/Customer/src/Helpers/Wishlist.php +++ b/packages/Webkul/Customer/src/Helpers/Wishlist.php @@ -14,9 +14,7 @@ class Wishlist { $wishlist = false; - $guard = request()->has('token') ? 'api' : 'customer'; - - if ($customer = auth()->guard($guard)->user()) { + if ($customer = auth()->guard()->user()) { $wishlist = $customer->wishlist_items->filter(function ($item) use ($product) { return $item->channel_id == core()->getCurrentChannel()->id && $item->product_id == $product->product_id; })->first(); diff --git a/packages/Webkul/Customer/src/Models/Customer.php b/packages/Webkul/Customer/src/Models/Customer.php index ff0ecb439..0756539c6 100755 --- a/packages/Webkul/Customer/src/Models/Customer.php +++ b/packages/Webkul/Customer/src/Models/Customer.php @@ -7,6 +7,7 @@ use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\URL; +use Laravel\Sanctum\HasApiTokens; use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject; use Webkul\Checkout\Models\CartProxy; use Webkul\Core\Models\SubscribersListProxy; @@ -18,7 +19,7 @@ use Webkul\Sales\Models\OrderProxy; class Customer extends Authenticatable implements CustomerContract, JWTSubject { - use HasFactory, Notifiable; + use HasApiTokens, HasFactory, Notifiable; /** * The table associated with the model. diff --git a/packages/Webkul/Customer/src/Models/Wishlist.php b/packages/Webkul/Customer/src/Models/Wishlist.php index 1a2176eff..2f08d9cf8 100755 --- a/packages/Webkul/Customer/src/Models/Wishlist.php +++ b/packages/Webkul/Customer/src/Models/Wishlist.php @@ -2,12 +2,15 @@ namespace Webkul\Customer\Models; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Webkul\Customer\Contracts\Wishlist as WishlistContract; use Webkul\Product\Models\ProductProxy; class Wishlist extends Model implements WishlistContract { + use HasFactory; + /** * The table associated with the model. * @@ -44,4 +47,14 @@ class Wishlist extends Model implements WishlistContract { return $this->hasOne(ProductProxy::modelClass(), 'id', 'product_id'); } + + /** + * Create a new factory instance for the model + * + * @return Factory + */ + protected static function newFactory() + { + return \Webkul\Customer\Database\Factories\CustomerWishlistFactory::new (); + } } diff --git a/packages/Webkul/Product/src/Database/Factories/ProductFactory.php b/packages/Webkul/Product/src/Database/Factories/ProductFactory.php index 207434b30..56ff4c2f0 100644 --- a/packages/Webkul/Product/src/Database/Factories/ProductFactory.php +++ b/packages/Webkul/Product/src/Database/Factories/ProductFactory.php @@ -2,8 +2,8 @@ namespace Webkul\Product\Database\Factories; -use Webkul\Product\Models\Product; use Illuminate\Database\Eloquent\Factories\Factory; +use Webkul\Product\Models\Product; class ProductFactory extends Factory { @@ -15,6 +15,8 @@ class ProductFactory extends Factory protected $model = Product::class; /** + * States. + * * @var string[] */ protected $states = [ @@ -32,7 +34,7 @@ class ProductFactory extends Factory public function definition(): array { return [ - 'sku' => $this->faker->uuid, + 'sku' => $this->faker->uuid, 'attribute_family_id' => 1, ]; } @@ -72,4 +74,4 @@ class ProductFactory extends Factory ]; }); } -} \ No newline at end of file +} diff --git a/packages/Webkul/Product/src/Repositories/ProductRepository.php b/packages/Webkul/Product/src/Repositories/ProductRepository.php index 4951a83f4..e1c9f6dd4 100755 --- a/packages/Webkul/Product/src/Repositories/ProductRepository.php +++ b/packages/Webkul/Product/src/Repositories/ProductRepository.php @@ -256,8 +256,8 @@ class ProductRepository extends Repository if (count($priceRange) > 0) { $customerGroupId = null; - if (Cart::getCurrentCustomer()->check()) { - $customerGroupId = Cart::getCurrentCustomer()->user()->customer_group_id; + if (auth()->guard()->check()) { + $customerGroupId = auth()->guard()->user()->customer_group_id; } else { $customerGuestGroup = app('Webkul\Customer\Repositories\CustomerGroupRepository')->getCustomerGuestGroup(); diff --git a/packages/Webkul/Product/src/Type/AbstractType.php b/packages/Webkul/Product/src/Type/AbstractType.php index 7805b7038..8f22a0838 100644 --- a/packages/Webkul/Product/src/Type/AbstractType.php +++ b/packages/Webkul/Product/src/Type/AbstractType.php @@ -652,8 +652,8 @@ abstract class AbstractType $customerGroupId = null; - if (Cart::getCurrentCustomer()->check()) { - $customerGroupId = Cart::getCurrentCustomer()->user()->customer_group_id; + if (auth()->guard()->check()) { + $customerGroupId = auth()->guard()->user()->customer_group_id; } else { $customerGuestGroup = app(CustomerGroupRepository::class)->getCustomerGuestGroup(); @@ -1008,8 +1008,8 @@ abstract class AbstractType $haveOffers = true; $customerGroupId = null; - if (Cart::getCurrentCustomer()->check()) { - $customerGroupId = Cart::getCurrentCustomer()->user()->customer_group_id; + if (auth()->guard()->check()) { + $customerGroupId = auth()->guard()->user()->customer_group_id; } else { $customerGroupRepository = app('Webkul\Customer\Repositories\CustomerGroupRepository'); diff --git a/packages/Webkul/User/src/Models/Admin.php b/packages/Webkul/User/src/Models/Admin.php index 59eb45dd4..bcef89f97 100755 --- a/packages/Webkul/User/src/Models/Admin.php +++ b/packages/Webkul/User/src/Models/Admin.php @@ -6,14 +6,15 @@ use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; +use Laravel\Sanctum\HasApiTokens; +use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject; use Webkul\User\Contracts\Admin as AdminContract; use Webkul\User\Database\Factories\AdminFactory; use Webkul\User\Notifications\AdminResetPassword; -use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject; class Admin extends Authenticatable implements AdminContract, JWTSubject { - use HasFactory, Notifiable; + use HasFactory, HasApiTokens, Notifiable; /** * The attributes that are mass assignable. @@ -79,11 +80,11 @@ class Admin extends Authenticatable implements AdminContract, JWTSubject /** * Create a new factory instance for the model. * - * @return Factory + * @return \Illuminate\Database\Eloquent\Factories\Factory */ protected static function newFactory(): Factory { - return AdminFactory::new(); + return AdminFactory::new (); } /** diff --git a/packages/Webkul/User/src/Models/AdminProxy.php b/packages/Webkul/User/src/Models/AdminProxy.php index 06721d054..76c466bf8 100644 --- a/packages/Webkul/User/src/Models/AdminProxy.php +++ b/packages/Webkul/User/src/Models/AdminProxy.php @@ -6,5 +6,4 @@ use Konekt\Concord\Proxies\ModelProxy; class AdminProxy extends ModelProxy { - -} \ No newline at end of file +} diff --git a/packages/Webkul/User/src/Models/Role.php b/packages/Webkul/User/src/Models/Role.php index b026afef7..da247271f 100755 --- a/packages/Webkul/User/src/Models/Role.php +++ b/packages/Webkul/User/src/Models/Role.php @@ -19,12 +19,19 @@ class Role extends Model implements RoleContract 'permissions', ]; + /** + * The attributes that are castable. + * + * @var array + */ protected $casts = [ 'permissions' => 'array', ]; /** * Get the admins. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function admins() { diff --git a/packages/Webkul/User/src/Models/RoleProxy.php b/packages/Webkul/User/src/Models/RoleProxy.php index e5e58dc85..3e37adf94 100644 --- a/packages/Webkul/User/src/Models/RoleProxy.php +++ b/packages/Webkul/User/src/Models/RoleProxy.php @@ -6,5 +6,4 @@ use Konekt\Concord\Proxies\ModelProxy; class RoleProxy extends ModelProxy { - -} \ No newline at end of file +} diff --git a/tests/_support/AcceptanceTester.php b/tests/_support/AcceptanceTester.php deleted file mode 100644 index cdc9f2186..000000000 --- a/tests/_support/AcceptanceTester.php +++ /dev/null @@ -1,37 +0,0 @@ -amOnPage('/admin'); - $I->see('Sign In'); - $I->fillField('email', 'admin@example.com'); - $I->fillField('password', 'admin123'); - $I->dontSee('The "Email" field is required.'); - $I->dontSee('The "Password" field is required.'); - $I->click('Sign In'); - $I->see('Dashboard', '//h1'); - } -} diff --git a/tests/_support/ApiTester.php b/tests/_support/ApiTester.php new file mode 100644 index 000000000..f7b177246 --- /dev/null +++ b/tests/_support/ApiTester.php @@ -0,0 +1,383 @@ +create(), + ['*'] + ); + } + + /** + * Create token for sanctum authenticated customer. + * + * @param \Webkul\Customer\Models\Customer $customer + * @return string + */ + public function amCreatingTokenForSanctumAuthenticatedCustomer(Customer $customer) + { + return $this->grabTokenFromSanctumGeneratedString( + $customer->createToken($this->fake()->company)->plainTextToken + ); + } + + /** + * Set all necessary headers, if token is passed then bearable authentication header + * will pass. + * + * @param optional|string $token + * @return void + */ + public function haveAllNecessaryHeaders($token = null) + { + $this->haveHttpHeader('Accept', 'application/json'); + + $this->haveHttpHeader('Content-Type', 'application/json'); + + if ($token) { + $this->amBearerAuthenticated($token); + } + } + + /** + * Check all necessary success response. + * + * @return void + */ + public function seeAllNecessarySuccessResponse() + { + $this->seeResponseCodeIsSuccessful(); + + $this->seeResponseIsJson(); + } + + /** + * Get JSON decoded response. + * + * @return mixed + */ + public function grabJsonDecodedResponse() + { + return json_decode($this->grabResponse()); + } + + /** + * Get token from response. + * + * @return string + */ + public function grabTokenFromResponse() + { + $idAndToken = $this->grabDataFromResponseByJsonPath('token')[0]; + + return $this->grabTokenFromSanctumGeneratedString($idAndToken); + } + + /** + * Get token from sanctum generated string. + * + * @return string + */ + public function grabTokenFromSanctumGeneratedString($idAndToken) + { + $idAndToken = explode('|', $idAndToken); + + return $idAndToken[1]; + } + + /** + * Clean all fields. + * + * @param array $fields + * @return array + */ + public function cleanAllFields(array $fields) + { + return collect($fields)->map(function ($field, $key) { + return $this->cleanField($field); + })->toArray(); + } + + /** + * Clean field. + * + * @param string $field + * @return string + */ + public function cleanField($field) + { + return preg_replace('/[^A-Za-z0-9 ]/', '', $field); + } + + /** + * Generate cart. + * + * @param array $attributes + * @return \Webkul\Checkout\Contracts\Cart + */ + public function haveCart($attributes = []) + { + return Cart::factory($attributes)->adjustCustomer()->create(); + } + + /** + * Generate cart items. + * + * @param array $attributes + * @return \Webkul\Checkout\Contracts\CartItem + */ + public function haveCartItems($attributes = []) + { + return CartItem::factory($attributes)->adjustProduct()->create(); + } + + /** + * Generate simple product. + * + * @param array $configs + * @param array $productStates + * @return \Webkul\Product\Contracts\Product + */ + public function haveSimpleProduct(array $configs = [], array $productStates = []): Product + { + $I = $this; + + if (! in_array('simple', $productStates)) { + $productStates = array_merge($productStates, ['simple']); + } + + $product = $I->createProduct($configs['productAttributes'] ?? [], $productStates); + + $I->createAttributeValues($product, $configs['attributeValues'] ?? []); + + $I->createInventory($product->id, $configs['productInventory'] ?? []); + + return $product->refresh(); + } + + /** + * Create product. + * + * @param array $attributes + * @param array $states + * @return \Webkul\Product\Contracts\Product + */ + public function createProduct(array $attributes = [], array $states = []): Product + { + return Product::factory() + ->state(function () use ($states) { + return [ + 'type' => $states[0], + ]; + }) + ->create($attributes); + } + + /** + * Create product inventory. + * + * @param int $productId + * @param array $inventoryConfig + * @return void + */ + public function createInventory(int $productId, array $inventoryConfig = []): void + { + $I = $this; + + $I->have(ProductInventory::class, array_merge($inventoryConfig, [ + 'product_id' => $productId, + 'inventory_source_id' => 1, + ])); + } + + /** + * Create attribute values. + * + * @param \Webkul\Product\Contracts\Product $product + * @param array $attributeValues + * @return void + */ + public function createAttributeValues(Product $product, array $attributeValues = []): void + { + $I = $this; + + $brand = Attribute::query()->where(['code' => 'brand'])->firstOrFail(); + + if (! AttributeOption::query()->where(['attribute_id' => $brand->id])->exists()) { + AttributeOption::create([ + 'admin_name' => 'Webkul Demo Brand (c) 2020', + 'attribute_id' => $brand->id, + ]); + } + + /** + * Some defaults that should apply to all generated products. + * By defaults products will be generated as saleable. + * If you do not want this, this defaults can be overriden by $attributeValues. + */ + $defaultAttributeValues = [ + 'name' => $I->fake()->words(3, true), + 'description' => $I->fake()->sentence, + 'short_description' => $I->fake()->sentence, + 'sku' => $product->sku, + 'url_key' => $I->fake()->slug, + 'status' => true, + 'guest_checkout' => true, + 'visible_individually' => true, + 'special_price_from' => null, + 'special_price_to' => null, + 'special_price' => null, + 'price' => $I->fake()->randomFloat(2, 1, 1000), + 'weight' => '1.00', + 'brand' => AttributeOption::query()->firstWhere('attribute_id', $brand->id)->id, + ]; + + $attributeValues = array_merge($defaultAttributeValues, $attributeValues); + + $possibleAttributeValues = DB::table('attributes') + ->select('id', 'code', 'type') + ->get() + ->toArray(); + + foreach ($possibleAttributeValues as $attributeSet) { + $data = [ + 'product_id' => $product->id, + 'attribute_id' => $attributeSet->id, + ]; + + $fieldName = self::getAttributeFieldName($attributeSet->type); + + $data[$fieldName] = $attributeValues[$attributeSet->code] ?? null; + + $data = $this->appendAttributeDependencies($attributeSet->code, $data); + + $I->have(ProductAttributeValue::class, $data); + } + } + + /** + * Get attribute field names. + * + * @param string $type + * @return string|void + */ + private static function getAttributeFieldName(string $type): ?string + { + $possibleTypes = [ + 'text' => 'text_value', + 'select' => 'integer_value', + 'boolean' => 'boolean_value', + 'textarea' => 'text_value', + 'price' => 'float_value', + 'date' => 'date_value', + 'checkbox' => 'text_value', + ]; + + return $possibleTypes[$type]; + } + + /** + * Append attribute dependencies. + * + * @param string $attributeCode + * @param array $data + * @return array + */ + private function appendAttributeDependencies(string $attributeCode, array $data): array + { + $locale = core()->getCurrentLocale()->code; + + $channel = core()->getCurrentChannelCode(); + + $attributeSetDependencies = [ + 'name' => [ + 'locale', + 'channel', + ], + 'tax_category_id' => [ + 'channel', + ], + 'short_description' => [ + 'locale', + 'channel', + ], + 'description' => [ + 'locale', + 'channel', + ], + 'cost' => [ + 'channel', + ], + 'special_price_from' => [ + 'channel', + ], + 'special_price_to' => [ + 'channel', + ], + 'meta_title' => [ + 'locale', + 'channel', + ], + 'meta_keywords' => [ + 'locale', + 'channel', + ], + 'meta_description' => [ + 'locale', + 'channel', + ], + 'custom_sale_badge' => [ + 'locale', + ], + ]; + + if (array_key_exists($attributeCode, $attributeSetDependencies)) { + foreach ($attributeSetDependencies[$attributeCode] as $key) { + if ($key === 'locale') { + $data['locale'] = $locale; + } + + if ($key === 'channel') { + $data['channel'] = $channel; + } + } + } + + return $data; + } +} diff --git a/tests/_support/FunctionalTester.php b/tests/_support/FunctionalTester.php index f89e14708..673aa0fdb 100644 --- a/tests/_support/FunctionalTester.php +++ b/tests/_support/FunctionalTester.php @@ -1,15 +1,14 @@ login($admin); + Auth::guard('admin')->login($admin); $I->seeAuthentication('admin'); @@ -64,9 +59,9 @@ class FunctionalTester extends Actor * Set the logged in user to the customer identity. * * @param \Webkul\User\Models\Customer|null $customer + * @return Customer * * @throws \Exception - * @returns Customer */ public function loginAsCustomer(Customer $customer = null): Customer { @@ -76,8 +71,7 @@ class FunctionalTester extends Actor $customer = $I->have(Customer::class); } - Auth::guard('customer') - ->login($customer); + Auth::guard('customer')->login($customer); $I->seeAuthentication('customer'); @@ -85,9 +79,12 @@ class FunctionalTester extends Actor } /** - * @param string $name - * @param array $params - * @param bool $routeCheck set this to false if the action is doing a redirection + * On admin route. + * + * @param string $name + * @param array $params + * @param bool $routeCheck + * @return void */ public function amOnAdminRoute(string $name, array $params = [], bool $routeCheck = true) { @@ -98,19 +95,17 @@ class FunctionalTester extends Actor $I->seeCurrentRouteIs($name); } - /** @var RouteCollection $routes */ $routes = Route::getRoutes(); $middlewares = $routes->getByName($name)->middleware(); $I->assertContains('admin', $middlewares, 'check that admin middleware is applied'); } /** - * Set specific Webkul/Core configuration keys to a given value + * Set specific Webkul/Core configuration keys to a given value. * - * // TODO: change method as soon as there is a method to set core config data - * - * @param $data array containing 'code => value' pairs + * TODO: Change method as soon as there is a method to set core config data. * + * @param $data array containing 'code => value' pairs * @return void */ public function setConfigData($data): void @@ -133,6 +128,11 @@ class FunctionalTester extends Actor } } + /** + * Use default theme. + * + * @return void. + */ public function useDefaultTheme(): void { $channel = core()->getCurrentChannel(); diff --git a/tests/_support/Helper/Acceptance.php b/tests/_support/Helper/Acceptance.php deleted file mode 100644 index 65b94215e..000000000 --- a/tests/_support/Helper/Acceptance.php +++ /dev/null @@ -1,10 +0,0 @@ -comment('I execute function "' + + $I->comment( + 'I execute function "' . $functionName . '" of class "' . (is_object($className) ? get_class($className) : $className) @@ -59,9 +55,13 @@ class UnitTester extends \Codeception\Actor . count($mocks) . ' mocked class-methods/params' ); + $class = new \ReflectionClass($className); + $method = $class->getMethod($functionName); + $method->setAccessible(true); + if (is_object($className)) { $reflectedClass = $className; } elseif (empty($constructParams)) { diff --git a/tests/acceptance.suite.yml b/tests/acceptance.suite.yml deleted file mode 100644 index 012379ee8..000000000 --- a/tests/acceptance.suite.yml +++ /dev/null @@ -1,30 +0,0 @@ -# Codeception Test Suite Configuration -# -# Suite for acceptance tests. -# Perform tests in browser using the WebDriver or PhpBrowser. -# If you need both WebDriver and PHPBrowser tests - create a separate suite. - -actor: AcceptanceTester -modules: - enabled: - - \Helper\Acceptance - - Asserts - - WebDriver: - url: http://nginx/ - host: selenium-chrome - browser: chrome - window_size: 1920x1080 - restart: true - wait: 20 - pageload_timeout: 10 - connection_timeout: 60 - request_timeout: 60 - log_js_errors: true - - Webkul\Core\Helpers\Laravel5Helper: - part: ORM - cleanup: false - environment_file: .env - database_seeder_class: DatabaseSeeder - url: http://nginx - -step_decorators: ~ \ No newline at end of file diff --git a/tests/acceptance/BookingProduct/BookingProductEventTicketCest.php b/tests/acceptance/BookingProduct/BookingProductEventTicketCest.php deleted file mode 100644 index 2058b257c..000000000 --- a/tests/acceptance/BookingProduct/BookingProductEventTicketCest.php +++ /dev/null @@ -1,54 +0,0 @@ -faker = Factory::create(); - } - - public function testSpecialPricesAreShown(AcceptanceTester $I): void - { - $product = $I->haveProduct(Laravel5Helper::VIRTUAL_PRODUCT); - Product::query()->where('id', $product->id)->update(['type' => 'booking']); - - $bookingProduct = $I->have(BookingProduct::class, [ - 'type' => 'event', - 'available_to' => Carbon::now()->addMinutes($this->faker->numberBetween(2, 59))->toDateTimeString(), - 'product_id' => $product->id, - ]); - - $scenario['ticket'] = [ - 'price' => 10, - 'special_price' => 5 - ]; - - $ticket = $I->have( - BookingProductEventTicket::class, - array_merge( - ['booking_product_id' => $bookingProduct->id], - $scenario['ticket'] - ) - ); - - $I->amOnPage($product->url_key); - - $I->see(core()->currency($ticket->price), '//span[@class="regular-price"]'); - $I->see( - __('bookingproduct::app.shop.products.per-ticket-price', ['price' => core()->currency($ticket->special_price)]), - '//span[@class="special-price"]' - ); - } -} diff --git a/tests/acceptance/GuestCheckoutCest.php b/tests/acceptance/GuestCheckoutCest.php deleted file mode 100644 index 0b62b9260..000000000 --- a/tests/acceptance/GuestCheckoutCest.php +++ /dev/null @@ -1,60 +0,0 @@ -faker = Factory::create(); - } - - function testToConfigureGlobalGuestCheckout(AcceptanceTester $I) - { - $admin = config('app.admin_url'); - $I->loginAsAdmin(); - - $I->amGoingTo('turn ON the global guest checkout configuration'); - $I->amOnPage($admin . '/configuration/catalog/products'); - $I->see(__('admin::app.admin.system.allow-guest-checkout')); - $I->selectOption('catalog[products][guest-checkout][allow-guest-checkout]', 1); - $I->click(__('admin::app.configuration.save-btn-title')); - $I->seeRecord('core_config', ['code' => 'catalog.products.guest-checkout.allow-guest-checkout', 'value' => 1]); - - $I->amGoingTo('assert that the product guest checkout configuration is shown'); - $I->amOnPage($admin . '/catalog/products'); - $I->click(__('admin::app.catalog.products.add-product-btn-title')); - $I->selectOption('attribute_family_id', 1); - $I->fillField('sku', $this->faker->uuid); - $I->dontSeeInSource('The "SKU" field is required.'); - $I->click(__('admin::app.catalog.products.save-btn-title')); - $I->seeInCurrentUrl($admin . '/catalog/products/edit'); - $I->scrollTo('#new'); - $I->see('Guest Checkout'); - $I->seeInSource('amGoingTo('turn OFF the global guest checkout configuration'); - $I->amOnPage($admin . '/configuration/catalog/products'); - $I->see(__('admin::app.admin.system.allow-guest-checkout')); - $I->selectOption('catalog[products][guest-checkout][allow-guest-checkout]', 0); - $I->click(__('admin::app.configuration.save-btn-title')); - $I->seeRecord('core_config', ['code' => 'catalog.products.guest-checkout.allow-guest-checkout', 'value' => 0]); - - $I->amGoingTo('assert that the product guest checkout configuration is not shown'); - $I->amOnPage($admin . '/catalog/products'); - $I->click(__('admin::app.catalog.products.add-product-btn-title')); - $I->selectOption('attribute_family_id', 1); - $I->fillField('sku', $this->faker->uuid); - $I->dontSeeInSource('The "SKU" field is required.'); - $I->click(__('admin::app.catalog.products.save-btn-title')); - $I->seeInCurrentUrl($admin . '/catalog/products/edit'); - $I->scrollTo('#new'); - $I->dontSee('Guest Checkout'); - $I->dontSeeInSource('sendGet($this->getVersionRoute('attributes')); + + $I->seeAllNecessarySuccessResponse(); + } + + public function testForFetchingTheAttributeById(ApiTester $I) + { + $attribute = Attribute::find(1); + + $I->sendGet($this->getVersionRoute('attributes/' . $attribute->id)); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'id' => $attribute->id, + 'code' => $attribute->code, + 'type' => $attribute->type, + 'name' => $attribute->name, + ]); + } +} diff --git a/tests/api/V1/Shop/Catalog/AttributeFamilyCest.php b/tests/api/V1/Shop/Catalog/AttributeFamilyCest.php new file mode 100644 index 000000000..8884cee98 --- /dev/null +++ b/tests/api/V1/Shop/Catalog/AttributeFamilyCest.php @@ -0,0 +1,32 @@ +sendGet($this->getVersionRoute('attribute-families')); + + $I->seeAllNecessarySuccessResponse(); + } + + public function testForFetchingTheAttributeFamilyById(ApiTester $I) + { + $attributeFamily = AttributeFamily::find(1); + + $I->sendGet($this->getVersionRoute('attribute-families/' . $attributeFamily->id)); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'id' => $attributeFamily->id, + 'code' => $attributeFamily->code, + 'name' => $attributeFamily->name, + 'groups' => [], + ]); + } +} diff --git a/tests/api/V1/Shop/Catalog/CatalogCest.php b/tests/api/V1/Shop/Catalog/CatalogCest.php new file mode 100644 index 000000000..a8c43ac0c --- /dev/null +++ b/tests/api/V1/Shop/Catalog/CatalogCest.php @@ -0,0 +1,9 @@ +sendGet($this->getVersionRoute('categories')); + + $I->seeAllNecessarySuccessResponse(); + } +} diff --git a/tests/api/V1/Shop/Catalog/ProductCest.php b/tests/api/V1/Shop/Catalog/ProductCest.php new file mode 100755 index 000000000..d03e7e9db --- /dev/null +++ b/tests/api/V1/Shop/Catalog/ProductCest.php @@ -0,0 +1,15 @@ +sendGet($this->getVersionRoute('products')); + + $I->seeAllNecessarySuccessResponse(); + } +} diff --git a/tests/api/V1/Shop/Core/ChannelCest.php b/tests/api/V1/Shop/Core/ChannelCest.php new file mode 100644 index 000000000..a2d79bc46 --- /dev/null +++ b/tests/api/V1/Shop/Core/ChannelCest.php @@ -0,0 +1,31 @@ +sendGet($this->getVersionRoute('channels')); + + $I->seeAllNecessarySuccessResponse(); + } + + public function testForFetchingTheChannelById(ApiTester $I) + { + $channel = Channel::find(1); + + $I->sendGet($this->getVersionRoute('channels/' . $channel->id)); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'id' => $channel->id, + 'code' => $channel->code, + 'name' => $channel->name, + ]); + } +} diff --git a/tests/api/V1/Shop/Core/CoreCest.php b/tests/api/V1/Shop/Core/CoreCest.php new file mode 100755 index 000000000..c4a00dec8 --- /dev/null +++ b/tests/api/V1/Shop/Core/CoreCest.php @@ -0,0 +1,9 @@ +sendGet($this->getVersionRoute('countries')); + + $I->seeAllNecessarySuccessResponse(); + } + + public function testForFetchingTheCountryById(ApiTester $I) + { + $country = Country::find(1); + + $I->sendGet($this->getVersionRoute('countries/' . $country->id)); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'id' => $country->id, + 'code' => $country->code, + 'name' => $country->name, + ]); + } + + public function testForFetchingStatesGroupByCountries(ApiTester $I) + { + $I->sendGet($this->getVersionRoute('countries/states/groups')); + + $I->seeAllNecessarySuccessResponse(); + } +} diff --git a/tests/api/V1/Shop/Core/CurrencyCest.php b/tests/api/V1/Shop/Core/CurrencyCest.php new file mode 100644 index 000000000..f59c961de --- /dev/null +++ b/tests/api/V1/Shop/Core/CurrencyCest.php @@ -0,0 +1,31 @@ +sendGet($this->getVersionRoute('currencies')); + + $I->seeAllNecessarySuccessResponse(); + } + + public function testForFetchingTheCurrencyById(ApiTester $I) + { + $currency = Currency::find(1); + + $I->sendGet($this->getVersionRoute('currencies/' . $currency->id)); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'id' => $currency->id, + 'code' => $currency->code, + 'name' => $currency->name, + ]); + } +} diff --git a/tests/api/V1/Shop/Core/LocaleCest.php b/tests/api/V1/Shop/Core/LocaleCest.php new file mode 100644 index 000000000..7968b7d74 --- /dev/null +++ b/tests/api/V1/Shop/Core/LocaleCest.php @@ -0,0 +1,31 @@ +sendGet($this->getVersionRoute('locales')); + + $I->seeAllNecessarySuccessResponse(); + } + + public function testForFetchingTheLocaleById(ApiTester $I) + { + $locale = Locale::find(1); + + $I->sendGet($this->getVersionRoute('locales/' . $locale->id)); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'id' => $locale->id, + 'code' => $locale->code, + 'name' => $locale->name, + ]); + } +} diff --git a/tests/api/V1/Shop/Core/SliderCest.php b/tests/api/V1/Shop/Core/SliderCest.php new file mode 100644 index 000000000..9b7ae0420 --- /dev/null +++ b/tests/api/V1/Shop/Core/SliderCest.php @@ -0,0 +1,15 @@ +sendGet($this->getVersionRoute('sliders')); + + $I->seeAllNecessarySuccessResponse(); + } +} diff --git a/tests/api/V1/Shop/Customer/AddressCest.php b/tests/api/V1/Shop/Customer/AddressCest.php new file mode 100644 index 000000000..a4f833889 --- /dev/null +++ b/tests/api/V1/Shop/Customer/AddressCest.php @@ -0,0 +1,177 @@ +fake()->randomDigitNotZero(); + + $customer = $I->amSanctumAuthenticatedCustomer(); + + $I->haveMultiple(CustomerAddress::class, $howManyAddresses, [ + 'customer_id' => $customer->id, + ]); + + $I->haveAllNecessaryHeaders(); + + $I->sendGet($this->getVersionRoute('customer/addresses')); + + $I->seeAllNecessarySuccessResponse(); + + $response = $I->grabJsonDecodedResponse(); + + $I->assertEquals($howManyAddresses, count($response->data)); + } + + public function testForStoringTheCustomerAddress(ApiTester $I) + { + $I->amSanctumAuthenticatedCustomer(); + + $I->haveAllNecessaryHeaders(); + + $fields = $I->cleanAllFields([ + 'first_name' => $I->fake()->firstName, + 'last_name' => $I->fake()->lastName, + 'address1' => [$I->fake()->streetAddress], + 'company_name' => $I->fake()->company, + 'country' => $I->fake()->countryCode, + 'state' => $I->fake()->word, + 'city' => $I->fake()->city, + 'postcode' => $I->fake()->postcode, + 'phone' => $I->fake()->phoneNumber, + ]); + + $I->sendPost($this->getVersionRoute('customer/addresses'), $fields); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'data' => [ + 'first_name' => $fields['first_name'], + 'last_name' => $fields['last_name'], + 'address1' => $fields['address1'], + 'company_name' => $fields['company_name'], + 'country' => $fields['country'], + 'state' => $fields['state'], + 'city' => $fields['city'], + 'postcode' => $fields['postcode'], + 'phone' => $fields['phone'], + ], + ]); + } + + public function testForFetchingTheCustomerAddress(ApiTester $I) + { + $customer = $I->amSanctumAuthenticatedCustomer(); + + $customerAddress = $I->have(CustomerAddress::class, [ + 'customer_id' => $customer->id, + 'first_name' => $I->fake()->firstName, + 'last_name' => $I->fake()->lastName, + 'address1' => $I->fake()->streetAddress, + 'company_name' => $I->fake()->company, + 'country' => $I->fake()->countryCode, + 'state' => $I->fake()->word, + 'city' => $I->fake()->city, + 'postcode' => $I->fake()->postcode, + 'phone' => $I->fake()->phoneNumber, + ]); + + $I->haveAllNecessaryHeaders(); + + $I->sendGet($this->getVersionRoute('customer/addresses/' . $customerAddress->id)); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'data' => [ + 'first_name' => $customerAddress->first_name, + 'last_name' => $customerAddress->last_name, + 'address1' => [$customerAddress->address1], + 'company_name' => $customerAddress->company_name, + 'country' => $customerAddress->country, + 'state' => $customerAddress->state, + 'city' => $customerAddress->city, + 'postcode' => $customerAddress->postcode, + 'phone' => $customerAddress->phone, + ], + ]); + } + + public function testForUpdatingTheCustomerAddress(ApiTester $I) + { + $customer = $I->amSanctumAuthenticatedCustomer(); + + $customerAddress = $I->have(CustomerAddress::class, [ + 'customer_id' => $customer->id, + 'first_name' => $I->fake()->firstName, + 'last_name' => $I->fake()->lastName, + 'address1' => $I->fake()->streetAddress, + 'company_name' => $I->fake()->company, + 'country' => $I->fake()->countryCode, + 'state' => $I->fake()->word, + 'city' => $I->fake()->city, + 'postcode' => $I->fake()->postcode, + 'phone' => $I->fake()->phoneNumber, + ]); + + $I->haveAllNecessaryHeaders(); + + $fields = $I->cleanAllFields([ + 'first_name' => $I->fake()->firstName, + 'last_name' => $I->fake()->lastName, + 'address1' => [$customerAddress->address1], + 'company_name' => $customerAddress->company_name, + 'country' => $customerAddress->country, + 'state' => $customerAddress->state, + 'city' => $customerAddress->city, + 'postcode' => $customerAddress->postcode, + 'phone' => $customerAddress->phone, + ]); + + $I->sendPut($this->getVersionRoute('customer/addresses/' . $customerAddress->id), $fields); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'data' => [ + 'first_name' => $fields['first_name'], + 'last_name' => $fields['last_name'], + 'address1' => $fields['address1'], + 'company_name' => $fields['company_name'], + 'country' => $fields['country'], + 'state' => $fields['state'], + 'city' => $fields['city'], + 'postcode' => $fields['postcode'], + 'phone' => $fields['phone'], + ], + ]); + + $I->dontSeeResponseContainsJson([ + 'data' => [ + 'first_name' => $customerAddress->firstName, + 'last_name' => $customerAddress->lastName, + ], + ]); + } + + public function testForDeletingTheCustomerAddress(ApiTester $I) + { + $customer = $I->amSanctumAuthenticatedCustomer(); + + $customerAddress = $I->have(CustomerAddress::class, [ + 'customer_id' => $customer->id, + ]); + + $I->haveAllNecessaryHeaders(); + + $I->sendDelete($this->getVersionRoute('customer/addresses/' . $customerAddress->id)); + + $I->seeAllNecessarySuccessResponse(); + } +} diff --git a/tests/api/V1/Shop/Customer/AuthCest.php b/tests/api/V1/Shop/Customer/AuthCest.php new file mode 100644 index 000000000..5ec9a635f --- /dev/null +++ b/tests/api/V1/Shop/Customer/AuthCest.php @@ -0,0 +1,127 @@ +haveAllNecessaryHeaders(); + + $I->sendPost($this->getVersionRoute('customer/register'), [ + 'first_name' => $I->fake()->firstName(), + 'last_name' => $I->fake()->lastName(), + 'email' => $I->fake()->email(), + 'password' => $password = $I->fake()->password, + 'password_confirmation' => $password, + ]); + + $I->seeAllNecessarySuccessResponse(); + } + + public function testForLoginTheCustomer(ApiTester $I) + { + $customer = $I->have(Customer::class); + + $I->haveAllNecessaryHeaders(); + + $I->sendPost($this->getVersionRoute('customer/login'), [ + 'email' => $customer->email, + 'password' => json_decode($customer->notes)->plain_password, + 'device_name' => $I->fake()->company, + ]); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'data' => [ + 'first_name' => $customer->first_name, + 'last_name' => $customer->last_name, + 'gender' => $customer->gender, + 'email' => $customer->email, + ], + ]); + } + + public function testForFetchingTheLoggedInCustomer(ApiTester $I) + { + $customer = $I->amSanctumAuthenticatedCustomer(); + + $I->haveAllNecessaryHeaders(); + + $I->sendGet($this->getVersionRoute('customer/get')); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'data' => [ + 'first_name' => $customer->first_name, + 'last_name' => $customer->last_name, + 'gender' => $customer->gender, + 'email' => $customer->email, + ], + ]); + } + + public function testForUpdatingTheLoggedInCustomer(ApiTester $I) + { + $customer = $I->amSanctumAuthenticatedCustomer(); + + $I->haveAllNecessaryHeaders(); + + $I->sendPut($this->getVersionRoute('customer/profile'), [ + 'first_name' => $changedFirstName = $I->fake()->firstName(), + 'last_name' => $changedLastName = $I->fake()->lastName(), + 'gender' => $customer->gender, + 'email' => $customer->email, + ]); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'data' => [ + 'first_name' => $changedFirstName, + 'last_name' => $changedLastName, + 'gender' => $customer->gender, + 'email' => $customer->email, + ], + ]); + + $I->dontSeeResponseContainsJson([ + 'data' => [ + 'first_name' => $customer->first_name, + 'last_name' => $customer->last_name, + ], + ]); + } + + public function testForLogoutTheCustomer(ApiTester $I) + { + $I->amSanctumAuthenticatedCustomer(); + + $I->haveAllNecessaryHeaders(); + + $I->sendPost($this->getVersionRoute('customer/logout')); + + $I->seeAllNecessarySuccessResponse(); + } + + public function testForPasswordResetLink(ApiTester $I) + { + $customer = $I->amSanctumAuthenticatedCustomer(); + + $I->haveAllNecessaryHeaders(); + + Notification::fake(); + + $I->sendPost($this->getVersionRoute('customer/forgot-password'), [ + 'email' => $customer->email, + ]); + + $I->seeAllNecessarySuccessResponse(); + } +} diff --git a/tests/api/V1/Shop/Customer/CartCest.php b/tests/api/V1/Shop/Customer/CartCest.php new file mode 100644 index 000000000..47f74a3f8 --- /dev/null +++ b/tests/api/V1/Shop/Customer/CartCest.php @@ -0,0 +1,282 @@ +amSanctumAuthenticatedCustomer(); + + $product = $I->haveSimpleProduct(); + + $cart = $I->haveCart([ + 'customer_id' => $customer->id, + ]); + + $cartItem = $I->haveCartItems([ + 'cart_id' => $cart->id, + 'product_id' => $product->id, + ]); + + $I->haveAllNecessaryHeaders(); + + $I->sendGet($this->getVersionRoute('customer/cart')); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'data' => [ + 'id' => $cart->id, + 'customer_email' => $customer->email, + 'customer_first_name' => $customer->first_name, + 'customer_last_name' => $customer->last_name, + 'items' => [ + [ + 'id' => $cartItem->id, + 'product' => [ + 'id' => $product->id, + ], + ], + ], + ], + ]); + } + + public function testForAddingItemToTheCart(ApiTester $I) + { + $customer = $I->amSanctumAuthenticatedCustomer(); + + $I->haveAllNecessaryHeaders(); + + $product = $I->haveSimpleProduct(); + + $I->sendPost($this->getVersionRoute('customer/cart/add/' . $product->id), [ + 'quantity' => 1, + ]); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'data' => [ + 'customer_email' => $customer->email, + 'customer_first_name' => $customer->first_name, + 'customer_last_name' => $customer->last_name, + 'items' => [ + [ + 'product' => [ + 'id' => $product->id, + ], + ], + ], + ], + ]); + } + + public function testForUpdatingTheCart(ApiTester $I) + { + $customer = $I->amSanctumAuthenticatedCustomer(); + + $product = $I->haveSimpleProduct(); + + $cart = $I->haveCart([ + 'customer_id' => $customer->id, + ]); + + $cartItem = $I->haveCartItems([ + 'cart_id' => $cart->id, + 'product_id' => $product->id, + ]); + + $I->haveAllNecessaryHeaders(); + + $I->sendPut($this->getVersionRoute('customer/cart/update'), [ + 'qty' => [ + $cartItem->id => $expectedQuantity = 2, + ], + ]); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'data' => [ + 'id' => $cart->id, + 'customer_email' => $customer->email, + 'customer_first_name' => $customer->first_name, + 'customer_last_name' => $customer->last_name, + 'items' => [ + [ + 'id' => $cartItem->id, + 'quantity' => $expectedQuantity, + 'product' => [ + 'id' => $product->id, + ], + ], + ], + ], + ]); + } + + public function testForRemovingItemFromTheCart(ApiTester $I) + { + $customer = $I->amSanctumAuthenticatedCustomer(); + + $cart = $I->haveCart([ + 'customer_id' => $customer->id, + ]); + + $product1 = $I->haveSimpleProduct(); + + $cartItem1 = $I->haveCartItems([ + 'cart_id' => $cart->id, + 'product_id' => $product1->id, + ]); + + $product2 = $I->haveSimpleProduct(); + + $cartItem2 = $I->haveCartItems([ + 'cart_id' => $cart->id, + 'product_id' => $product2->id, + ]); + + $I->assertEquals(2, \Webkul\Checkout\Facades\Cart::getCart()->items()->count()); + + $I->haveAllNecessaryHeaders(); + + $I->sendDelete($this->getVersionRoute('customer/cart/remove/' . $cartItem1->id)); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'data' => [ + 'id' => $cart->id, + 'customer_email' => $customer->email, + 'customer_first_name' => $customer->first_name, + 'customer_last_name' => $customer->last_name, + 'items' => [ + [ + 'id' => $cartItem2->id, + 'quantity' => $cartItem2->quantity, + 'product' => [ + 'id' => $product2->id, + ], + ], + ], + ], + ]); + + $I->assertEquals(1, \Webkul\Checkout\Facades\Cart::getCart()->items()->count()); + } + + public function testForEmptyCart(ApiTester $I) + { + $customer = $I->amSanctumAuthenticatedCustomer(); + + $product = $I->haveSimpleProduct(); + + $cart = $I->haveCart([ + 'customer_id' => $customer->id, + ]); + + $I->haveCartItems([ + 'cart_id' => $cart->id, + 'product_id' => $product->id, + ]); + + $I->assertEquals(1, \Webkul\Checkout\Facades\Cart::getCart()->items()->count()); + + $I->haveAllNecessaryHeaders(); + + $I->sendDelete($this->getVersionRoute('customer/cart/empty')); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'data' => null, + ]); + + $I->assertNull(\Webkul\Checkout\Facades\Cart::getCart()); + } + + public function testForMovingCartItemToWishlist(ApiTester $I) + { + $customer = $I->amSanctumAuthenticatedCustomer(); + + $cart = $I->haveCart([ + 'customer_id' => $customer->id, + ]); + + $product1 = $I->haveSimpleProduct(); + + $cartItem1 = $I->haveCartItems([ + 'cart_id' => $cart->id, + 'product_id' => $product1->id, + ]); + + $product2 = $I->haveSimpleProduct(); + + $cartItem2 = $I->haveCartItems([ + 'cart_id' => $cart->id, + 'product_id' => $product2->id, + ]); + + $I->assertEquals(2, \Webkul\Checkout\Facades\Cart::getCart()->items()->count()); + + $I->haveAllNecessaryHeaders(); + + $I->sendPost($this->getVersionRoute('customer/cart/move-to-wishlist/' . $cartItem1->id)); + + $I->seeAllNecessarySuccessResponse(); + + $I->seeResponseContainsJson([ + 'data' => [ + 'id' => $cart->id, + 'customer_email' => $customer->email, + 'customer_first_name' => $customer->first_name, + 'customer_last_name' => $customer->last_name, + 'items' => [ + [ + 'id' => $cartItem2->id, + 'quantity' => $cartItem2->quantity, + 'product' => [ + 'id' => $product2->id, + ], + ], + ], + ], + ]); + + $I->assertEquals(1, \Webkul\Checkout\Facades\Cart::getCart()->items()->count()); + + $I->assertCount(1, Wishlist::all()); + } + + public function testForApplyingInvalidCouponToTheCart(ApiTester $I) + { + $customer = $I->amSanctumAuthenticatedCustomer(); + + $product = $I->haveSimpleProduct(); + + $cart = $I->haveCart([ + 'customer_id' => $customer->id, + ]); + + $I->haveCartItems([ + 'cart_id' => $cart->id, + 'product_id' => $product->id, + ]); + + $I->assertEquals(1, \Webkul\Checkout\Facades\Cart::getCart()->items()->count()); + + $I->haveAllNecessaryHeaders(); + + $I->sendPost($this->getVersionRoute('customer/cart/coupon'), [ + 'code' => 'INVALID_CODE', + ]); + + $I->seeResponseCodeIs(400); + } +} diff --git a/tests/api/V1/Shop/Customer/CheckoutCest.php b/tests/api/V1/Shop/Customer/CheckoutCest.php new file mode 100644 index 000000000..0a1bf357a --- /dev/null +++ b/tests/api/V1/Shop/Customer/CheckoutCest.php @@ -0,0 +1,98 @@ +amSanctumAuthenticatedCustomer(); + + $token = $I->amCreatingTokenForSanctumAuthenticatedCustomer($customer); + + $I->haveAllNecessaryHeaders($token); + + $this->generateCartForCustomer($I, $customer); + + $this->saveAddress($I); + + $this->saveShippingMethod($I); + + $this->savePaymentMethod($I); + + $this->saveOrder($I); + } + + private function generateCartForCustomer(ApiTester $I, $customer) + { + $product = $I->haveSimpleProduct(); + + $cart = $I->haveCart([ + 'customer_id' => $customer->id, + ]); + + $cartItem = $I->haveCartItems([ + 'cart_id' => $cart->id, + 'product_id' => $product->id, + ]); + } + + private function saveAddress(ApiTester $I) + { + $fields = $I->cleanAllFields([ + 'first_name' => $I->fake()->firstName, + 'last_name' => $I->fake()->lastName, + 'email' => $I->fake()->safeEmail(), + 'address1' => [$I->fake()->streetAddress], + 'company_name' => $I->fake()->company, + 'country' => $I->fake()->countryCode, + 'state' => $I->fake()->word, + 'city' => $I->fake()->city, + 'postcode' => $I->fake()->postcode, + 'phone' => $I->fake()->phoneNumber, + ]); + + $I->sendPost($this->getVersionRoute('customer/checkout/save-address'), [ + 'billing' => array_merge($fields, ['use_for_shipping' => false]), + + 'shipping' => $fields, + ]); + + $I->seeAllNecessarySuccessResponse(); + } + + private function saveShippingMethod(ApiTester $I) + { + $I->haveHttpHeader('X-CSRF-TOKEN', csrf_token()); + + $I->sendPost($this->getVersionRoute('customer/checkout/save-shipping'), [ + 'shipping_method' => 'flatrate_flatrate', + ]); + + $I->seeAllNecessarySuccessResponse(); + } + + private function savePaymentMethod(ApiTester $I) + { + $I->haveHttpHeader('X-CSRF-TOKEN', csrf_token()); + + $I->sendPost($this->getVersionRoute('customer/checkout/save-payment'), [ + 'payment' => [ + 'method' => 'cashondelivery', + ], + ]); + + $I->seeAllNecessarySuccessResponse(); + } + + private function saveOrder(ApiTester $I) + { + $I->haveHttpHeader('X-CSRF-TOKEN', csrf_token()); + + $I->sendPost($this->getVersionRoute('customer/checkout/save-order')); + + $I->seeAllNecessarySuccessResponse(); + } +} diff --git a/tests/api/V1/Shop/Customer/CustomerCest.php b/tests/api/V1/Shop/Customer/CustomerCest.php new file mode 100644 index 000000000..fb0c6d084 --- /dev/null +++ b/tests/api/V1/Shop/Customer/CustomerCest.php @@ -0,0 +1,56 @@ +haveSimpleProduct(); + + $order = $I->have(OrderItem::class, ['product_id' => $product->id])->order; + + $I->have(OrderAddress::class, $this->generateAddressData($I, [ + 'order_id' => $order->id, + 'address_type' => OrderAddress::ADDRESS_TYPE_SHIPPING, + 'customer_id' => $order->customer->id, + ])); + + $I->have(OrderAddress::class, $this->generateAddressData($I, [ + 'order_id' => $order->id, + 'address_type' => OrderAddress::ADDRESS_TYPE_BILLING, + 'customer_id' => $order->customer->id, + ])); + + $I->have(OrderPayment::class, [ + 'method' => 'cashondelivery', + 'method_title' => null, + 'order_id' => $order->id, + ]); + + return $order; + } + + protected function generateAddressData(ApiTester $I, array $additionalData): array + { + $faker = $I->fake(); + + return array_merge([ + 'city' => $faker->city, + 'company_name' => $faker->company, + 'country' => $faker->countryCode, + 'email' => $faker->email, + 'first_name' => $faker->firstName, + 'last_name' => $faker->lastName, + 'phone' => $faker->phoneNumber, + 'postcode' => $faker->postcode, + 'state' => $faker->state, + ], $additionalData); + } +} diff --git a/tests/api/V1/Shop/Customer/InvoiceCest.php b/tests/api/V1/Shop/Customer/InvoiceCest.php new file mode 100644 index 000000000..dc1afd6fe --- /dev/null +++ b/tests/api/V1/Shop/Customer/InvoiceCest.php @@ -0,0 +1,26 @@ +generateCashOnDeliveryOrder($I); + + $invoices = $I->have(Invoice::class, [ + 'order_id' => $order->id, + ]); + + $token = $I->amCreatingTokenForSanctumAuthenticatedCustomer($order->customer); + + $I->haveAllNecessaryHeaders($token); + + $I->sendGet($this->getVersionRoute('customer/invoices')); + + $I->seeAllNecessarySuccessResponse(); + } +} diff --git a/tests/api/V1/Shop/Customer/OrderCest.php b/tests/api/V1/Shop/Customer/OrderCest.php new file mode 100644 index 000000000..36a558ece --- /dev/null +++ b/tests/api/V1/Shop/Customer/OrderCest.php @@ -0,0 +1,21 @@ +generateCashOnDeliveryOrder($I); + + $token = $I->amCreatingTokenForSanctumAuthenticatedCustomer($order->customer); + + $I->haveAllNecessaryHeaders($token); + + $I->sendGet($this->getVersionRoute('customer/orders')); + + $I->seeAllNecessarySuccessResponse(); + } +} diff --git a/tests/api/V1/Shop/Customer/ShipmentCest.php b/tests/api/V1/Shop/Customer/ShipmentCest.php new file mode 100644 index 000000000..8e2516f87 --- /dev/null +++ b/tests/api/V1/Shop/Customer/ShipmentCest.php @@ -0,0 +1,24 @@ +generateCashOnDeliveryOrder($I); + + $shipments = $I->have(Shipment::class); + + $token = $I->amCreatingTokenForSanctumAuthenticatedCustomer($order->customer); + + $I->haveAllNecessaryHeaders($token); + + $I->sendGet($this->getVersionRoute('customer/shipments')); + + $I->seeAllNecessarySuccessResponse(); + } +} diff --git a/tests/api/V1/Shop/Customer/WishlistCest.php b/tests/api/V1/Shop/Customer/WishlistCest.php new file mode 100644 index 000000000..ffa4fad4a --- /dev/null +++ b/tests/api/V1/Shop/Customer/WishlistCest.php @@ -0,0 +1,26 @@ +amSanctumAuthenticatedCustomer(); + + $product = $I->haveSimpleProduct(); + + $wishlist = $I->have(Wishlist::class, [ + 'channel_id' => core()->getCurrentChannel()->id, + 'customer_id' => $customer->id, + 'product_id' => $product->id, + ]); + + $I->sendGet($this->getVersionRoute('customer/wishlist')); + + $I->seeAllNecessarySuccessResponse(); + } +} diff --git a/tests/functional.suite.yml b/tests/functional.suite.yml index 9c3c8c557..44d424012 100644 --- a/tests/functional.suite.yml +++ b/tests/functional.suite.yml @@ -1,14 +1,6 @@ -# Codeception Test Suite Configuration -# -# Suite for functional tests -# Emulate web requests and make application process them -# Include one of framework modules (Symfony2, Yii2, Laravel5) to use it -# Remove this suite if you don't use frameworks - actor: FunctionalTester modules: enabled: - # add a framework module here - \Helper\Functional - \Helper\DataMocker - Asserts @@ -20,4 +12,4 @@ modules: run_database_seeder: true database_seeder_class: DatabaseSeeder - step_decorators: ~ \ No newline at end of file + step_decorators: ~ diff --git a/tests/trigger.suite.yml b/tests/trigger.suite.yml index 77d44fee3..d3298c674 100644 --- a/tests/trigger.suite.yml +++ b/tests/trigger.suite.yml @@ -1,7 +1,3 @@ -# Codeception Test Suite Configuration -# -# Suite for unit or integration tests that test database logic (e.g. triggers). - actor: TriggerTester modules: enabled: @@ -15,4 +11,4 @@ modules: database_seeder_class: DatabaseSeeder packages: packages - step_decorators: ~ \ No newline at end of file + step_decorators: ~ diff --git a/tests/unit.suite.yml b/tests/unit.suite.yml index cab8a5bc2..7bd176827 100644 --- a/tests/unit.suite.yml +++ b/tests/unit.suite.yml @@ -1,7 +1,3 @@ -# Codeception Test Suite Configuration -# -# Suite for unit or integration tests. - actor: UnitTester modules: enabled: @@ -16,4 +12,4 @@ modules: database_seeder_class: DatabaseSeeder packages: packages - step_decorators: ~ \ No newline at end of file + step_decorators: ~