diff --git a/app/code/Magento/SendFriendGraphQl/Model/Provider/GetProduct.php b/app/code/Magento/SendFriendGraphQl/Model/Provider/GetVisibleProduct.php similarity index 98% rename from app/code/Magento/SendFriendGraphQl/Model/Provider/GetProduct.php rename to app/code/Magento/SendFriendGraphQl/Model/Provider/GetVisibleProduct.php index 27ef64918dee4..9fa9bf2b35d29 100644 --- a/app/code/Magento/SendFriendGraphQl/Model/Provider/GetProduct.php +++ b/app/code/Magento/SendFriendGraphQl/Model/Provider/GetVisibleProduct.php @@ -17,7 +17,7 @@ /** * Class GetProduct */ -class GetProduct +class GetVisibleProduct { /** @var ProductRepositoryInterface */ private $productRepository; diff --git a/app/code/Magento/SendFriendGraphQl/Model/Resolver/SendEmailToFriend.php b/app/code/Magento/SendFriendGraphQl/Model/Resolver/SendEmailToFriend.php index fe13e074d98fd..0a4fe1e3e5616 100644 --- a/app/code/Magento/SendFriendGraphQl/Model/Resolver/SendEmailToFriend.php +++ b/app/code/Magento/SendFriendGraphQl/Model/Resolver/SendEmailToFriend.php @@ -7,15 +7,14 @@ namespace Magento\SendFriendGraphQl\Model\Resolver; -use Magento\Framework\DataObjectFactory; -use Magento\Framework\Event\ManagerInterface; use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\SendFriend\Model\SendFriend; -use Magento\SendFriend\Model\SendFriendFactory; -use Magento\SendFriendGraphQl\Model\Provider\GetProduct; +use Magento\GraphQl\Model\Query\ContextInterface; +use Magento\SendFriend\Helper\Data as SendFriendHelper; +use Magento\SendFriendGraphQl\Model\SendFriend\SendEmail; /** * @inheritdoc @@ -23,41 +22,25 @@ class SendEmailToFriend implements ResolverInterface { /** - * @var SendFriendFactory + * @var SendFriendHelper */ - private $sendFriendFactory; + private $sendFriendHelper; /** - * @var DataObjectFactory + * @var SendEmail */ - private $dataObjectFactory; + private $sendEmail; /** - * @var ManagerInterface - */ - private $eventManager; - - /** - * @var GetProduct - */ - private $getProductProvider; - - /** - * @param SendFriendFactory $sendFriendFactory - * @param DataObjectFactory $dataObjectFactory - * @param ManagerInterface $eventManager - * @param GetProduct $getProductProvider + * @param SendEmail $sendEmail + * @param SendFriendHelper $sendFriendHelper */ public function __construct( - SendFriendFactory $sendFriendFactory, - DataObjectFactory $dataObjectFactory, - ManagerInterface $eventManager, - GetProduct $getProductProvider + SendEmail $sendEmail, + SendFriendHelper $sendFriendHelper ) { - $this->sendFriendFactory = $sendFriendFactory; - $this->dataObjectFactory = $dataObjectFactory; - $this->eventManager = $eventManager; - $this->getProductProvider = $getProductProvider; + $this->sendEmail = $sendEmail; + $this->sendFriendHelper = $sendFriendHelper; } /** @@ -65,55 +48,24 @@ public function __construct( */ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) { - /** @var SendFriend $sendFriend */ - $sendFriend = $this->sendFriendFactory->create(); - - if ($sendFriend->getMaxSendsToFriend() && $sendFriend->isExceedLimit()) { - throw new GraphQlInputException( - __('You can\'t send messages more than %1 times an hour.', $sendFriend->getMaxSendsToFriend()) - ); + /** @var ContextInterface $context */ + if (!$this->sendFriendHelper->isAllowForGuest() + && false === $context->getExtensionAttributes()->getIsCustomer() + ) { + throw new GraphQlAuthorizationException(__('The current customer isn\'t authorized.')); } - $product = $this->getProductProvider->execute($args['input']['product_id']); - $this->eventManager->dispatch('sendfriend_product', ['product' => $product]); - $sendFriend->setProduct($product); - $senderData = $this->extractSenderData($args); - $sendFriend->setSender($senderData); - $recipientsData = $this->extractRecipientsData($args); - $sendFriend->setRecipients($recipientsData); - - $this->validateSendFriendModel($sendFriend, $senderData, $recipientsData); - $sendFriend->send(); + $this->sendEmail->execute( + $args['input']['product_id'], + $senderData, + $recipientsData + ); return array_merge($senderData, $recipientsData); } - /** - * Validate send friend model - * - * @param SendFriend $sendFriend - * @param array $senderData - * @param array $recipientsData - * @return void - * @throws GraphQlInputException - */ - private function validateSendFriendModel(SendFriend $sendFriend, array $senderData, array $recipientsData): void - { - $sender = $this->dataObjectFactory->create()->setData($senderData['sender']); - $sendFriend->setData('_sender', $sender); - - $emails = array_column($recipientsData['recipients'], 'email'); - $recipients = $this->dataObjectFactory->create()->setData('emails', $emails); - $sendFriend->setData('_recipients', $recipients); - - $validationResult = $sendFriend->validate(); - if ($validationResult !== true) { - throw new GraphQlInputException(__(implode($validationResult))); - } - } - /** * Extract recipients data * diff --git a/app/code/Magento/SendFriendGraphQl/Model/SendFriend/SendEmail.php b/app/code/Magento/SendFriendGraphQl/Model/SendFriend/SendEmail.php new file mode 100644 index 0000000000000..196086c7546c4 --- /dev/null +++ b/app/code/Magento/SendFriendGraphQl/Model/SendFriend/SendEmail.php @@ -0,0 +1,142 @@ +dataObjectFactory = $dataObjectFactory; + $this->productRepository = $productRepository; + $this->sendFriendFactory = $sendFriendFactory; + $this->eventManager = $eventManager; + } + + /** + * Send product email to friend(s) + * + * @param int $productId + * @param array $senderData + * @param array $recipientsData + * @throws GraphQlInputException + * @throws GraphQlNoSuchEntityException + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function execute(int $productId, array $senderData, array $recipientsData): void + { + /** @var SendFriend $sendFriend */ + $sendFriend = $this->sendFriendFactory->create(); + + if ($sendFriend->getMaxSendsToFriend() && $sendFriend->isExceedLimit()) { + throw new GraphQlInputException( + __('You can\'t send messages more than %1 times an hour.', $sendFriend->getMaxSendsToFriend()) + ); + } + + $product = $this->getProduct($productId); + + $this->eventManager->dispatch('sendfriend_product', ['product' => $product]); + + $sendFriend->setProduct($product); + $sendFriend->setSender($senderData); + $sendFriend->setRecipients($recipientsData); + + $this->validateSendFriendModel($sendFriend, $senderData, $recipientsData); + + $sendFriend->send(); + } + + /** + * Validate send friend model + * + * @param SendFriend $sendFriend + * @param array $senderData + * @param array $recipientsData + * @return void + * @throws GraphQlInputException + */ + private function validateSendFriendModel(SendFriend $sendFriend, array $senderData, array $recipientsData): void + { + $sender = $this->dataObjectFactory->create()->setData($senderData['sender']); + $sendFriend->setData('_sender', $sender); + + $emails = array_column($recipientsData['recipients'], 'email'); + $recipients = $this->dataObjectFactory->create()->setData('emails', $emails); + $sendFriend->setData('_recipients', $recipients); + + $validationResult = $sendFriend->validate(); + if ($validationResult !== true) { + throw new GraphQlInputException(__(implode($validationResult))); + } + } + + /** + * Get product + * + * @param int $productId + * @return ProductInterface + * @throws GraphQlNoSuchEntityException + */ + private function getProduct(int $productId): ProductInterface + { + try { + $product = $this->productRepository->getById($productId); + if (!$product->isVisibleInCatalog()) { + throw new GraphQlNoSuchEntityException( + __("The product that was requested doesn't exist. Verify the product and try again.") + ); + } + } catch (NoSuchEntityException $e) { + throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e); + } + return $product; + } +} diff --git a/app/code/Magento/SendFriendGraphQl/composer.json b/app/code/Magento/SendFriendGraphQl/composer.json index d401f57b2257a..091c684879129 100644 --- a/app/code/Magento/SendFriendGraphQl/composer.json +++ b/app/code/Magento/SendFriendGraphQl/composer.json @@ -6,9 +6,7 @@ "php": "~7.1.3||~7.2.0", "magento/framework": "*", "magento/module-catalog": "*", - "magento/module-send-friend": "*" - }, - "suggest": { + "magento/module-send-friend": "*", "magento/module-graph-ql": "*" }, "license": [ diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/SendFriend/SendFriendTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/SendFriend/SendFriendTest.php index e67c1ff40ae6c..e885c2b8fb568 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/SendFriend/SendFriendTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/SendFriend/SendFriendTest.php @@ -8,10 +8,11 @@ namespace Magento\GraphQl\SendFriend; use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\Exception\AuthenticationException; +use Magento\Integration\Api\CustomerTokenServiceInterface; use Magento\SendFriend\Model\SendFriend; use Magento\SendFriend\Model\SendFriendFactory; use Magento\TestFramework\Helper\Bootstrap; -use Magento\TestFramework\TestCase\GraphQl\ResponseContainsErrorsException; use Magento\TestFramework\TestCase\GraphQlAbstract; /** @@ -24,21 +25,29 @@ class SendFriendTest extends GraphQlAbstract * @var SendFriendFactory */ private $sendFriendFactory; + /** * @var ProductRepositoryInterface */ private $productRepository; + /** + * @var CustomerTokenServiceInterface + */ + private $customerTokenService; + protected function setUp() { $this->sendFriendFactory = Bootstrap::getObjectManager()->get(SendFriendFactory::class); $this->productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class); + $this->customerTokenService = Bootstrap::getObjectManager()->get(CustomerTokenServiceInterface::class); } /** * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/SendFriend/_files/enable_send_friend_guest.php */ - public function testSendFriend() + public function testSendFriendGuestEnable() { $productId = (int)$this->productRepository->get('simple_product')->getId(); $recipients = '{ @@ -52,15 +61,57 @@ public function testSendFriend() $query = $this->getQuery($productId, $recipients); $response = $this->graphQlMutation($query); - self::assertEquals('Name', $response['sendEmailToFriend']['sender']['name']); - self::assertEquals('e@mail.com', $response['sendEmailToFriend']['sender']['email']); - self::assertEquals('Lorem Ipsum', $response['sendEmailToFriend']['sender']['message']); - self::assertEquals('Recipient Name 1', $response['sendEmailToFriend']['recipients'][0]['name']); - self::assertEquals('recipient1@mail.com', $response['sendEmailToFriend']['recipients'][0]['email']); - self::assertEquals('Recipient Name 2', $response['sendEmailToFriend']['recipients'][1]['name']); - self::assertEquals('recipient2@mail.com', $response['sendEmailToFriend']['recipients'][1]['email']); + $this->assertResponse($response); + } + + /** + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/SendFriend/_files/disable_send_friend_guest.php + * @expectedException \Exception + * @expectedExceptionMessage The current customer isn't authorized. + */ + public function testSendFriendGuestDisableAsGuest() + { + $productId = (int)$this->productRepository->get('simple_product')->getId(); + $recipients = '{ + name: "Recipient Name 1" + email:"recipient1@mail.com" + }, + { + name: "Recipient Name 2" + email:"recipient2@mail.com" + }'; + $query = $this->getQuery($productId, $recipients); + + $response = $this->graphQlMutation($query); + $this->assertResponse($response); } + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/SendFriend/_files/disable_send_friend_guest.php + */ + public function testSendFriendGuestDisableAsCustomer() + { + $productId = (int)$this->productRepository->get('simple_product')->getId(); + $recipients = '{ + name: "Recipient Name 1" + email:"recipient1@mail.com" + }, + { + name: "Recipient Name 2" + email:"recipient2@mail.com" + }'; + $query = $this->getQuery($productId, $recipients); + + $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + $this->assertResponse($response); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + */ public function testSendWithoutExistProduct() { $productId = 2018; @@ -78,10 +129,11 @@ public function testSendWithoutExistProduct() $this->expectExceptionMessage( 'The product that was requested doesn\'t exist. Verify the product and try again.' ); - $this->graphQlMutation($query); + $this->graphQlMutation($query, [], '', $this->getHeaderMap()); } /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php */ public function testMaxSendEmailToFriend() @@ -119,10 +171,11 @@ public function testMaxSendEmailToFriend() $this->expectException(\Exception::class); $this->expectExceptionMessage("No more than {$sendFriend->getMaxRecipients()} emails can be sent at a time."); - $this->graphQlMutation($query); + $this->graphQlMutation($query, [], '', $this->getHeaderMap()); } /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php * @dataProvider sendFriendsErrorsDataProvider * @param string $input @@ -152,10 +205,11 @@ public function testErrors(string $input, string $errorMessage) QUERY; $this->expectException(\Exception::class); $this->expectExceptionMessage($errorMessage); - $this->graphQlMutation($query); + $this->graphQlMutation($query, [], '', $this->getHeaderMap()); } /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php * TODO: use magentoApiConfigFixture (to be merged https://github.com/magento/graphql-ce/pull/351) * @magentoApiDataFixture Magento/SendFriend/Fixtures/sendfriend_configuration.php @@ -184,11 +238,12 @@ public function testLimitMessagesPerHour() $maxSendToFriends = $sendFriend->getMaxSendsToFriend(); for ($i = 0; $i <= $maxSendToFriends + 1; $i++) { - $this->graphQlMutation($query); + $this->graphQlMutation($query, [], '', $this->getHeaderMap()); } } /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php */ public function testSendProductWithoutSenderEmail() @@ -202,10 +257,11 @@ public function testSendProductWithoutSenderEmail() $this->expectException(\Exception::class); $this->expectExceptionMessage('GraphQL response contains errors: Please provide Email for all of recipients.'); - $this->graphQlMutation($query); + $this->graphQlMutation($query, [], '', $this->getHeaderMap()); } /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product_without_visibility.php */ public function testSendProductWithoutVisibility() @@ -220,8 +276,9 @@ public function testSendProductWithoutVisibility() email:"recipient2@mail.com" }'; $query = $this->getQuery($productId, $recipients); - $this->expectException(ResponseContainsErrorsException::class); - $this->graphQlMutation($query); + + $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + $this->assertResponse($response); } /** @@ -305,6 +362,37 @@ public function sendFriendsErrorsDataProvider() ]; } + /** + * Generic assertions for send a friend response + * + * @param array $response + */ + private function assertResponse(array $response): void + { + self::assertEquals('Name', $response['sendEmailToFriend']['sender']['name']); + self::assertEquals('e@mail.com', $response['sendEmailToFriend']['sender']['email']); + self::assertEquals('Lorem Ipsum', $response['sendEmailToFriend']['sender']['message']); + self::assertEquals('Recipient Name 1', $response['sendEmailToFriend']['recipients'][0]['name']); + self::assertEquals('recipient1@mail.com', $response['sendEmailToFriend']['recipients'][0]['email']); + self::assertEquals('Recipient Name 2', $response['sendEmailToFriend']['recipients'][1]['name']); + self::assertEquals('recipient2@mail.com', $response['sendEmailToFriend']['recipients'][1]['email']); + } + + /** + * Retrieve customer authorization headers + * + * @param string $username + * @param string $password + * @return array + * @throws AuthenticationException + */ + private function getHeaderMap(string $username = 'customer@example.com', string $password = 'password'): array + { + $customerToken = $this->customerTokenService->createCustomerAccessToken($username, $password); + $headerMap = ['Authorization' => 'Bearer ' . $customerToken]; + return $headerMap; + } + /** * @param int $productId * @param string $recipients diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/SendFriend/_files/disable_send_friend_guest.php b/dev/tests/integration/testsuite/Magento/GraphQl/SendFriend/_files/disable_send_friend_guest.php new file mode 100644 index 0000000000000..80fcc2079a018 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GraphQl/SendFriend/_files/disable_send_friend_guest.php @@ -0,0 +1,21 @@ +get(WriterInterface::class); + +$configWriter->save('sendfriend/email/allow_guest', '0'); + +$scopeConfig = $objectManager->get(ScopeConfigInterface::class); +$scopeConfig->clean(); diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/SendFriend/_files/enable_send_friend_guest.php b/dev/tests/integration/testsuite/Magento/GraphQl/SendFriend/_files/enable_send_friend_guest.php new file mode 100644 index 0000000000000..aaf9a447aeaa0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GraphQl/SendFriend/_files/enable_send_friend_guest.php @@ -0,0 +1,21 @@ +get(WriterInterface::class); + +$configWriter->save('sendfriend/email/allow_guest', '1'); + +$scopeConfig = $objectManager->get(ScopeConfigInterface::class); +$scopeConfig->clean();