From 80acf7617eecbb65df45e3a4f53e1377a4bb7adc Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 10:15:05 +0200 Subject: [PATCH 01/20] Added tools to generate guest JWTs --- .../JWTGuestOrderAuthenticator.php | 72 +++++++++++++++++++ src/Encoder/GuestOrderJWTEncoder.php | 41 +++++++++++ src/Encoder/GuestOrderJWTEncoderInterface.php | 14 ++++ src/Provider/GuestUserProvider.php | 45 ++++++++++++ .../config/services/authenticator.xml | 10 +++ src/Resources/config/services/encoder.xml | 13 ++++ src/Resources/config/services/providers.xml | 5 ++ .../CustomerGuestAuthenticationInterface.php | 16 +++++ .../CustomerGuestAuthenticationTrait.php | 28 ++++++++ 9 files changed, 244 insertions(+) create mode 100644 src/Authenticator/JWTGuestOrderAuthenticator.php create mode 100644 src/Encoder/GuestOrderJWTEncoder.php create mode 100644 src/Encoder/GuestOrderJWTEncoderInterface.php create mode 100644 src/Provider/GuestUserProvider.php create mode 100644 src/Resources/config/services/authenticator.xml create mode 100644 src/Resources/config/services/encoder.xml create mode 100644 src/Traits/CustomerGuestAuthenticationInterface.php create mode 100644 src/Traits/CustomerGuestAuthenticationTrait.php diff --git a/src/Authenticator/JWTGuestOrderAuthenticator.php b/src/Authenticator/JWTGuestOrderAuthenticator.php new file mode 100644 index 000000000..3c62038c7 --- /dev/null +++ b/src/Authenticator/JWTGuestOrderAuthenticator.php @@ -0,0 +1,72 @@ +headers->has(self::TOKEN_HEADER); + } + + public function getCredentials(Request $request): string + { + return $request->headers->get(self::TOKEN_HEADER); + } + + public function getUser($credentials, UserProviderInterface $userProvider): UserInterface + { + try { + return $userProvider->loadUserByUsername($credentials); + } catch (JWTDecodeFailureException $decodeFailureException) { + throw new AuthenticationException($decodeFailureException->getMessage()); + } + } + + public function checkCredentials($credentials, UserInterface $user): bool + { + return true; + } + + public function onAuthenticationFailure(Request $request, AuthenticationException $exception): Response + { + return new JsonResponse(['message' => $exception->getMessage()], Response::HTTP_UNAUTHORIZED); + } + + public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey): ?Response + { + // The request continues + return null; + } + + public function supportsRememberMe(): bool + { + return false; + } + + public function start(Request $request, AuthenticationException $authException = null): Response + { + return new JsonResponse(['message' => 'Authentication required'], Response::HTTP_UNAUTHORIZED); + } + + public function createAuthenticatedToken(UserInterface $user, $providerKey): GuardTokenInterface + { + return new PostAuthenticationGuardToken($user, $providerKey, []); + } +} diff --git a/src/Encoder/GuestOrderJWTEncoder.php b/src/Encoder/GuestOrderJWTEncoder.php new file mode 100644 index 000000000..b27ed1462 --- /dev/null +++ b/src/Encoder/GuestOrderJWTEncoder.php @@ -0,0 +1,41 @@ +JWTEncoder = $JWTEncoder; + $this->orderRepository = $orderRepository; + } + + public function encode(OrderInterface $order): string + { + $data = ['orderToken' => $order->getTokenValue()]; + + return $this->JWTEncoder->encode($data); + } + + public function decode(string $jwt): OrderInterface + { + $data = $this->JWTEncoder->decode($jwt); + + /** @var OrderInterface $order */ + $order = $this->orderRepository->findOneByTokenValue($data['orderToken']); + + return $order; + } +} diff --git a/src/Encoder/GuestOrderJWTEncoderInterface.php b/src/Encoder/GuestOrderJWTEncoderInterface.php new file mode 100644 index 000000000..6b2ad7df0 --- /dev/null +++ b/src/Encoder/GuestOrderJWTEncoderInterface.php @@ -0,0 +1,14 @@ +encoder = $encoder; + } + + public function loadUserByUsername($jwt): UserInterface + { + $order = $this->encoder->decode($jwt); + + /** @var CustomerGuestAuthenticationInterface $customer */ + $customer = $order->getCustomer(); + Assert::implementsInterface($customer, CustomerGuestAuthenticationInterface::class); + + $customer->setAuthorizedOrder($order); + + return $customer; + } + + public function refreshUser(UserInterface $user) + { + } + + public function supportsClass($class): bool + { + return (new ReflectionClass($class))->implementsInterface(CustomerGuestAuthenticationInterface::class); + } +} diff --git a/src/Resources/config/services/authenticator.xml b/src/Resources/config/services/authenticator.xml new file mode 100644 index 000000000..ee89397f9 --- /dev/null +++ b/src/Resources/config/services/authenticator.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/Resources/config/services/encoder.xml b/src/Resources/config/services/encoder.xml new file mode 100644 index 000000000..243890543 --- /dev/null +++ b/src/Resources/config/services/encoder.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/src/Resources/config/services/providers.xml b/src/Resources/config/services/providers.xml index 82a87f51e..f086df420 100644 --- a/src/Resources/config/services/providers.xml +++ b/src/Resources/config/services/providers.xml @@ -23,5 +23,10 @@ + + + + diff --git a/src/Traits/CustomerGuestAuthenticationInterface.php b/src/Traits/CustomerGuestAuthenticationInterface.php new file mode 100644 index 000000000..579de660a --- /dev/null +++ b/src/Traits/CustomerGuestAuthenticationInterface.php @@ -0,0 +1,16 @@ +authorizedOrder; + } + + public function setAuthorizedOrder(OrderInterface $authorizedOrder): void + { + $this->authorizedOrder = $authorizedOrder; + } +} From ad943f303af4ce765e6253f91e391b3bfd179454 Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 10:42:25 +0200 Subject: [PATCH 02/20] Added guest order summary action --- .../Order/ShowGuestOrderDetailsAction.php | 53 +++++++++++++++++++ src/Resources/config/routing/order.yml | 6 +++ .../config/services/actions/order.xml | 7 +++ 3 files changed, 66 insertions(+) create mode 100644 src/Controller/Order/ShowGuestOrderDetailsAction.php diff --git a/src/Controller/Order/ShowGuestOrderDetailsAction.php b/src/Controller/Order/ShowGuestOrderDetailsAction.php new file mode 100644 index 000000000..98b1308dc --- /dev/null +++ b/src/Controller/Order/ShowGuestOrderDetailsAction.php @@ -0,0 +1,53 @@ +viewHandler = $viewHandler; + $this->tokenStorage = $tokenStorage; + } + + public function __invoke(Request $request): Response + { + try { + $token = $this->tokenStorage->getToken(); + + Assert::notNull($token); + + /** @var CustomerGuestAuthenticationInterface|CustomerInterface $customer */ + $customer = $token->getUser(); + + Assert::isInstanceOf($customer, CustomerGuestAuthenticationInterface::class); + Assert::null($customer->getUser()); + + $order = $customer->getAuthorizedOrder(); + } catch (\InvalidArgumentException $exception) { + return $this->viewHandler->handle(View::create(null, Response::HTTP_UNAUTHORIZED)); + } + + return $this->viewHandler->handle(View::create($order, Response::HTTP_OK)); + } +} diff --git a/src/Resources/config/routing/order.yml b/src/Resources/config/routing/order.yml index fa2215128..7e613e5c0 100644 --- a/src/Resources/config/routing/order.yml +++ b/src/Resources/config/routing/order.yml @@ -9,3 +9,9 @@ sylius_shop_api_order_details: methods: [GET] defaults: _controller: sylius.shop_api_plugin.controller.order.show_order_details_action + +sylius_shop_api_guest_order_details: + path: /guest/order + methods: [GET] + defaults: + _controller: sylius.shop_api_plugin.controller.order.show_guest_order_details_action diff --git a/src/Resources/config/services/actions/order.xml b/src/Resources/config/services/actions/order.xml index e0d38092c..99a20b498 100644 --- a/src/Resources/config/services/actions/order.xml +++ b/src/Resources/config/services/actions/order.xml @@ -19,5 +19,12 @@ + + + + + From 0fd3fd173a8844ca84a8c55d26bbbff4b26ef93b Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 11:05:39 +0200 Subject: [PATCH 03/20] Added guest login & firewall config --- src/Controller/Customer/GuestLoginAction.php | 105 ++++++++++++++++++ src/Request/Customer/GuestLoginRequest.php | 47 ++++++++ .../validation/customer/GuestLoginRequest.xml | 20 ++++ .../Application/config/packages/security.yaml | 23 ++++ tests/Application/config/routes.yaml | 6 + 5 files changed, 201 insertions(+) create mode 100644 src/Controller/Customer/GuestLoginAction.php create mode 100644 src/Request/Customer/GuestLoginRequest.php create mode 100644 src/Resources/config/validation/customer/GuestLoginRequest.xml diff --git a/src/Controller/Customer/GuestLoginAction.php b/src/Controller/Customer/GuestLoginAction.php new file mode 100644 index 000000000..6bac3e56f --- /dev/null +++ b/src/Controller/Customer/GuestLoginAction.php @@ -0,0 +1,105 @@ +validator = $validator; + $this->validationErrorViewFactory = $validationErrorViewFactory; + $this->viewHandler = $viewHandler; + $this->orderRepository = $orderRepository; + $this->guestOrderJWTEncoder = $guestOrderJWTEncoder; + } + + public function __invoke(Request $request): Response + { + // This is just to validate that all necessary fields are present. + $loginRequest = new GuestLoginRequest($request); + $validationErrors = $this->validator->validate($loginRequest); + if (0 < count($validationErrors)) { + return $this->viewHandler->handle( + View::create( + $this->validationErrorViewFactory->create($validationErrors), + Response::HTTP_BAD_REQUEST + ) + ); + } + + // Actual login logic + $success = false; + + /** @var OrderInterface $order */ + $order = $this->orderRepository->findOneByNumber($loginRequest->getOrderNumber()); + + // The order has to exist and must be placed + if (null !== $order && $order->getCheckoutState() !== OrderCheckoutStates::STATE_CART) { + /** @var CustomerInterface $customer */ + $customer = $order->getCustomer(); + $paymentMethod = $order->getLastPayment()->getMethod(); + + // The order must be a guest order. Also the provided email & payment method must match. + if ( + null === $customer->getUser() && + $loginRequest->getEmail() === $customer->getEmail() && + $paymentMethod->getCode() === $loginRequest->getPaymentMethodCode() + ) { + $success = true; + } + } + + // Return the jwt on success + if (true === $success) { + $jwt = $this->guestOrderJWTEncoder->encode($order); + + return $this->viewHandler->handle(View::create(['jwt' => $jwt], Response::HTTP_OK)); + } + + return $this->viewHandler->handle(View::create(['message' => 'Bad credentials.'], Response::HTTP_UNAUTHORIZED)); + } +} diff --git a/src/Request/Customer/GuestLoginRequest.php b/src/Request/Customer/GuestLoginRequest.php new file mode 100644 index 000000000..487b0652b --- /dev/null +++ b/src/Request/Customer/GuestLoginRequest.php @@ -0,0 +1,47 @@ +email = $request->request->get('email'); + $this->orderNumber = $request->request->get('orderNumber'); + $this->paymentMethodCode = $request->request->get('paymentMethod'); + } + + public function getEmail(): string + { + return $this->email; + } + + public function getOrderNumber(): string + { + return $this->orderNumber; + } + + public function getPaymentMethodCode(): string + { + return $this->paymentMethodCode; + } +} diff --git a/src/Resources/config/validation/customer/GuestLoginRequest.xml b/src/Resources/config/validation/customer/GuestLoginRequest.xml new file mode 100644 index 000000000..429867391 --- /dev/null +++ b/src/Resources/config/validation/customer/GuestLoginRequest.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/tests/Application/config/packages/security.yaml b/tests/Application/config/packages/security.yaml index ac16053ca..11fb99ea5 100644 --- a/tests/Application/config/packages/security.yaml +++ b/tests/Application/config/packages/security.yaml @@ -10,6 +10,8 @@ security: id: sylius.admin_user_provider.email_or_name_based sylius_shop_user_provider: id: sylius.shop_user_provider.email_or_name_based + sylius_guest_user_provider: + id: sylius.shop_api_plugin.provider.guest_user_provider encoders: Sylius\Component\User\Model\UserInterface: sha512 firewalls: @@ -51,6 +53,18 @@ security: stateless: true anonymous: true + shop_api_guest_login: + pattern: "%shop_api.security.regex%/login/guest" + stateless: true + anonymous: true + form_login: + provider: sylius_guest_user_provider + login_path: sylius_shop_api_guest_login_check + check_path: sylius_shop_api_guest_login_check + success_handler: sylius.shop_api_plugin.handler.authentication_success_handler + failure_handler: lexik_jwt_authentication.handler.authentication_failure + require_previous_session: false + sylius_shop_api_login: pattern: "%shop_api.security.regex%/login" stateless: true @@ -63,6 +77,15 @@ security: failure_handler: lexik_jwt_authentication.handler.authentication_failure require_previous_session: false + shop_api_guest: + pattern: "%shop_api.security.regex%/[0-9a-zA-Z]+/guest" + stateless: true + anonymous: true + guard: + athenticators: + - sylius.shop_api_plugin.authenticator.jwtguest_order_authenticator + provider: sylius_guest_user_provider + shop_api: pattern: "%shop_api.security.regex%" stateless: true diff --git a/tests/Application/config/routes.yaml b/tests/Application/config/routes.yaml index 9645b82d5..15194d571 100644 --- a/tests/Application/config/routes.yaml +++ b/tests/Application/config/routes.yaml @@ -9,3 +9,9 @@ sylius_shop_api: sylius_shop_api_login_check: methods: [POST] path: /shop-api/login_check + +sylius_shop_api_guest_login_check: + methods: [POST] + path: /shop-api/guest/login_check + defaults: + _controller: From 162513309e6b567f93d60d014467b625536ec3bc Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 11:11:43 +0200 Subject: [PATCH 04/20] Added missing methods to guest customer trait & updated test config --- .../CustomerGuestAuthenticationTrait.php | 35 +++++++++++++++++++ .../Application/config/packages/_sylius.yaml | 6 ++++ tests/Application/src/Entity/Customer.php | 15 ++++++++ 3 files changed, 56 insertions(+) create mode 100644 tests/Application/src/Entity/Customer.php diff --git a/src/Traits/CustomerGuestAuthenticationTrait.php b/src/Traits/CustomerGuestAuthenticationTrait.php index 086c52860..2352de8d2 100644 --- a/src/Traits/CustomerGuestAuthenticationTrait.php +++ b/src/Traits/CustomerGuestAuthenticationTrait.php @@ -5,6 +5,7 @@ namespace Sylius\ShopApiPlugin\Traits; +use Ramsey\Uuid\Uuid; use Sylius\Component\Core\Model\OrderInterface; trait CustomerGuestAuthenticationTrait @@ -25,4 +26,38 @@ public function setAuthorizedOrder(OrderInterface $authorizedOrder): void { $this->authorizedOrder = $authorizedOrder; } + + /* + * The following methods are required by the UserInterface, which we need to be able to allow a guest login + */ + + /** {@inheritdoc} */ + public function getRoles() + { + return []; + } + + /** {@inheritdoc} */ + public function getPassword() + { + return ''; + } + + /** {@inheritdoc} */ + public function getSalt() + { + return null; + } + + /** {@inheritdoc} */ + public function getUsername() + { + // Generate a unique temporary username + return sprintf('guest_%s_%s', str_replace('@', '(at)', $this->email), Uuid::uuid4()->toString()); + } + + /** {@inheritdoc} */ + public function eraseCredentials() + { + } } diff --git a/tests/Application/config/packages/_sylius.yaml b/tests/Application/config/packages/_sylius.yaml index f6dd8d4e8..d75662805 100644 --- a/tests/Application/config/packages/_sylius.yaml +++ b/tests/Application/config/packages/_sylius.yaml @@ -15,3 +15,9 @@ parameters: sylius_shop: product_grid: include_all_descendants: true + +sylius_customer: + resources: + customer: + classes: + model: 'Tests\Sylius\ShopApiPlugin\Application\src\Entity\Customer' diff --git a/tests/Application/src/Entity/Customer.php b/tests/Application/src/Entity/Customer.php new file mode 100644 index 000000000..c5b9439be --- /dev/null +++ b/tests/Application/src/Entity/Customer.php @@ -0,0 +1,15 @@ + Date: Thu, 4 Jul 2019 11:26:50 +0200 Subject: [PATCH 05/20] Added tests --- .../Controller/Customer/GuestLoginApiTest.php | 67 ++++++++++++++++++ .../Order/GuestOrderShowApiTest.php | 61 +++++++++++++++++ tests/DataFixtures/ORM/address.yml | 10 +++ tests/DataFixtures/ORM/customer.yml | 4 ++ tests/DataFixtures/ORM/order.yml | 68 +++++++++++++++++++ .../customer/guest_login_response.json | 3 + .../order/guest_order_summary_response.json | 58 ++++++++++++++++ 7 files changed, 271 insertions(+) create mode 100644 tests/Controller/Customer/GuestLoginApiTest.php create mode 100644 tests/Controller/Order/GuestOrderShowApiTest.php create mode 100644 tests/DataFixtures/ORM/order.yml create mode 100644 tests/Responses/Expected/customer/guest_login_response.json create mode 100644 tests/Responses/Expected/order/guest_order_summary_response.json diff --git a/tests/Controller/Customer/GuestLoginApiTest.php b/tests/Controller/Customer/GuestLoginApiTest.php new file mode 100644 index 000000000..8a609dfc4 --- /dev/null +++ b/tests/Controller/Customer/GuestLoginApiTest.php @@ -0,0 +1,67 @@ +loadFixturesFromFiles(['order.yml', 'shop.yml', 'customer.yml', 'address.yml']); + + $data = <<client->request(Request::METHOD_POST, '/shop-api/WEB_GB/guest/login_check', [], [], self::CONTENT_TYPE_HEADER, $data); + $response = $this->client->getResponse(); + $this->assertResponse($response, 'customer/guest_login_response'); + } + + /** @test */ + public function it_returns_unauthorized_on_wrong_payment_method(): void + { + $this->loadFixturesFromFiles(['order.yml', 'shop.yml', 'customer.yml', 'address.yml']); + + $data = <<client->request(Request::METHOD_POST, '/shop-api/WEB_GB/guest/login_check', [], [], self::CONTENT_TYPE_HEADER, $data); + $response = $this->client->getResponse(); + $this->assertResponseCode($response, Response::HTTP_UNAUTHORIZED); + } + + /** @test */ + public function it_returns_unauthorized_if_order_belongs_to_user(): void + { + $this->loadFixturesFromFiles(['order.yml', 'shop.yml', 'customer.yml', 'address.yml']); + + $data = <<client->request(Request::METHOD_POST, '/shop-api/WEB_GB/guest/login_check', [], [], self::CONTENT_TYPE_HEADER, $data); + $response = $this->client->getResponse(); + $this->assertResponseCode($response, Response::HTTP_UNAUTHORIZED); + } +} diff --git a/tests/Controller/Order/GuestOrderShowApiTest.php b/tests/Controller/Order/GuestOrderShowApiTest.php new file mode 100644 index 000000000..d38cd5b7e --- /dev/null +++ b/tests/Controller/Order/GuestOrderShowApiTest.php @@ -0,0 +1,61 @@ +loadFixturesFromFiles(['order.yml', 'shop.yml', 'customer.yml', 'address.yml']); + + /** @var GuestOrderJWTEncoderInterface $encoder */ + $encoder = $this->get('brille24.shop_api.encoder.guest_order_jwtencoder'); + + /** @var OrderRepositoryInterface $orderRepository */ + $orderRepository = $this->get('sylius.repository.order'); + + $token = 'GUEST_ORDER_TOKEN'; + $order = $orderRepository->findOneByTokenValue($token); + $jwt = $encoder->encode($order); + + $this->client->setServerParameter(self::GUEST_TOKEN_HEADER, $jwt); + $this->client->request(Request::METHOD_GET, '/shop-api/WEB_GB/guest/order'); + $response = $this->client->getResponse(); + $this->assertResponse($response, 'order/guest_order_summary_response'); + } + + /** @test */ + public function it_returns_unauthorized_if_no_jwt_provided(): void + { + $this->loadFixturesFromFiles(['order.yml', 'shop.yml', 'customer.yml', 'address.yml']); + + $this->client->request(Request::METHOD_GET, '/shop-api/WEB_GB/guest/order'); + $response = $this->client->getResponse(); + $this->assertResponseCode($response, Response::HTTP_UNAUTHORIZED); + } + + /** @test */ + public function it_returns_unauthorized_if_invalid_jwt_provided(): void + { + $this->loadFixturesFromFiles(['order.yml', 'shop.yml', 'customer.yml', 'address.yml']); + + $jwt = 'abc'; + + $this->client->setServerParameter(self::GUEST_TOKEN_HEADER, $jwt); + $this->client->request(Request::METHOD_GET, '/shop-api/WEB_GB/guest/order'); + $response = $this->client->getResponse(); + $this->assertResponseCode($response, Response::HTTP_UNAUTHORIZED); + } +} diff --git a/tests/DataFixtures/ORM/address.yml b/tests/DataFixtures/ORM/address.yml index 33d73bd8f..3e3384a40 100644 --- a/tests/DataFixtures/ORM/address.yml +++ b/tests/DataFixtures/ORM/address.yml @@ -43,3 +43,13 @@ Sylius\Component\Core\Model\Address: city: "Split" postcode: "21000" customer: "@hater" + customer_guest_address: + firstName: "John" + lastName: "Doe" + phoneNumber: 0912539021 + countryCode: "GB" + provinceCode: "GB-SCT" + street: "Example str. 123" + city: "London" + postcode: "21000" + customer: "@guest" diff --git a/tests/DataFixtures/ORM/customer.yml b/tests/DataFixtures/ORM/customer.yml index ffce3fa78..f80e6389f 100644 --- a/tests/DataFixtures/ORM/customer.yml +++ b/tests/DataFixtures/ORM/customer.yml @@ -29,3 +29,7 @@ Sylius\Component\Core\Model\Customer: lastName: "Wilson" email: "hater@queen.com" emailCanonical: "slade@queen.com" + + guest: + email: "john@doe.com" + emailCanonical: "john@doe.com" diff --git a/tests/DataFixtures/ORM/order.yml b/tests/DataFixtures/ORM/order.yml new file mode 100644 index 000000000..68fd6e1b2 --- /dev/null +++ b/tests/DataFixtures/ORM/order.yml @@ -0,0 +1,68 @@ +Sylius\Compontent\Core\Model\Order: + olivers_order: + number: "00000022" + state: "new" + customer: "@customer_oliver" + channel: "@gb_web_channel" + shippingAddress: "@customer_oliver_home_address" + billingAddress: "@customer_oliver_home_address" + currencyCode: "GBP" + localeCode: "en_GB" + checkoutState: "completed" + paymentState: "awaiting_payment" + shippingState: "ready" + tokenValue: "ORDER_TOKEN" + items: ["@olivers_order_item"] + __calls: + - addPayment: ["@olivers_payment"] + + guest_order: + channel: "@gb_web_channel" + number: "00000078" + state: "new" + customer: "@guest" + shippingAddress: "@customer_guest_address" + billingAddress: "@customer_guest_address" + currencyCode: "GBP" + localeCode: "en_GB" + checkoutState: "completed" + paymentState: "awaiting_payment" + shippingState: "ready" + tokenValue: "GUEST_ORDER_TOKEN" + checkoutCompletedAt: "" + __calls: + - addPayment: ["@guest_payment"] + +Sylius\Component\Core\Model\OrderItem: + olivers_order_item: + order: "@olivers_order" + unitPrice: 1999 + variant: "@mug_variant" + productName: "Logan Mug" + variantName: "Logan Mug" + +Sylius\Component\Core\Model\OrderItemUnit: + olivers_glasses_order_item_unit: + __construct: ["@olivers_order_item"] + +Sylius\Component\Core\Model\Payment: + olivers_payment: + order: "@olivers_order" + method: "@bank_payment" + currencyCode: "GBP" + amount: 1999 + state: "new" + guest_payment: + order: "@guest_order" + method: "@bank_payment" + currencyCode: "GBP" + amount: 1000 + state: "new" + +Sylius\Component\Core\Model\PaymentMethod: + bank_payment: + channels: ["@gb_web_channel"] + code: "bank_payment" + environment: "test" + currentLocale: "en_GB" + name: "Bank Payment" diff --git a/tests/Responses/Expected/customer/guest_login_response.json b/tests/Responses/Expected/customer/guest_login_response.json new file mode 100644 index 000000000..661b030c8 --- /dev/null +++ b/tests/Responses/Expected/customer/guest_login_response.json @@ -0,0 +1,3 @@ +{ + "jwt": @string@ +} diff --git a/tests/Responses/Expected/order/guest_order_summary_response.json b/tests/Responses/Expected/order/guest_order_summary_response.json new file mode 100644 index 000000000..ade0f77e7 --- /dev/null +++ b/tests/Responses/Expected/order/guest_order_summary_response.json @@ -0,0 +1,58 @@ +{ + "channel": "WEB_GB", + "currency": "GBP", + "locale": "en_GB", + "checkoutState": "completed", + "checkoutCompletedAt": @string@, + "items": [], + "totals": { + "total": 0, + "items": 0, + "taxes": 0, + "shipping": 0, + "promotion": 0 + }, + "shippingAddress": { + "firstName": "John", + "lastName": "Doe", + "countryCode": "GB", + "street": "Vukovarska", + "city": "Split", + "postcode": "21000", + "company": "Separovic d.o.o", + "phoneNumber": "349713", + "streetNumber": "456" + }, + "billingAddress": { + "firstName": "John", + "lastName": "Doe", + "countryCode": "GB", + "street": "Vukovarska", + "city": "Split", + "postcode": "21000", + "company": "Separovic d.o.o", + "phoneNumber": "349713", + "streetNumber": "456" + }, + "payments": [ + { + "state": "new", + "method": { + "code": "bank_payment", + "name": "Bank Payment", + "description": @string@, + "instructions": @string@ + }, + "price": { + "current": 1000, + "currency": "GBP" + }, + "details": [] + } + ], + "shipments": [], + "cartDiscounts": [], + "tokenValue": "GUEST_ORDER_TOKEN", + "number": "00000078", + "orderDate": @string@ +} From e7b21503b6d00ae5a5da65a2b8c8652b8ed57856 Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 11:48:31 +0200 Subject: [PATCH 06/20] Fixed typo in test config --- tests/Application/config/packages/security.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Application/config/packages/security.yaml b/tests/Application/config/packages/security.yaml index 11fb99ea5..054ed1c08 100644 --- a/tests/Application/config/packages/security.yaml +++ b/tests/Application/config/packages/security.yaml @@ -82,9 +82,9 @@ security: stateless: true anonymous: true guard: - athenticators: + provider: sylius_guest_user_provider + authenticators: - sylius.shop_api_plugin.authenticator.jwtguest_order_authenticator - provider: sylius_guest_user_provider shop_api: pattern: "%shop_api.security.regex%" From eeb75d782b5d7b0429fc2f29ba17bfdb5c6d7dcd Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 11:51:14 +0200 Subject: [PATCH 07/20] Fixed service configuration --- src/Resources/config/services.xml | 2 ++ tests/Application/config/packages/security.yaml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index 6878ed5a1..b77092696 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -13,7 +13,9 @@ + + diff --git a/tests/Application/config/packages/security.yaml b/tests/Application/config/packages/security.yaml index 054ed1c08..f6acf035c 100644 --- a/tests/Application/config/packages/security.yaml +++ b/tests/Application/config/packages/security.yaml @@ -61,7 +61,7 @@ security: provider: sylius_guest_user_provider login_path: sylius_shop_api_guest_login_check check_path: sylius_shop_api_guest_login_check - success_handler: sylius.shop_api_plugin.handler.authentication_success_handler + success_handler: lexik_jwt_authentication.handler.authentication_success failure_handler: lexik_jwt_authentication.handler.authentication_failure require_previous_session: false From 0dac9c685ae87746bcfc232842f25f1897295e5e Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 12:08:03 +0200 Subject: [PATCH 08/20] Fixing test config --- tests/Application/config/packages/doctrine.yaml | 10 ++++++++++ .../src/Resources/config/doctrine/Customer.orm.xml | 4 ++++ 2 files changed, 14 insertions(+) create mode 100644 tests/Application/src/Resources/config/doctrine/Customer.orm.xml diff --git a/tests/Application/config/packages/doctrine.yaml b/tests/Application/config/packages/doctrine.yaml index f51ba5a22..41ee20f5a 100644 --- a/tests/Application/config/packages/doctrine.yaml +++ b/tests/Application/config/packages/doctrine.yaml @@ -12,3 +12,13 @@ doctrine: charset: UTF8 url: '%env(resolve:DATABASE_URL)%' + + orm: + entity_managers: + default: + mappings: + custom_mapping: + type: 'xml' + prefix: 'Tests\Sylius\ShopApiPlugin\Application\src\Entity' + dir: '%kernel.root_dir%/src/Resources/config/doctrine' + is_bundle: false diff --git a/tests/Application/src/Resources/config/doctrine/Customer.orm.xml b/tests/Application/src/Resources/config/doctrine/Customer.orm.xml new file mode 100644 index 000000000..664d595a7 --- /dev/null +++ b/tests/Application/src/Resources/config/doctrine/Customer.orm.xml @@ -0,0 +1,4 @@ + + + + From faec2edea4f052e9cd541f5c58bc74811c5f45ed Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 12:14:56 +0200 Subject: [PATCH 09/20] Made customer entity not final --- tests/Application/src/Entity/Customer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Application/src/Entity/Customer.php b/tests/Application/src/Entity/Customer.php index c5b9439be..47a9efdd9 100644 --- a/tests/Application/src/Entity/Customer.php +++ b/tests/Application/src/Entity/Customer.php @@ -9,7 +9,7 @@ use Sylius\ShopApiPlugin\Traits\CustomerGuestAuthenticationTrait; use Sylius\Component\Core\Model\Customer as BaseCustomer; -final class Customer extends BaseCustomer implements CustomerGuestAuthenticationInterface +class Customer extends BaseCustomer implements CustomerGuestAuthenticationInterface { use CustomerGuestAuthenticationTrait; } From 12a85c7b1802f74bc131a081f09422f1279793d9 Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 12:29:31 +0200 Subject: [PATCH 10/20] Changed customer data fixture class --- tests/DataFixtures/ORM/customer.yml | 2 +- tests/DataFixtures/ORM/order.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/DataFixtures/ORM/customer.yml b/tests/DataFixtures/ORM/customer.yml index f80e6389f..d9810052d 100644 --- a/tests/DataFixtures/ORM/customer.yml +++ b/tests/DataFixtures/ORM/customer.yml @@ -15,7 +15,7 @@ Sylius\Component\Core\Model\ShopUser: username: "hater@queen.com" usernameCanonical: "hater@queen.com" -Sylius\Component\Core\Model\Customer: +Tests\Sylius\ShopApiPlugin\Application\src\Entity\Customer: customer_oliver: firstName: "Oliver" lastName: "Queen" diff --git a/tests/DataFixtures/ORM/order.yml b/tests/DataFixtures/ORM/order.yml index 68fd6e1b2..068d31ee8 100644 --- a/tests/DataFixtures/ORM/order.yml +++ b/tests/DataFixtures/ORM/order.yml @@ -1,4 +1,4 @@ -Sylius\Compontent\Core\Model\Order: +Sylius\Component\Core\Model\Order: olivers_order: number: "00000022" state: "new" From c2383b6316858355ce7ad2ace38808c1ea51f1cb Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 14:08:32 +0200 Subject: [PATCH 11/20] Trying to fix the fixtures --- tests/DataFixtures/ORM/shop.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/DataFixtures/ORM/shop.yml b/tests/DataFixtures/ORM/shop.yml index 8299b715e..449f46d10 100644 --- a/tests/DataFixtures/ORM/shop.yml +++ b/tests/DataFixtures/ORM/shop.yml @@ -44,11 +44,7 @@ Sylius\Component\Core\Model\Product: images: ["@mug_thumbnail"] mainTaxon: "@mug_taxon" productTaxons: ["@mug_product_taxon"] - attributes: - - "@en_gb_mug_holiday_collection_value" - - "@de_de_mug_holiday_collection_value" - - "@en_gb_mug_holiday_material_value" - - "@de_de_mug_holiday_material_value" + attributes: ["@en_gb_mug_holiday_collection_value", "@de_de_mug_holiday_collection_value", "@en_gb_mug_holiday_material_value", "@de_de_mug_holiday_material_value"] t_shirt: code: "LOGAN_T_SHIRT_CODE" createdAt: "" From 1bac115ea992faad4c945c10365db1d260a8c893 Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 14:09:31 +0200 Subject: [PATCH 12/20] Removed channel from login url --- tests/Controller/Customer/GuestLoginApiTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Controller/Customer/GuestLoginApiTest.php b/tests/Controller/Customer/GuestLoginApiTest.php index 8a609dfc4..ff8d4e1d3 100644 --- a/tests/Controller/Customer/GuestLoginApiTest.php +++ b/tests/Controller/Customer/GuestLoginApiTest.php @@ -24,7 +24,7 @@ public function it_returns_jwt_on_success(): void } EOT; - $this->client->request(Request::METHOD_POST, '/shop-api/WEB_GB/guest/login_check', [], [], self::CONTENT_TYPE_HEADER, $data); + $this->client->request(Request::METHOD_POST, '/shop-api/guest/login_check', [], [], self::CONTENT_TYPE_HEADER, $data); $response = $this->client->getResponse(); $this->assertResponse($response, 'customer/guest_login_response'); } @@ -42,7 +42,7 @@ public function it_returns_unauthorized_on_wrong_payment_method(): void } EOT; - $this->client->request(Request::METHOD_POST, '/shop-api/WEB_GB/guest/login_check', [], [], self::CONTENT_TYPE_HEADER, $data); + $this->client->request(Request::METHOD_POST, '/shop-api/guest/login_check', [], [], self::CONTENT_TYPE_HEADER, $data); $response = $this->client->getResponse(); $this->assertResponseCode($response, Response::HTTP_UNAUTHORIZED); } @@ -60,7 +60,7 @@ public function it_returns_unauthorized_if_order_belongs_to_user(): void } EOT; - $this->client->request(Request::METHOD_POST, '/shop-api/WEB_GB/guest/login_check', [], [], self::CONTENT_TYPE_HEADER, $data); + $this->client->request(Request::METHOD_POST, '/shop-api/guest/login_check', [], [], self::CONTENT_TYPE_HEADER, $data); $response = $this->client->getResponse(); $this->assertResponseCode($response, Response::HTTP_UNAUTHORIZED); } From 444d560bad3605d7296235be7a575cf9f867359c Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 14:17:12 +0200 Subject: [PATCH 13/20] Added missing controller service --- src/Controller/Customer/GuestLoginAction.php | 10 +++++----- src/Resources/config/services/actions/customer.xml | 10 ++++++++++ tests/Application/config/routes.yaml | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Controller/Customer/GuestLoginAction.php b/src/Controller/Customer/GuestLoginAction.php index 6bac3e56f..176155a03 100644 --- a/src/Controller/Customer/GuestLoginAction.php +++ b/src/Controller/Customer/GuestLoginAction.php @@ -19,15 +19,15 @@ final class GuestLoginAction { + /** @var ViewHandlerInterface */ + private $viewHandler; + /** @var ValidatorInterface */ private $validator; /** @var ValidationErrorViewFactoryInterface */ private $validationErrorViewFactory; - /** @var ViewHandlerInterface */ - private $viewHandler; - /** @var OrderRepositoryInterface */ private $orderRepository; @@ -44,15 +44,15 @@ final class GuestLoginAction * @param GuestOrderJWTEncoderInterface $guestOrderJWTEncoder */ public function __construct( + ViewHandlerInterface $viewHandler, ValidatorInterface $validator, ValidationErrorViewFactoryInterface $validationErrorViewFactory, - ViewHandlerInterface $viewHandler, OrderRepositoryInterface $orderRepository, GuestOrderJWTEncoderInterface $guestOrderJWTEncoder ) { + $this->viewHandler = $viewHandler; $this->validator = $validator; $this->validationErrorViewFactory = $validationErrorViewFactory; - $this->viewHandler = $viewHandler; $this->orderRepository = $orderRepository; $this->guestOrderJWTEncoder = $guestOrderJWTEncoder; } diff --git a/src/Resources/config/services/actions/customer.xml b/src/Resources/config/services/actions/customer.xml index f5924e567..de61e6afe 100644 --- a/src/Resources/config/services/actions/customer.xml +++ b/src/Resources/config/services/actions/customer.xml @@ -55,5 +55,15 @@ + + + + + + + + diff --git a/tests/Application/config/routes.yaml b/tests/Application/config/routes.yaml index 15194d571..903ba8d77 100644 --- a/tests/Application/config/routes.yaml +++ b/tests/Application/config/routes.yaml @@ -14,4 +14,4 @@ sylius_shop_api_guest_login_check: methods: [POST] path: /shop-api/guest/login_check defaults: - _controller: + _controller: sylius.shop_api_plugin.controller.customer.guest_login_action From e1f8aa171a4e717566c97daede622520f4ea1a77 Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 14:38:33 +0200 Subject: [PATCH 14/20] Changed the order that test fixtures are loaded --- tests/Controller/Customer/GuestLoginApiTest.php | 6 +++--- tests/Controller/Order/GuestOrderShowApiTest.php | 6 +++--- tests/DataFixtures/ORM/shop.yml | 6 +++++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/Controller/Customer/GuestLoginApiTest.php b/tests/Controller/Customer/GuestLoginApiTest.php index ff8d4e1d3..6d53b64c6 100644 --- a/tests/Controller/Customer/GuestLoginApiTest.php +++ b/tests/Controller/Customer/GuestLoginApiTest.php @@ -14,7 +14,7 @@ final class GuestLoginApiTest extends JsonApiTestCase /** @test */ public function it_returns_jwt_on_success(): void { - $this->loadFixturesFromFiles(['order.yml', 'shop.yml', 'customer.yml', 'address.yml']); + $this->loadFixturesFromFiles(['shop.yml', 'order.yml', 'customer.yml', 'address.yml']); $data = <<loadFixturesFromFiles(['order.yml', 'shop.yml', 'customer.yml', 'address.yml']); + $this->loadFixturesFromFiles(['shop.yml', 'order.yml', 'customer.yml', 'address.yml']); $data = <<loadFixturesFromFiles(['order.yml', 'shop.yml', 'customer.yml', 'address.yml']); + $this->loadFixturesFromFiles(['shop.yml', 'order.yml', 'customer.yml', 'address.yml']); $data = <<loadFixturesFromFiles(['order.yml', 'shop.yml', 'customer.yml', 'address.yml']); + $this->loadFixturesFromFiles(['shop.yml', 'order.yml', 'customer.yml', 'address.yml']); /** @var GuestOrderJWTEncoderInterface $encoder */ $encoder = $this->get('brille24.shop_api.encoder.guest_order_jwtencoder'); @@ -39,7 +39,7 @@ public function it_returns_summary_for_guest_order(): void /** @test */ public function it_returns_unauthorized_if_no_jwt_provided(): void { - $this->loadFixturesFromFiles(['order.yml', 'shop.yml', 'customer.yml', 'address.yml']); + $this->loadFixturesFromFiles(['shop.yml', 'order.yml', 'customer.yml', 'address.yml']); $this->client->request(Request::METHOD_GET, '/shop-api/WEB_GB/guest/order'); $response = $this->client->getResponse(); @@ -49,7 +49,7 @@ public function it_returns_unauthorized_if_no_jwt_provided(): void /** @test */ public function it_returns_unauthorized_if_invalid_jwt_provided(): void { - $this->loadFixturesFromFiles(['order.yml', 'shop.yml', 'customer.yml', 'address.yml']); + $this->loadFixturesFromFiles(['shop.yml', 'order.yml', 'customer.yml', 'address.yml']); $jwt = 'abc'; diff --git a/tests/DataFixtures/ORM/shop.yml b/tests/DataFixtures/ORM/shop.yml index 449f46d10..8299b715e 100644 --- a/tests/DataFixtures/ORM/shop.yml +++ b/tests/DataFixtures/ORM/shop.yml @@ -44,7 +44,11 @@ Sylius\Component\Core\Model\Product: images: ["@mug_thumbnail"] mainTaxon: "@mug_taxon" productTaxons: ["@mug_product_taxon"] - attributes: ["@en_gb_mug_holiday_collection_value", "@de_de_mug_holiday_collection_value", "@en_gb_mug_holiday_material_value", "@de_de_mug_holiday_material_value"] + attributes: + - "@en_gb_mug_holiday_collection_value" + - "@de_de_mug_holiday_collection_value" + - "@en_gb_mug_holiday_material_value" + - "@de_de_mug_holiday_material_value" t_shirt: code: "LOGAN_T_SHIRT_CODE" createdAt: "" From 2b626f1d4baf2574ed1c5c6aafec170631ce1e9d Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 15:12:58 +0200 Subject: [PATCH 15/20] Since the fixtures don't like attribute values as array, we insert them as array collection --- tests/DataFixtures/ORM/shop.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/DataFixtures/ORM/shop.yml b/tests/DataFixtures/ORM/shop.yml index 8299b715e..ec1d4234f 100644 --- a/tests/DataFixtures/ORM/shop.yml +++ b/tests/DataFixtures/ORM/shop.yml @@ -34,6 +34,15 @@ Sylius\Component\Locale\Model\Locale: locale_de_de: code: de_DE +Doctrine\Common\Collections\ArrayCollection: + mug_attributes: + __construct: + 0: + - "@en_gb_mug_holiday_collection_value" + - "@de_de_mug_holiday_collection_value" + - "@en_gb_mug_holiday_material_value" + - "@de_de_mug_holiday_material_value" + Sylius\Component\Core\Model\Product: mug: code: "LOGAN_MUG_CODE" @@ -44,11 +53,7 @@ Sylius\Component\Core\Model\Product: images: ["@mug_thumbnail"] mainTaxon: "@mug_taxon" productTaxons: ["@mug_product_taxon"] - attributes: - - "@en_gb_mug_holiday_collection_value" - - "@de_de_mug_holiday_collection_value" - - "@en_gb_mug_holiday_material_value" - - "@de_de_mug_holiday_material_value" + attributes: "@mug_attributes" t_shirt: code: "LOGAN_T_SHIRT_CODE" createdAt: "" From 1a861aaff79c615427bdf214e3690288aab94192 Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Thu, 4 Jul 2019 15:36:33 +0200 Subject: [PATCH 16/20] Fixed wrong service id in test --- tests/Controller/Order/GuestOrderShowApiTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Controller/Order/GuestOrderShowApiTest.php b/tests/Controller/Order/GuestOrderShowApiTest.php index 8002f7b00..2863453c3 100644 --- a/tests/Controller/Order/GuestOrderShowApiTest.php +++ b/tests/Controller/Order/GuestOrderShowApiTest.php @@ -21,7 +21,7 @@ public function it_returns_summary_for_guest_order(): void $this->loadFixturesFromFiles(['shop.yml', 'order.yml', 'customer.yml', 'address.yml']); /** @var GuestOrderJWTEncoderInterface $encoder */ - $encoder = $this->get('brille24.shop_api.encoder.guest_order_jwtencoder'); + $encoder = $this->get('sylius.shop_api_plugin.encoder.guest_order_jwtencoder'); /** @var OrderRepositoryInterface $orderRepository */ $orderRepository = $this->get('sylius.repository.order'); From 18ea9a2c65430daa43e056535dcad5f481f310a1 Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Fri, 5 Jul 2019 09:37:53 +0200 Subject: [PATCH 17/20] Fixed the last unit test --- .../Order/ShowGuestOrderDetailsAction.php | 10 +++++++-- .../config/services/actions/order.xml | 1 + .../Application/config/packages/security.yaml | 2 +- .../order/guest_order_summary_response.json | 22 +++++++------------ 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/Controller/Order/ShowGuestOrderDetailsAction.php b/src/Controller/Order/ShowGuestOrderDetailsAction.php index 98b1308dc..16d57b102 100644 --- a/src/Controller/Order/ShowGuestOrderDetailsAction.php +++ b/src/Controller/Order/ShowGuestOrderDetailsAction.php @@ -9,6 +9,7 @@ use FOS\RestBundle\View\ViewHandlerInterface; use Sylius\Component\Core\Model\CustomerInterface; use Sylius\ShopApiPlugin\Traits\CustomerGuestAuthenticationInterface; +use Sylius\ShopApiPlugin\ViewRepository\Order\PlacedOrderViewRepositoryInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; @@ -22,12 +23,17 @@ final class ShowGuestOrderDetailsAction /** @var TokenStorageInterface */ protected $tokenStorage; + /** @var PlacedOrderViewRepositoryInterface */ + protected $placedOrderViewRepository; + public function __construct( ViewHandlerInterface $viewHandler, - TokenStorageInterface $tokenStorage + TokenStorageInterface $tokenStorage, + PlacedOrderViewRepositoryInterface $placedOrderViewRepository ) { $this->viewHandler = $viewHandler; $this->tokenStorage = $tokenStorage; + $this->placedOrderViewRepository = $placedOrderViewRepository; } public function __invoke(Request $request): Response @@ -43,7 +49,7 @@ public function __invoke(Request $request): Response Assert::isInstanceOf($customer, CustomerGuestAuthenticationInterface::class); Assert::null($customer->getUser()); - $order = $customer->getAuthorizedOrder(); + $order = $this->placedOrderViewRepository->getOneCompletedByCustomerEmailAndToken($customer->getEmail(), $customer->getAuthorizedOrder()->getTokenValue()); } catch (\InvalidArgumentException $exception) { return $this->viewHandler->handle(View::create(null, Response::HTTP_UNAUTHORIZED)); } diff --git a/src/Resources/config/services/actions/order.xml b/src/Resources/config/services/actions/order.xml index 99a20b498..8aec1d64c 100644 --- a/src/Resources/config/services/actions/order.xml +++ b/src/Resources/config/services/actions/order.xml @@ -25,6 +25,7 @@ > + diff --git a/tests/Application/config/packages/security.yaml b/tests/Application/config/packages/security.yaml index f6acf035c..031aaa5b2 100644 --- a/tests/Application/config/packages/security.yaml +++ b/tests/Application/config/packages/security.yaml @@ -78,7 +78,7 @@ security: require_previous_session: false shop_api_guest: - pattern: "%shop_api.security.regex%/[0-9a-zA-Z]+/guest" + pattern: "%shop_api.security.regex%/[0-9a-zA-Z-_]+/guest" stateless: true anonymous: true guard: diff --git a/tests/Responses/Expected/order/guest_order_summary_response.json b/tests/Responses/Expected/order/guest_order_summary_response.json index ade0f77e7..1b47be458 100644 --- a/tests/Responses/Expected/order/guest_order_summary_response.json +++ b/tests/Responses/Expected/order/guest_order_summary_response.json @@ -16,23 +16,19 @@ "firstName": "John", "lastName": "Doe", "countryCode": "GB", - "street": "Vukovarska", - "city": "Split", + "street": "Example str. 123", + "city": "London", "postcode": "21000", - "company": "Separovic d.o.o", - "phoneNumber": "349713", - "streetNumber": "456" + "phoneNumber": "349713" }, "billingAddress": { "firstName": "John", "lastName": "Doe", "countryCode": "GB", - "street": "Vukovarska", - "city": "Split", + "street": "Example str. 123", + "city": "London", "postcode": "21000", - "company": "Separovic d.o.o", - "phoneNumber": "349713", - "streetNumber": "456" + "phoneNumber": "349713" }, "payments": [ { @@ -46,13 +42,11 @@ "price": { "current": 1000, "currency": "GBP" - }, - "details": [] + } } ], "shipments": [], "cartDiscounts": [], "tokenValue": "GUEST_ORDER_TOKEN", - "number": "00000078", - "orderDate": @string@ + "number": "00000078" } From df3b94b15718912254fda1d834e60145bea0263f Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Fri, 5 Jul 2019 09:55:42 +0200 Subject: [PATCH 18/20] Codestyle --- src/Controller/Customer/GuestLoginAction.php | 18 ++++++------------ .../Order/ShowGuestOrderDetailsAction.php | 5 ++--- src/Encoder/GuestOrderJWTEncoder.php | 2 +- src/Provider/GuestUserProvider.php | 2 +- src/Request/Customer/GuestLoginRequest.php | 16 +++++----------- .../CustomerGuestAuthenticationInterface.php | 1 - .../CustomerGuestAuthenticationTrait.php | 1 - .../Controller/Customer/GuestLoginApiTest.php | 1 - .../Controller/Order/GuestOrderShowApiTest.php | 5 ++--- 9 files changed, 17 insertions(+), 34 deletions(-) diff --git a/src/Controller/Customer/GuestLoginAction.php b/src/Controller/Customer/GuestLoginAction.php index 176155a03..0a9964061 100644 --- a/src/Controller/Customer/GuestLoginAction.php +++ b/src/Controller/Customer/GuestLoginAction.php @@ -36,12 +36,6 @@ final class GuestLoginAction /** * GuestLoginAction constructor. - * - * @param ValidatorInterface $validator - * @param ValidationErrorViewFactoryInterface $validationErrorViewFactory - * @param ViewHandlerInterface $viewHandler - * @param OrderRepositoryInterface $orderRepository - * @param GuestOrderJWTEncoderInterface $guestOrderJWTEncoder */ public function __construct( ViewHandlerInterface $viewHandler, @@ -50,17 +44,17 @@ public function __construct( OrderRepositoryInterface $orderRepository, GuestOrderJWTEncoderInterface $guestOrderJWTEncoder ) { - $this->viewHandler = $viewHandler; - $this->validator = $validator; + $this->viewHandler = $viewHandler; + $this->validator = $validator; $this->validationErrorViewFactory = $validationErrorViewFactory; - $this->orderRepository = $orderRepository; - $this->guestOrderJWTEncoder = $guestOrderJWTEncoder; + $this->orderRepository = $orderRepository; + $this->guestOrderJWTEncoder = $guestOrderJWTEncoder; } public function __invoke(Request $request): Response { // This is just to validate that all necessary fields are present. - $loginRequest = new GuestLoginRequest($request); + $loginRequest = new GuestLoginRequest($request); $validationErrors = $this->validator->validate($loginRequest); if (0 < count($validationErrors)) { return $this->viewHandler->handle( @@ -80,7 +74,7 @@ public function __invoke(Request $request): Response // The order has to exist and must be placed if (null !== $order && $order->getCheckoutState() !== OrderCheckoutStates::STATE_CART) { /** @var CustomerInterface $customer */ - $customer = $order->getCustomer(); + $customer = $order->getCustomer(); $paymentMethod = $order->getLastPayment()->getMethod(); // The order must be a guest order. Also the provided email & payment method must match. diff --git a/src/Controller/Order/ShowGuestOrderDetailsAction.php b/src/Controller/Order/ShowGuestOrderDetailsAction.php index 16d57b102..8754e7bac 100644 --- a/src/Controller/Order/ShowGuestOrderDetailsAction.php +++ b/src/Controller/Order/ShowGuestOrderDetailsAction.php @@ -4,7 +4,6 @@ namespace Sylius\ShopApiPlugin\Controller\Order; - use FOS\RestBundle\View\View; use FOS\RestBundle\View\ViewHandlerInterface; use Sylius\Component\Core\Model\CustomerInterface; @@ -21,10 +20,10 @@ final class ShowGuestOrderDetailsAction private $viewHandler; /** @var TokenStorageInterface */ - protected $tokenStorage; + private $tokenStorage; /** @var PlacedOrderViewRepositoryInterface */ - protected $placedOrderViewRepository; + private $placedOrderViewRepository; public function __construct( ViewHandlerInterface $viewHandler, diff --git a/src/Encoder/GuestOrderJWTEncoder.php b/src/Encoder/GuestOrderJWTEncoder.php index b27ed1462..ed4f0942c 100644 --- a/src/Encoder/GuestOrderJWTEncoder.php +++ b/src/Encoder/GuestOrderJWTEncoder.php @@ -18,7 +18,7 @@ class GuestOrderJWTEncoder implements GuestOrderJWTEncoderInterface public function __construct(JWTEncoderInterface $JWTEncoder, OrderRepositoryInterface $orderRepository) { - $this->JWTEncoder = $JWTEncoder; + $this->JWTEncoder = $JWTEncoder; $this->orderRepository = $orderRepository; } diff --git a/src/Provider/GuestUserProvider.php b/src/Provider/GuestUserProvider.php index 1e36fb760..d90f52ed8 100644 --- a/src/Provider/GuestUserProvider.php +++ b/src/Provider/GuestUserProvider.php @@ -14,7 +14,7 @@ final class GuestUserProvider implements UserProviderInterface { /** @var GuestOrderJWTEncoderInterface */ - protected $encoder; + private $encoder; public function __construct(GuestOrderJWTEncoderInterface $encoder) { diff --git a/src/Request/Customer/GuestLoginRequest.php b/src/Request/Customer/GuestLoginRequest.php index 487b0652b..6d638c57e 100644 --- a/src/Request/Customer/GuestLoginRequest.php +++ b/src/Request/Customer/GuestLoginRequest.php @@ -8,25 +8,19 @@ class GuestLoginRequest { - /** - * @var string - */ + /** @var string */ protected $email; - /** - * @var string - */ + /** @var string */ protected $orderNumber; - /** - * @var string - */ + /** @var string */ protected $paymentMethodCode; public function __construct(Request $request) { - $this->email = $request->request->get('email'); - $this->orderNumber = $request->request->get('orderNumber'); + $this->email = $request->request->get('email'); + $this->orderNumber = $request->request->get('orderNumber'); $this->paymentMethodCode = $request->request->get('paymentMethod'); } diff --git a/src/Traits/CustomerGuestAuthenticationInterface.php b/src/Traits/CustomerGuestAuthenticationInterface.php index 579de660a..fe1de7283 100644 --- a/src/Traits/CustomerGuestAuthenticationInterface.php +++ b/src/Traits/CustomerGuestAuthenticationInterface.php @@ -4,7 +4,6 @@ namespace Sylius\ShopApiPlugin\Traits; - use Sylius\Component\Core\Model\OrderInterface; use Symfony\Component\Security\Core\User\UserInterface; diff --git a/src/Traits/CustomerGuestAuthenticationTrait.php b/src/Traits/CustomerGuestAuthenticationTrait.php index 2352de8d2..b2d1bcac2 100644 --- a/src/Traits/CustomerGuestAuthenticationTrait.php +++ b/src/Traits/CustomerGuestAuthenticationTrait.php @@ -4,7 +4,6 @@ namespace Sylius\ShopApiPlugin\Traits; - use Ramsey\Uuid\Uuid; use Sylius\Component\Core\Model\OrderInterface; diff --git a/tests/Controller/Customer/GuestLoginApiTest.php b/tests/Controller/Customer/GuestLoginApiTest.php index 6d53b64c6..39fac2006 100644 --- a/tests/Controller/Customer/GuestLoginApiTest.php +++ b/tests/Controller/Customer/GuestLoginApiTest.php @@ -4,7 +4,6 @@ namespace Tests\Sylius\ShopApiPlugin\Controller\Customer; - use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Tests\Sylius\ShopApiPlugin\Controller\JsonApiTestCase; diff --git a/tests/Controller/Order/GuestOrderShowApiTest.php b/tests/Controller/Order/GuestOrderShowApiTest.php index 2863453c3..823cc5207 100644 --- a/tests/Controller/Order/GuestOrderShowApiTest.php +++ b/tests/Controller/Order/GuestOrderShowApiTest.php @@ -4,7 +4,6 @@ namespace Tests\Sylius\ShopApiPlugin\Controller\Order; - use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\ShopApiPlugin\Encoder\GuestOrderJWTEncoderInterface; use Symfony\Component\HttpFoundation\Request; @@ -13,7 +12,7 @@ final class GuestOrderShowApiTest extends JsonApiTestCase { - const GUEST_TOKEN_HEADER = 'HTTP_Sylius-Guest-Token'; + public const GUEST_TOKEN_HEADER = 'HTTP_Sylius-Guest-Token'; /** @test */ public function it_returns_summary_for_guest_order(): void @@ -28,7 +27,7 @@ public function it_returns_summary_for_guest_order(): void $token = 'GUEST_ORDER_TOKEN'; $order = $orderRepository->findOneByTokenValue($token); - $jwt = $encoder->encode($order); + $jwt = $encoder->encode($order); $this->client->setServerParameter(self::GUEST_TOKEN_HEADER, $jwt); $this->client->request(Request::METHOD_GET, '/shop-api/WEB_GB/guest/order'); From 32fbc4b243e323996cd5079f42580bc641125e23 Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Fri, 5 Jul 2019 10:27:55 +0200 Subject: [PATCH 19/20] Trying to fix phpstan --- src/Controller/Order/ShowGuestOrderDetailsAction.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Controller/Order/ShowGuestOrderDetailsAction.php b/src/Controller/Order/ShowGuestOrderDetailsAction.php index 8754e7bac..e07f53919 100644 --- a/src/Controller/Order/ShowGuestOrderDetailsAction.php +++ b/src/Controller/Order/ShowGuestOrderDetailsAction.php @@ -45,6 +45,7 @@ public function __invoke(Request $request): Response /** @var CustomerGuestAuthenticationInterface|CustomerInterface $customer */ $customer = $token->getUser(); + Assert::isInstanceOf($customer, CustomerInterface::class); Assert::isInstanceOf($customer, CustomerGuestAuthenticationInterface::class); Assert::null($customer->getUser()); From cd909627f97d5e009b837e92d93cd2b8b70c1007 Mon Sep 17 00:00:00 2001 From: Jakob Tolkemit Date: Mon, 12 Aug 2019 15:30:12 +0200 Subject: [PATCH 20/20] Fix unit test --- tests/Application/config/packages/security.yaml | 4 +--- tests/Controller/Order/GuestOrderShowApiTest.php | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/Application/config/packages/security.yaml b/tests/Application/config/packages/security.yaml index 06c12c996..088e70d0b 100644 --- a/tests/Application/config/packages/security.yaml +++ b/tests/Application/config/packages/security.yaml @@ -57,10 +57,8 @@ security: stateless: true anonymous: true provider: sylius_guest_user_provider - json_login: + form_login: check_path: /shop-api/login/guest - username_path: email - password_path: password success_handler: lexik_jwt_authentication.handler.authentication_success failure_handler: lexik_jwt_authentication.handler.authentication_failure require_previous_session: false diff --git a/tests/Controller/Order/GuestOrderShowApiTest.php b/tests/Controller/Order/GuestOrderShowApiTest.php index 823cc5207..cf91f6738 100644 --- a/tests/Controller/Order/GuestOrderShowApiTest.php +++ b/tests/Controller/Order/GuestOrderShowApiTest.php @@ -30,7 +30,7 @@ public function it_returns_summary_for_guest_order(): void $jwt = $encoder->encode($order); $this->client->setServerParameter(self::GUEST_TOKEN_HEADER, $jwt); - $this->client->request(Request::METHOD_GET, '/shop-api/WEB_GB/guest/order'); + $this->client->request(Request::METHOD_GET, '/shop-api/guest/order'); $response = $this->client->getResponse(); $this->assertResponse($response, 'order/guest_order_summary_response'); } @@ -40,7 +40,7 @@ public function it_returns_unauthorized_if_no_jwt_provided(): void { $this->loadFixturesFromFiles(['shop.yml', 'order.yml', 'customer.yml', 'address.yml']); - $this->client->request(Request::METHOD_GET, '/shop-api/WEB_GB/guest/order'); + $this->client->request(Request::METHOD_GET, '/shop-api/guest/order'); $response = $this->client->getResponse(); $this->assertResponseCode($response, Response::HTTP_UNAUTHORIZED); } @@ -53,7 +53,7 @@ public function it_returns_unauthorized_if_invalid_jwt_provided(): void $jwt = 'abc'; $this->client->setServerParameter(self::GUEST_TOKEN_HEADER, $jwt); - $this->client->request(Request::METHOD_GET, '/shop-api/WEB_GB/guest/order'); + $this->client->request(Request::METHOD_GET, '/shop-api/guest/order'); $response = $this->client->getResponse(); $this->assertResponseCode($response, Response::HTTP_UNAUTHORIZED); }