Skip to content
Permalink
Browse files Browse the repository at this point in the history
NEXT-19276 - Add filtering to promotion and product codes
  • Loading branch information
mstegmeyer authored and pweyck committed Feb 4, 2022
1 parent 47b4b09 commit 651598a
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 28 deletions.
@@ -0,0 +1,8 @@
---
title: Add filtering to product and promotion codes
issue: NEXT-19276
author: Max Stegmeyer
author_email: m.stegmeyer@shopware.com
---
# Storefront
* Changed `Shopware\Storefront\Controller\CartLineItemController` to sanitize from promotion codes and product number error messages
Expand Up @@ -15,13 +15,15 @@ public function supports(string $type): bool

public function create(array $data, SalesChannelContext $context): LineItem
{
$uniqueKey = 'promotion-' . $data['referencedId'];
$code = $data['referencedId'];

$uniqueKey = 'promotion-' . $code;
$item = new LineItem($uniqueKey, LineItem::PROMOTION_LINE_ITEM_TYPE);
$item->setLabel($uniqueKey);
$item->setGood(false);

// this is used to pass on the code for later usage
$item->setReferencedId($data['referencedId']);
$item->setReferencedId($code);

// this is important to avoid any side effects when calculating the cart
// a percentage of 0,00 will just do nothing
Expand Down
1 change: 1 addition & 0 deletions src/Core/Checkout/DependencyInjection/promotion.xml
Expand Up @@ -70,6 +70,7 @@
<service id="Shopware\Core\Checkout\Promotion\Cart\PromotionCollector">
<argument type="service" id="Shopware\Core\Checkout\Promotion\Gateway\PromotionGateway"/>
<argument type="service" id="Shopware\Core\Checkout\Promotion\Cart\PromotionItemBuilder"/>
<argument type="service" id="Shopware\Core\Framework\Util\HtmlSanitizer"/>
<!-- // inject after product collector(5000) -->
<tag name="shopware.cart.collector" priority="4900"/>
</service>
Expand Down
9 changes: 7 additions & 2 deletions src/Core/Checkout/Promotion/Cart/PromotionCollector.php
Expand Up @@ -22,6 +22,7 @@
use Shopware\Core\Checkout\Promotion\PromotionEntity;
use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Util\HtmlSanitizer;
use Shopware\Core\System\SalesChannel\SalesChannelContext;

class PromotionCollector implements CartDataCollectorInterface
Expand All @@ -35,12 +36,15 @@ class PromotionCollector implements CartDataCollectorInterface

private PromotionItemBuilder $itemBuilder;

private HtmlSanitizer $htmlSanitizer;

private array $requiredDalAssociations;

public function __construct(PromotionGatewayInterface $gateway, PromotionItemBuilder $itemBuilder)
public function __construct(PromotionGatewayInterface $gateway, PromotionItemBuilder $itemBuilder, HtmlSanitizer $htmlSanitizer)
{
$this->gateway = $gateway;
$this->itemBuilder = $itemBuilder;
$this->htmlSanitizer = $htmlSanitizer;

$this->requiredDalAssociations = [
'personaRules',
Expand Down Expand Up @@ -134,7 +138,8 @@ public function collect(CartDataCollection $data, Cart $original, SalesChannelCo
foreach ($allCodes as $code) {
if (!\in_array($code, $foundCodes, true)) {
$cartExtension->removeCode($code);
$this->addPromotionNotFoundError($code, $original);

$this->addPromotionNotFoundError($this->htmlSanitizer->sanitize($code, null, true), $original);
}
}

Expand Down
34 changes: 15 additions & 19 deletions src/Storefront/Controller/CartLineItemController.php
Expand Up @@ -20,6 +20,7 @@
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
use Shopware\Core\Framework\Routing\Annotation\Since;
use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
use Shopware\Core\Framework\Util\HtmlSanitizer;
use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
use Shopware\Core\System\SalesChannel\Entity\SalesChannelRepositoryInterface;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
Expand All @@ -32,36 +33,28 @@
*/
class CartLineItemController extends StorefrontController
{
/**
* @var CartService
*/
private $cartService;
private CartService $cartService;

/**
* @var PromotionItemBuilder
*/
private $promotionItemBuilder;
private PromotionItemBuilder $promotionItemBuilder;

/**
* @var SalesChannelRepositoryInterface
*/
private $productRepository;
private SalesChannelRepositoryInterface $productRepository;

/**
* @var ProductLineItemFactory
*/
private $productLineItemFactory;
private ProductLineItemFactory $productLineItemFactory;

private HtmlSanitizer $htmlSanitizer;

public function __construct(
CartService $cartService,
SalesChannelRepositoryInterface $productRepository,
PromotionItemBuilder $promotionItemBuilder,
ProductLineItemFactory $productLineItemFactory
ProductLineItemFactory $productLineItemFactory,
HtmlSanitizer $htmlSanitizer
) {
$this->cartService = $cartService;
$this->productRepository = $productRepository;
$this->promotionItemBuilder = $promotionItemBuilder;
$this->productLineItemFactory = $productLineItemFactory;
$this->htmlSanitizer = $htmlSanitizer;
}

/**
Expand Down Expand Up @@ -169,7 +162,7 @@ public function changeQuantity(Cart $cart, string $id, Request $request, SalesCh
*/
public function addProductByNumber(Request $request, SalesChannelContext $salesChannelContext): Response
{
$number = $request->request->get('number');
$number = (string) $request->request->get('number');

if (!$number) {
throw new MissingRequestParameterException('number');
Expand All @@ -183,7 +176,10 @@ public function addProductByNumber(Request $request, SalesChannelContext $salesC
$data = $idSearchResult->getIds();

if (empty($data)) {
$this->addFlash(self::DANGER, $this->trans('error.productNotFound', ['%number%' => $number]));
$this->addFlash(self::DANGER, $this->trans(
'error.productNotFound',
['%number%' => $this->htmlSanitizer->sanitize($number, null, true)]
));

return $this->createActionResponse($request);
}
Expand Down
1 change: 1 addition & 0 deletions src/Storefront/DependencyInjection/controller.xml
Expand Up @@ -98,6 +98,7 @@
<argument type="service" id="sales_channel.product.repository"/>
<argument type="service" id="Shopware\Core\Checkout\Promotion\Cart\PromotionItemBuilder"/>
<argument type="service" id="Shopware\Core\Content\Product\Cart\ProductLineItemFactory"/>
<argument type="service" id="Shopware\Core\Framework\Util\HtmlSanitizer"/>
<call method="setContainer">
<argument type="service" id="service_container"/>
</call>
Expand Down
51 changes: 46 additions & 5 deletions src/Storefront/Test/Controller/CartLineItemControllerTest.php
Expand Up @@ -38,21 +38,29 @@ public function clearFlashBag(): void
/**
* @dataProvider productNumbers
*/
public function testAddProductByNumber(string $productId, string $productNumber): void
public function testAddProductByNumber(?string $productId, string $productNumber): void
{
$contextToken = Uuid::randomHex();

$cartService = $this->getContainer()->get(CartService::class);
$this->createProduct($productId, $productNumber);
if ($productId) {
$this->createProduct($productId, $productNumber);
}
$request = $this->createRequest(['number' => $productNumber]);

$salesChannelContext = $this->createSalesChannelContext($contextToken);
$response = $this->getContainer()->get(CartLineItemController::class)->addProductByNumber($request, $salesChannelContext);

$cartLineItem = $cartService->getCart($contextToken, $salesChannelContext)->getLineItems()->get($productId);

static::assertArrayHasKey('success', $this->getFlashBag()->all());
static::assertNotNull($cartLineItem);
$flashBag = $this->getFlashBag()->all();
if ($productId) {
static::assertArrayHasKey('success', $flashBag);
static::assertNotNull($cartLineItem);
} else {
static::assertArrayHasKey('danger', $flashBag);
static::assertSame($this->getContainer()->get('translator')->trans('error.productNotFound', ['%number%' => \strip_tags($productNumber)]), $flashBag['danger'][0]);
static::assertNull($cartLineItem);
}
static::assertSame(200, $response->getStatusCode());
}

Expand All @@ -65,9 +73,42 @@ public function productNumbers(): array
[Uuid::randomHex(), 'test_123'],
[Uuid::randomHex(), 'testäüö123'],
[Uuid::randomHex(), 'test/123'],
[null, 'nonExisting'],
[null, 'with<br>HTML'],
];
}

public function promotions(): array
{
return [
['testCode'],
['with<br>HTML'],
];
}

/**
* @dataProvider promotions
*/
public function testAddPromotion(string $code): void
{
$contextToken = Uuid::randomHex();

$cartService = $this->getContainer()->get(CartService::class);
$request = $this->createRequest(['code' => $code]);

$salesChannelContext = $this->createSalesChannelContext($contextToken);
$this->getContainer()->get(CartLineItemController::class)->addPromotion(
$cartService->getCart($contextToken, $salesChannelContext),
$request,
$salesChannelContext
);

$flashBag = $this->getFlashBag()->all();
static::assertArrayHasKey('danger', $flashBag);
static::assertSame($this->getContainer()->get('translator')->trans('checkout.promotion-not-found', ['%code%' => \strip_tags($code)]), $flashBag['danger'][0]);
static::assertSame(0, $cartService->getCart($contextToken, $salesChannelContext)->getLineItems()->count());
}

private function getLineItemAddPayload(string $productId): array
{
return [
Expand Down

0 comments on commit 651598a

Please sign in to comment.