Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

* [PR-279](https://github.com/itk-dev/economics/pull/279)
Anonymize worklogs after 5 years.
* [PR-276](https://github.com/itk-dev/economics/pull/276)
Changed to use supercronic instead of woodpecker for crontabs.
* [PR-277](https://github.com/itk-dev/economics/pull/277)
Expand Down
3 changes: 3 additions & 0 deletions crontab.prod
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@

# Sync deleted every 15 minutes starting at 10 minutes past the hour
10,25,40,55 * * * * bin/console app:data-providers:sync-deleted

# Anonymize worklogs after 5 years, every night at 03:00
* 3 * * * bin/console app:anonymize-worklogs
3 changes: 3 additions & 0 deletions crontab.stg
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@

# Sync deleted every hour starting at 10 minutes past the hour
10 * * * * bin/console app:data-providers:sync-deleted

# Anonymize worklogs after 5 years, every night at 03:00
* 3 * * * bin/console app:anonymize-worklogs
31 changes: 31 additions & 0 deletions migrations/Version20260325094458.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260325094458 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}

public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE worklog ADD anonymized_date DATETIME DEFAULT NULL');
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE worklog DROP anonymized_date');
}
}
32 changes: 32 additions & 0 deletions src/Command/AnonymizeWorklogsCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace App\Command;

use App\Service\AnonymizeService;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(
name: 'app:anonymize-worklogs',
description: 'Anonymizes worklogs that are older than 5 years.',
)]
class AnonymizeWorklogsCommand extends Command
{
public function __construct(
private readonly AnonymizeService $anonymizeService,
) {
parent::__construct($this->getName());
}

#[\Override]
protected function execute(InputInterface $input, OutputInterface $output): int
{
$anonymizeBefore = (new \DateTime())->sub(new \DateInterval('P5Y'));

$this->anonymizeService->anonymizeWorklogs($anonymizeBefore);

return Command::SUCCESS;
}
}
22 changes: 22 additions & 0 deletions src/Entity/Trait/AnonymizedTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace App\Entity\Trait;

use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;

trait AnonymizedTrait
{
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $anonymizedDate = null;

public function getAnonymizedDate(): ?\DateTimeInterface
{
return $this->anonymizedDate;
}

public function setAnonymizedDate(?\DateTimeInterface $anonymizedDate): void
{
$this->anonymizedDate = $anonymizedDate;
}
}
2 changes: 2 additions & 0 deletions src/Entity/Worklog.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Entity;

use App\Entity\Trait\AnonymizedTrait;
use App\Entity\Trait\DataProviderTrait;
use App\Entity\Trait\SynchronizedEntityTrait;
use App\Enum\BillableKindsEnum;
Expand All @@ -19,6 +20,7 @@ class Worklog extends AbstractBaseEntity
{
use DataProviderTrait;
use SynchronizedEntityTrait;
use AnonymizedTrait;

// TODO: Rename to projectTrackerId.
#[ORM\Column]
Expand Down
16 changes: 16 additions & 0 deletions src/Repository/WorklogRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -296,4 +296,20 @@ public function getWorklogsAttachedToInvoiceInDateRange(\DateTimeInterface $peri
'paginator' => $paginator,
];
}

public function anonymizeWorklogs(\DateTimeInterface $anonymizeBefore): int
{
$qb = $this->createQueryBuilder('w');

$qb->update()
->set('w.description', 'CONCAT(:prefix, w.id)')
->set('w.anonymizedDate', ':now')
->where('w.started < :anonymizeBefore')
->andWhere('w.anonymizedDate IS NULL')
->setParameter('prefix', 'worklog ')
->setParameter('now', new \DateTime())
->setParameter('anonymizeBefore', $anonymizeBefore);

return $qb->getQuery()->execute();
}
}
17 changes: 17 additions & 0 deletions src/Service/AnonymizeService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace App\Service;

use App\Repository\WorklogRepository;

class AnonymizeService
{
public function __construct(private readonly WorklogRepository $worklogRepository)
{
}

public function anonymizeWorklogs(\DateTime $anonymizeBefore)
{
$this->worklogRepository->anonymizeWorklogs($anonymizeBefore);
}
}
6 changes: 5 additions & 1 deletion src/Service/DataProviderService.php
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,11 @@ public function upsertWorklog(DataProviderWorklogData $upsertWorklogData): void
}

$worklog->setWorklogId($upsertWorklogData->projectTrackerId);
$worklog->setDescription($upsertWorklogData->description);

if (null === $worklog->getAnonymizedDate()) {
$worklog->setDescription($upsertWorklogData->description);
}

$worklog->setWorker($upsertWorklogData->username);
$worklog->setStarted($upsertWorklogData->startedDate);
$worklog->setProjectTrackerIssueId($upsertWorklogData->projectTrackerIssueId);
Expand Down
Loading
Loading