Skip to content

Commit

Permalink
Merge pull request #31 from synolia/feature/add-customer-anonymized-c…
Browse files Browse the repository at this point in the history
…ount-on-advanced-actions

Display how many customer has been anonymized and fix dateTime object anonymization
  • Loading branch information
oallain authored Jul 7, 2023
2 parents ef87abc + 3248867 commit 549f0e3
Show file tree
Hide file tree
Showing 12 changed files with 112 additions and 13 deletions.
1 change: 1 addition & 0 deletions ruleset/phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ parameters:
- '#Call to an undefined method Faker\\UniqueGenerator::format\(\).#'
- "#^Call to an undefined method Symfony\\\\Component\\\\HttpFoundation\\\\Session\\\\SessionInterface\\:\\:getFlashBag\\(\\)\\.$#"
- '#.*Laminas\\Stdlib\\PriorityQueue*.#'
- '#Call to an undefined method Faker\\UniqueGenerator::format\(\).#'
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,29 @@
use Sylius\Component\Core\Model\ShopUserInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Synolia\SyliusGDPRPlugin\Processor\AnonymizerProcessor;

class AnonymizeCustomersNotLoggedBeforeProcessor implements AdvancedActionsFormDataProcessorInterface
{
private EntityManagerInterface $entityManager;

private AnonymizerProcessor $anonymizerProcessor;

private ParameterBagInterface $parameterBag;

private RequestStack $requestStack;

public function __construct(
private EntityManagerInterface $entityManager,
private AnonymizerProcessor $anonymizerProcessor,
private ParameterBagInterface $parameterBag,
EntityManagerInterface $entityManager,
AnonymizerProcessor $anonymizerProcessor,
ParameterBagInterface $parameterBag,
RequestStack $requestStack,
) {
$this->entityManager = $entityManager;
$this->anonymizerProcessor = $anonymizerProcessor;
$this->parameterBag = $parameterBag;
$this->requestStack = $requestStack;
}

/** @inheritdoc */
Expand All @@ -43,6 +57,8 @@ public function process(string $formTypeClass, FormInterface $form): void
}

$this->anonymizerProcessor->anonymizeEntities($this->getCustomersFromShopUsers($shopUsers));

$this->requestStack->getSession()->getFlashBag()->add('success', sprintf('%d customers anonymized.', $this->anonymizerProcessor->getAnonymizedEntityCount()));
}

private function getCustomersFromShopUsers(array $shopUsers): array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,29 @@
use Sylius\Component\Core\Model\OrderInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Synolia\SyliusGDPRPlugin\Processor\AnonymizerProcessor;

class AnonymizeCustomersWithoutAnyOrdersBeforeProcessor implements AdvancedActionsFormDataProcessorInterface
{
private EntityManagerInterface $entityManager;

private AnonymizerProcessor $anonymizerProcessor;

private ParameterBagInterface $parameterBag;

private RequestStack $requestStack;

public function __construct(
private EntityManagerInterface $entityManager,
private AnonymizerProcessor $anonymizerProcessor,
private ParameterBagInterface $parameterBag,
EntityManagerInterface $entityManager,
AnonymizerProcessor $anonymizerProcessor,
ParameterBagInterface $parameterBag,
RequestStack $requestStack,
) {
$this->entityManager = $entityManager;
$this->anonymizerProcessor = $anonymizerProcessor;
$this->parameterBag = $parameterBag;
$this->requestStack = $requestStack;
}

/** @inheritdoc */
Expand Down Expand Up @@ -46,6 +60,8 @@ public function process(string $formTypeClass, FormInterface $form): void
$this->removeNoneEligibleCustomers($customers);

$this->anonymizerProcessor->anonymizeEntities($customers);

$this->requestStack->getSession()->getFlashBag()->add('success', sprintf('%d customers anonymized.', $this->anonymizerProcessor->getAnonymizedEntityCount()));
}

private function removeNoneEligibleCustomers(array &$customers): array
Expand Down
33 changes: 31 additions & 2 deletions src/Processor/AnonymizerProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,34 @@
namespace Synolia\SyliusGDPRPlugin\Processor;

use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Synolia\SyliusGDPRPlugin\Provider\AnonymizerInterface;

final class AnonymizerProcessor
{
private const MODULO_FLUSH = 50;

public function __construct(private AnonymizerInterface $anonymizer, private EntityManagerInterface $entityManager)
{
private AnonymizerInterface $anonymizer;

private EntityManagerInterface $entityManager;

private TranslatorInterface $translator;

private LoggerInterface $logger;

private int $anonymizedEntity = 0;

public function __construct(
AnonymizerInterface $anonymizer,
EntityManagerInterface $entityManager,
TranslatorInterface $translator,
LoggerInterface $logger,
) {
$this->anonymizer = $anonymizer;
$this->entityManager = $entityManager;
$this->translator = $translator;
$this->logger = $logger;
}

public function anonymizeEntities(array $entities, bool $reset = false, int $maxRetries = 50): void
Expand All @@ -30,10 +50,19 @@ public function anonymizeEntities(array $entities, bool $reset = false, int $max
}

$this->entityManager->flush();

$this->logger->info(sprintf('%d %s', $this->getAnonymizedEntityCount(), $this->translator->trans('sylius.ui.admin.synolia_gdpr.advanced_actions.customer_anonymized_count')));
}

public function getAnonymizedEntityCount(): int
{
return $this->anonymizedEntity;
}

private function anonymizeEntity(Object $entity, bool $reset = false, int $maxRetries = 50): void
{
$this->anonymizer->anonymize($entity, $reset, $maxRetries);

++$this->anonymizedEntity;
}
}
4 changes: 4 additions & 0 deletions src/Provider/Anonymizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ public function anonymize(Object $entity, bool $reset = false, int $maxRetries =

if ($this->isSubclass($entity, $className, $propertyName)) {
$getter = 'get' . ucfirst($propertyName);
if ($entity->$getter() instanceof \DateTime && $attributeMetaData instanceof AttributeMetaData) {
$this->anonymizeProcess($entity, $reset, $maxRetries, $className, $propertyName, $attributeMetaData);
}

$this->anonymize($entity->$getter(), $reset, $maxRetries);

continue;
Expand Down
4 changes: 1 addition & 3 deletions src/Resources/config/mappings/AddressLogEntry.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
Sylius\Component\Addressing\Model\AddressLogEntry:
properties:
loggedAt:
faker: dateTime
data:
value: ['anonymized-details']
objectId:
value: 'anonymized'
value: 'anonymized'
3 changes: 2 additions & 1 deletion src/Resources/config/mappings/ShopUser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ Sylius\Component\Core\Model\ShopUser:
faker: sha256
prefix: 'anonymized-'
lastLogin:
faker: dateTime
faker: dateTimeBetween
args: ['+100 years', '+101 years']
emailVerificationToken:
value: null
passwordResetToken:
Expand Down
1 change: 1 addition & 0 deletions src/Resources/translations/messages.en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ sylius:
gdpr_title: GDPR
advanced_actions:
title: Advanced actions
customer_anonymized_count: customers anonymized.
anonymize_customers_not_logged_before:
label: Anonymize customers not logged before
anonymize_customer_without_any_orders:
Expand Down
3 changes: 2 additions & 1 deletion src/Resources/translations/messages.fr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ sylius:
gdpr_title: RGPD
advanced_actions:
title: Actions avancées
anonymize_customer_not_logged_before:
customer_anonymized_count: client anonymisé.
anonymize_customers_not_logged_before:
label: Anonymiser tous les utlisateurs non connectés avant
anonymize_customer_without_any_orders:
label: Anonymiser tous les utilisateurs n'ayant jamais créé de commande avant
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
use Symfony\Component\Form\Forms;
use Synolia\SyliusGDPRPlugin\Form\Type\Actions\AnonymizeCustomersNotLoggedBeforeType;
use Synolia\SyliusGDPRPlugin\Processor\AdvancedActions\CompositeAdvancedActionsFormDataProcessor;
use Tests\Synolia\SyliusGDPRPlugin\PHPUnit\Processor\WithSessionTrait;

class AnonymizeCustomerNotLoggedBeforeProcessorTest extends KernelTestCase
{
use WithSessionTrait;

private ?EntityManagerInterface $manager = null;

protected function setUp(): void
Expand All @@ -32,6 +35,8 @@ protected function tearDown(): void

public function testAnonymizeCustomers(): void
{
$this->createSession();

/** @var array<int, ShopUserInterface> $shopUsers */
$shopUsers = static::getContainer()->get('sylius.repository.shop_user')->findAll();
$shopUsers[0]->setLastLogin(new \DateTime());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@
use Symfony\Component\Form\Forms;
use Synolia\SyliusGDPRPlugin\Form\Type\Actions\AnonymizeCustomersWithoutAnyOrdersBeforeType;
use Synolia\SyliusGDPRPlugin\Processor\AdvancedActions\CompositeAdvancedActionsFormDataProcessor;
use Tests\Synolia\SyliusGDPRPlugin\PHPUnit\Processor\WithSessionTrait;

class AnonymizeCustomerWithoutAnyOrdersBeforeProcessorTest extends KernelTestCase
{
use WithSessionTrait;

private ?EntityManagerInterface $manager = null;

protected function setUp(): void
Expand All @@ -33,6 +36,8 @@ protected function tearDown(): void

public function testAnonymizeCustomers(): void
{
$this->createSession();

/** @var array<int, CustomerInterface> $customers */
$customers = static::getContainer()->get('sylius.repository.customer')->findAll();
$customers[0]->setCreatedAt(new \DateTime());
Expand Down
22 changes: 22 additions & 0 deletions tests/PHPUnit/Processor/WithSessionTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Tests\Synolia\SyliusGDPRPlugin\PHPUnit\Processor;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;

trait WithSessionTrait
{
private function createSession(): void
{
/** @var \Symfony\Component\HttpFoundation\RequestStack $requestStack */
$requestStack = self::getContainer()->get(RequestStack::class);
$request = Request::createFromGlobals();
$request->setSession(new Session(new MockArraySessionStorage()));
$requestStack->push($request);
}
}

0 comments on commit 549f0e3

Please sign in to comment.