diff --git a/config/modules.php b/config/modules.php index a799714..95abc5b 100644 --- a/config/modules.php +++ b/config/modules.php @@ -10,6 +10,7 @@ declare(strict_types=1); use App\Module\Absence\AbsenceModule; use App\Module\Core\CoreModule; use App\Module\Directory\DirectoryModule; +use App\Module\Mail\MailModule; use App\Module\ProjectManagement\ProjectManagementModule; use App\Module\TimeTracking\TimeTrackingModule; @@ -19,4 +20,5 @@ return [ ProjectManagementModule::class, AbsenceModule::class, DirectoryModule::class, + MailModule::class, ]; diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index 9157f14..fdb5142 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -58,6 +58,11 @@ doctrine: is_bundle: false dir: '%kernel.project_dir%/src/Module/Directory/Domain/Entity' prefix: 'App\Module\Directory\Domain\Entity' + Mail: + type: attribute + is_bundle: false + dir: '%kernel.project_dir%/src/Module/Mail/Domain/Entity' + prefix: 'App\Module\Mail\Domain\Entity' controller_resolver: auto_mapping: false diff --git a/config/packages/messenger.yaml b/config/packages/messenger.yaml index 044057e..a8a9bf1 100644 --- a/config/packages/messenger.yaml +++ b/config/packages/messenger.yaml @@ -23,7 +23,7 @@ framework: # messenger:consume à maintenir. La sync de fond reste assurée par le cron OS # (app:mail:sync, synchrone, indépendant du bus). Repasser à `async` + worker si # la boîte grossit au point que la sync à la demande approche le timeout PHP. - 'App\Message\MailSyncRequested': sync + 'App\Module\Mail\Application\Message\MailSyncRequested': sync when@test: framework: diff --git a/config/services.yaml b/config/services.yaml index e3625b1..3900610 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -103,4 +103,14 @@ services: App\Module\Directory\Domain\Repository\ProspectRepositoryInterface: '@App\Module\Directory\Infrastructure\Doctrine\DoctrineProspectRepository' + App\Module\Mail\Domain\Repository\MailConfigurationRepositoryInterface: '@App\Module\Mail\Infrastructure\Doctrine\DoctrineMailConfigurationRepository' + + App\Module\Mail\Domain\Repository\MailFolderRepositoryInterface: '@App\Module\Mail\Infrastructure\Doctrine\DoctrineMailFolderRepository' + + App\Module\Mail\Domain\Repository\MailMessageRepositoryInterface: '@App\Module\Mail\Infrastructure\Doctrine\DoctrineMailMessageRepository' + + App\Module\Mail\Domain\Repository\TaskMailLinkRepositoryInterface: '@App\Module\Mail\Infrastructure\Doctrine\DoctrineTaskMailLinkRepository' + + App\Module\Mail\Domain\Provider\MailProviderInterface: '@App\Module\Mail\Infrastructure\Imap\ImapMailProvider' + App\Shared\Domain\Contract\NotifierInterface: '@App\Module\Core\Infrastructure\Notifier' diff --git a/migrations/Version20260620200000.php b/migrations/Version20260620200000.php new file mode 100644 index 0000000..f750e91 --- /dev/null +++ b/migrations/Version20260620200000.php @@ -0,0 +1,54 @@ + "user"(id) ON DELETE SET NULL (Blamable) + * No DROP/ALTER on existing data. Columns are lowercase snake_case. + * Hand-written to mirror the schema dump and guarantee zero destructive + * instruction. down() drops the new columns and their FKs/indexes. + */ +final class Version20260620200000 extends AbstractMigration +{ + public function getDescription(): string + { + return 'Mail: add Timestampable/Blamable columns on mail_configuration (additive)'; + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE mail_configuration ADD created_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL'); + $this->addSql('ALTER TABLE mail_configuration ADD updated_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL'); + $this->addSql('ALTER TABLE mail_configuration ADD created_by INT DEFAULT NULL'); + $this->addSql('ALTER TABLE mail_configuration ADD updated_by INT DEFAULT NULL'); + $this->addSql('ALTER TABLE mail_configuration ADD CONSTRAINT FK_BFC0A7DBDE12AB56 FOREIGN KEY (created_by) REFERENCES "user" (id) ON DELETE SET NULL NOT DEFERRABLE'); + $this->addSql('ALTER TABLE mail_configuration ADD CONSTRAINT FK_BFC0A7DB16FE72E1 FOREIGN KEY (updated_by) REFERENCES "user" (id) ON DELETE SET NULL NOT DEFERRABLE'); + $this->addSql('CREATE INDEX IDX_BFC0A7DBDE12AB56 ON mail_configuration (created_by)'); + $this->addSql('CREATE INDEX IDX_BFC0A7DB16FE72E1 ON mail_configuration (updated_by)'); + $this->addSql("COMMENT ON COLUMN mail_configuration.created_at IS 'Creation timestamp (Timestampable, set on prePersist)'"); + $this->addSql("COMMENT ON COLUMN mail_configuration.updated_at IS 'Last update timestamp (Timestampable, set on prePersist/preUpdate)'"); + $this->addSql("COMMENT ON COLUMN mail_configuration.created_by IS 'User who created the entry (Blamable, FK user.id, SET NULL on delete)'"); + $this->addSql("COMMENT ON COLUMN mail_configuration.updated_by IS 'User who last updated the entry (Blamable, FK user.id, SET NULL on delete)'"); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE mail_configuration DROP CONSTRAINT FK_BFC0A7DBDE12AB56'); + $this->addSql('ALTER TABLE mail_configuration DROP CONSTRAINT FK_BFC0A7DB16FE72E1'); + $this->addSql('DROP INDEX IDX_BFC0A7DBDE12AB56'); + $this->addSql('DROP INDEX IDX_BFC0A7DB16FE72E1'); + $this->addSql('ALTER TABLE mail_configuration DROP created_at'); + $this->addSql('ALTER TABLE mail_configuration DROP updated_at'); + $this->addSql('ALTER TABLE mail_configuration DROP created_by'); + $this->addSql('ALTER TABLE mail_configuration DROP updated_by'); + } +} diff --git a/src/DataFixtures/AppFixtures.php b/src/DataFixtures/AppFixtures.php index da9cfab..2cb0be1 100644 --- a/src/DataFixtures/AppFixtures.php +++ b/src/DataFixtures/AppFixtures.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace App\DataFixtures; -use App\Entity\MailConfiguration; use App\Entity\ZimbraConfiguration; use App\Enum\ContractType; use App\Module\Absence\Domain\Entity\AbsenceBalance; @@ -17,6 +16,7 @@ use App\Module\Core\Domain\Entity\User; use App\Module\Directory\Domain\Entity\Client; use App\Module\Directory\Domain\Entity\Prospect; use App\Module\Directory\Domain\Enum\ProspectStatus; +use App\Module\Mail\Domain\Entity\MailConfiguration; use App\Module\ProjectManagement\Domain\Entity\Project; use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\ProjectManagement\Domain\Entity\TaskEffort; diff --git a/src/Mail/Dto/MailAttachmentDto.php b/src/Module/Mail/Application/Dto/MailAttachmentDto.php similarity index 85% rename from src/Mail/Dto/MailAttachmentDto.php rename to src/Module/Mail/Application/Dto/MailAttachmentDto.php index cb6362a..ce7146c 100644 --- a/src/Mail/Dto/MailAttachmentDto.php +++ b/src/Module/Mail/Application/Dto/MailAttachmentDto.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Mail\Dto; +namespace App\Module\Mail\Application\Dto; final readonly class MailAttachmentDto { diff --git a/src/Mail/Dto/MailFolderDto.php b/src/Module/Mail/Application/Dto/MailFolderDto.php similarity index 86% rename from src/Mail/Dto/MailFolderDto.php rename to src/Module/Mail/Application/Dto/MailFolderDto.php index d6ff8ff..5069774 100644 --- a/src/Mail/Dto/MailFolderDto.php +++ b/src/Module/Mail/Application/Dto/MailFolderDto.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Mail\Dto; +namespace App\Module\Mail\Application\Dto; final readonly class MailFolderDto { diff --git a/src/Mail/Dto/MailMessageDetailDto.php b/src/Module/Mail/Application/Dto/MailMessageDetailDto.php similarity index 88% rename from src/Mail/Dto/MailMessageDetailDto.php rename to src/Module/Mail/Application/Dto/MailMessageDetailDto.php index 76462e7..68587ba 100644 --- a/src/Mail/Dto/MailMessageDetailDto.php +++ b/src/Module/Mail/Application/Dto/MailMessageDetailDto.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Mail\Dto; +namespace App\Module\Mail\Application\Dto; final readonly class MailMessageDetailDto { diff --git a/src/Mail/Dto/MailMessageHeaderDto.php b/src/Module/Mail/Application/Dto/MailMessageHeaderDto.php similarity index 92% rename from src/Mail/Dto/MailMessageHeaderDto.php rename to src/Module/Mail/Application/Dto/MailMessageHeaderDto.php index fe9d022..1418298 100644 --- a/src/Mail/Dto/MailMessageHeaderDto.php +++ b/src/Module/Mail/Application/Dto/MailMessageHeaderDto.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Mail\Dto; +namespace App\Module\Mail\Application\Dto; use DateTimeImmutable; diff --git a/src/Mail/Dto/MailSyncReport.php b/src/Module/Mail/Application/Dto/MailSyncReport.php similarity index 91% rename from src/Mail/Dto/MailSyncReport.php rename to src/Module/Mail/Application/Dto/MailSyncReport.php index cee124b..c1c5f1a 100644 --- a/src/Mail/Dto/MailSyncReport.php +++ b/src/Module/Mail/Application/Dto/MailSyncReport.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Mail\Dto; +namespace App\Module\Mail\Application\Dto; use DateTimeImmutable; diff --git a/src/Message/MailSyncRequested.php b/src/Module/Mail/Application/Message/MailSyncRequested.php similarity index 77% rename from src/Message/MailSyncRequested.php rename to src/Module/Mail/Application/Message/MailSyncRequested.php index 01ecb52..5c80a56 100644 --- a/src/Message/MailSyncRequested.php +++ b/src/Module/Mail/Application/Message/MailSyncRequested.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Message; +namespace App\Module\Mail\Application\Message; final readonly class MailSyncRequested { diff --git a/src/MessageHandler/MailSyncRequestedHandler.php b/src/Module/Mail/Application/MessageHandler/MailSyncRequestedHandler.php similarity index 85% rename from src/MessageHandler/MailSyncRequestedHandler.php rename to src/Module/Mail/Application/MessageHandler/MailSyncRequestedHandler.php index d76e32b..89168eb 100644 --- a/src/MessageHandler/MailSyncRequestedHandler.php +++ b/src/Module/Mail/Application/MessageHandler/MailSyncRequestedHandler.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace App\MessageHandler; +namespace App\Module\Mail\Application\MessageHandler; -use App\Message\MailSyncRequested; -use App\Repository\MailFolderRepository; -use App\Service\MailSyncService; +use App\Module\Mail\Application\Message\MailSyncRequested; +use App\Module\Mail\Application\Service\MailSyncService; +use App\Module\Mail\Domain\Repository\MailFolderRepositoryInterface; use Psr\Log\LoggerInterface; use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Throwable; @@ -16,7 +16,7 @@ final readonly class MailSyncRequestedHandler { public function __construct( private MailSyncService $mailSyncService, - private MailFolderRepository $folderRepository, + private MailFolderRepositoryInterface $folderRepository, private LoggerInterface $logger, ) {} diff --git a/src/Service/MailSyncService.php b/src/Module/Mail/Application/Service/MailSyncService.php similarity index 94% rename from src/Service/MailSyncService.php rename to src/Module/Mail/Application/Service/MailSyncService.php index 2d0e329..ba90b9d 100644 --- a/src/Service/MailSyncService.php +++ b/src/Module/Mail/Application/Service/MailSyncService.php @@ -2,16 +2,16 @@ declare(strict_types=1); -namespace App\Service; +namespace App\Module\Mail\Application\Service; -use App\Entity\MailFolder; -use App\Entity\MailMessage; -use App\Mail\Dto\MailSyncReport; -use App\Mail\Exception\MailProviderException; -use App\Mail\MailProviderInterface; -use App\Repository\MailConfigurationRepository; -use App\Repository\MailFolderRepository; -use App\Repository\MailMessageRepository; +use App\Module\Mail\Application\Dto\MailSyncReport; +use App\Module\Mail\Domain\Entity\MailFolder; +use App\Module\Mail\Domain\Entity\MailMessage; +use App\Module\Mail\Domain\Exception\MailProviderException; +use App\Module\Mail\Domain\Provider\MailProviderInterface; +use App\Module\Mail\Domain\Repository\MailConfigurationRepositoryInterface; +use App\Module\Mail\Domain\Repository\MailFolderRepositoryInterface; +use App\Module\Mail\Domain\Repository\MailMessageRepositoryInterface; use DateTimeImmutable; use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ManagerRegistry; @@ -27,9 +27,9 @@ final class MailSyncService public function __construct( private readonly MailProviderInterface $provider, - private readonly MailConfigurationRepository $configRepository, - private readonly MailFolderRepository $folderRepository, - private readonly MailMessageRepository $messageRepository, + private readonly MailConfigurationRepositoryInterface $configRepository, + private readonly MailFolderRepositoryInterface $folderRepository, + private readonly MailMessageRepositoryInterface $messageRepository, private readonly EntityManagerInterface $entityManager, private readonly LockFactory $lockFactory, private readonly LoggerInterface $logger, diff --git a/src/Entity/MailConfiguration.php b/src/Module/Mail/Domain/Entity/MailConfiguration.php similarity index 87% rename from src/Entity/MailConfiguration.php rename to src/Module/Mail/Domain/Entity/MailConfiguration.php index b1af5b1..c63b120 100644 --- a/src/Entity/MailConfiguration.php +++ b/src/Module/Mail/Domain/Entity/MailConfiguration.php @@ -2,15 +2,22 @@ declare(strict_types=1); -namespace App\Entity; +namespace App\Module\Mail\Domain\Entity; -use App\Repository\MailConfigurationRepository; +use App\Module\Mail\Infrastructure\Doctrine\DoctrineMailConfigurationRepository; +use App\Shared\Domain\Attribute\Auditable; +use App\Shared\Domain\Contract\BlamableInterface; +use App\Shared\Domain\Contract\TimestampableInterface; +use App\Shared\Domain\Trait\TimestampableBlamableTrait; use Doctrine\ORM\Mapping as ORM; -#[ORM\Entity(repositoryClass: MailConfigurationRepository::class)] +#[Auditable] +#[ORM\Entity(repositoryClass: DoctrineMailConfigurationRepository::class)] #[ORM\Table(name: 'mail_configuration')] -class MailConfiguration +class MailConfiguration implements TimestampableInterface, BlamableInterface { + use TimestampableBlamableTrait; + #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] diff --git a/src/Entity/MailFolder.php b/src/Module/Mail/Domain/Entity/MailFolder.php similarity index 92% rename from src/Entity/MailFolder.php rename to src/Module/Mail/Domain/Entity/MailFolder.php index 0b2462d..8131c48 100644 --- a/src/Entity/MailFolder.php +++ b/src/Module/Mail/Domain/Entity/MailFolder.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace App\Entity; +namespace App\Module\Mail\Domain\Entity; -use App\Repository\MailFolderRepository; +use App\Module\Mail\Infrastructure\Doctrine\DoctrineMailFolderRepository; use DateTimeImmutable; use Doctrine\ORM\Mapping as ORM; -#[ORM\Entity(repositoryClass: MailFolderRepository::class)] +#[ORM\Entity(repositoryClass: DoctrineMailFolderRepository::class)] #[ORM\Table(name: 'mail_folder')] #[ORM\Index(columns: ['parent_path'], name: 'idx_mail_folder_parent_path')] class MailFolder diff --git a/src/Entity/MailMessage.php b/src/Module/Mail/Domain/Entity/MailMessage.php similarity index 96% rename from src/Entity/MailMessage.php rename to src/Module/Mail/Domain/Entity/MailMessage.php index 8efee5f..711306d 100644 --- a/src/Entity/MailMessage.php +++ b/src/Module/Mail/Domain/Entity/MailMessage.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace App\Entity; +namespace App\Module\Mail\Domain\Entity; -use App\Repository\MailMessageRepository; +use App\Module\Mail\Infrastructure\Doctrine\DoctrineMailMessageRepository; use DateTimeImmutable; use Doctrine\ORM\Mapping as ORM; -#[ORM\Entity(repositoryClass: MailMessageRepository::class)] +#[ORM\Entity(repositoryClass: DoctrineMailMessageRepository::class)] #[ORM\Table(name: 'mail_message')] #[ORM\UniqueConstraint(name: 'uq_mail_message_folder_uid', columns: ['folder_id', 'uid'])] #[ORM\Index(columns: ['sent_at'], name: 'idx_mail_message_sent_at')] diff --git a/src/Entity/TaskMailLink.php b/src/Module/Mail/Domain/Entity/TaskMailLink.php similarity index 81% rename from src/Entity/TaskMailLink.php rename to src/Module/Mail/Domain/Entity/TaskMailLink.php index 9ef6364..a55ed8e 100644 --- a/src/Entity/TaskMailLink.php +++ b/src/Module/Mail/Domain/Entity/TaskMailLink.php @@ -2,15 +2,15 @@ declare(strict_types=1); -namespace App\Entity; +namespace App\Module\Mail\Domain\Entity; -use App\Module\ProjectManagement\Domain\Entity\Task; -use App\Repository\TaskMailLinkRepository; +use App\Module\Mail\Infrastructure\Doctrine\DoctrineTaskMailLinkRepository; +use App\Shared\Domain\Contract\TaskInterface; use App\Shared\Domain\Contract\UserInterface; use DateTimeImmutable; use Doctrine\ORM\Mapping as ORM; -#[ORM\Entity(repositoryClass: TaskMailLinkRepository::class)] +#[ORM\Entity(repositoryClass: DoctrineTaskMailLinkRepository::class)] #[ORM\Table(name: 'task_mail_link')] #[ORM\UniqueConstraint(name: 'uq_task_mail_link', columns: ['task_id', 'mail_message_id'])] class TaskMailLink @@ -20,9 +20,9 @@ class TaskMailLink #[ORM\Column] private ?int $id = null; - #[ORM\ManyToOne(targetEntity: Task::class)] + #[ORM\ManyToOne(targetEntity: TaskInterface::class)] #[ORM\JoinColumn(name: 'task_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')] - private Task $task; + private TaskInterface $task; #[ORM\ManyToOne(targetEntity: MailMessage::class)] #[ORM\JoinColumn(name: 'mail_message_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')] @@ -40,12 +40,12 @@ class TaskMailLink return $this->id; } - public function getTask(): Task + public function getTask(): TaskInterface { return $this->task; } - public function setTask(Task $task): static + public function setTask(TaskInterface $task): static { $this->task = $task; diff --git a/src/Mail/Exception/MailProviderException.php b/src/Module/Mail/Domain/Exception/MailProviderException.php similarity index 91% rename from src/Mail/Exception/MailProviderException.php rename to src/Module/Mail/Domain/Exception/MailProviderException.php index af4e6da..656d8a3 100644 --- a/src/Mail/Exception/MailProviderException.php +++ b/src/Module/Mail/Domain/Exception/MailProviderException.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Mail\Exception; +namespace App\Module\Mail\Domain\Exception; use RuntimeException; diff --git a/src/Mail/MailProviderInterface.php b/src/Module/Mail/Domain/Provider/MailProviderInterface.php similarity index 88% rename from src/Mail/MailProviderInterface.php rename to src/Module/Mail/Domain/Provider/MailProviderInterface.php index c233846..d5b698d 100644 --- a/src/Mail/MailProviderInterface.php +++ b/src/Module/Mail/Domain/Provider/MailProviderInterface.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace App\Mail; +namespace App\Module\Mail\Domain\Provider; -use App\Mail\Dto\MailFolderDto; -use App\Mail\Dto\MailMessageDetailDto; -use App\Mail\Dto\MailMessageHeaderDto; -use App\Mail\Exception\MailProviderException; +use App\Module\Mail\Application\Dto\MailFolderDto; +use App\Module\Mail\Application\Dto\MailMessageDetailDto; +use App\Module\Mail\Application\Dto\MailMessageHeaderDto; +use App\Module\Mail\Domain\Exception\MailProviderException; interface MailProviderInterface { diff --git a/src/Module/Mail/Domain/Repository/MailConfigurationRepositoryInterface.php b/src/Module/Mail/Domain/Repository/MailConfigurationRepositoryInterface.php new file mode 100644 index 0000000..479a5e1 --- /dev/null +++ b/src/Module/Mail/Domain/Repository/MailConfigurationRepositoryInterface.php @@ -0,0 +1,12 @@ + + */ + public function findAllOrderedByPath(): array; + + public function findByPath(string $path): ?MailFolder; +} diff --git a/src/Module/Mail/Domain/Repository/MailMessageRepositoryInterface.php b/src/Module/Mail/Domain/Repository/MailMessageRepositoryInterface.php new file mode 100644 index 0000000..b55a1b2 --- /dev/null +++ b/src/Module/Mail/Domain/Repository/MailMessageRepositoryInterface.php @@ -0,0 +1,49 @@ + + */ + public function findAll(): array; + + public function findByMessageId(string $messageId): ?MailMessage; + + public function findByFolderAndUid(MailFolder $folder, int $uid): ?MailMessage; + + /** + * @return list + */ + public function findByFolderPaginated(MailFolder $folder, int $limit, int $offset): array; + + public function countUnreadByFolder(MailFolder $folder): int; + + public function findMaxUidInFolder(MailFolder $folder): int; + + /** + * @return list + */ + public function findLastNByFolder(MailFolder $folder, int $limit): array; + + /** + * @return list + */ + public function findAllUidsByFolder(MailFolder $folder): array; + + /** + * Pagination cursor : retourne $limit messages apres le cursor (sentAt DESC, id DESC). + * Cursor format : base64url(sentAt_iso8601:id) - null pour la premiere page. + * + * @return array{messages: list, nextCursor: ?string} + */ + public function findByFolderCursor(MailFolder $folder, int $limit, ?string $cursor): array; +} diff --git a/src/Module/Mail/Domain/Repository/TaskMailLinkRepositoryInterface.php b/src/Module/Mail/Domain/Repository/TaskMailLinkRepositoryInterface.php new file mode 100644 index 0000000..092ecc0 --- /dev/null +++ b/src/Module/Mail/Domain/Repository/TaskMailLinkRepositoryInterface.php @@ -0,0 +1,24 @@ + + */ + public function findByTask(TaskInterface $task): array; + + public function findByTaskAndMessage(TaskInterface $task, MailMessage $message): ?TaskMailLink; + + /** + * @return list + */ + public function findByMessage(MailMessage $message): array; +} diff --git a/src/ApiResource/MailSettings.php b/src/Module/Mail/Infrastructure/ApiPlatform/Resource/MailSettings.php similarity index 90% rename from src/ApiResource/MailSettings.php rename to src/Module/Mail/Infrastructure/ApiPlatform/Resource/MailSettings.php index 615b9d1..aae9704 100644 --- a/src/ApiResource/MailSettings.php +++ b/src/Module/Mail/Infrastructure/ApiPlatform/Resource/MailSettings.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace App\ApiResource; +namespace App\Module\Mail\Infrastructure\ApiPlatform\Resource; use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\Patch; -use App\State\Mail\MailSettingsProcessor; -use App\State\Mail\MailSettingsProvider; +use App\Module\Mail\Infrastructure\ApiPlatform\State\MailSettingsProcessor; +use App\Module\Mail\Infrastructure\ApiPlatform\State\MailSettingsProvider; use Symfony\Component\Serializer\Attribute\Groups; #[ApiResource( diff --git a/src/State/Mail/MailSettingsProcessor.php b/src/Module/Mail/Infrastructure/ApiPlatform/State/MailSettingsProcessor.php similarity index 89% rename from src/State/Mail/MailSettingsProcessor.php rename to src/Module/Mail/Infrastructure/ApiPlatform/State/MailSettingsProcessor.php index 9b7a7df..c08f3de 100644 --- a/src/State/Mail/MailSettingsProcessor.php +++ b/src/Module/Mail/Infrastructure/ApiPlatform/State/MailSettingsProcessor.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace App\State\Mail; +namespace App\Module\Mail\Infrastructure\ApiPlatform\State; use ApiPlatform\Metadata\Operation; use ApiPlatform\State\ProcessorInterface; -use App\ApiResource\MailSettings; -use App\Entity\MailConfiguration; -use App\Repository\MailConfigurationRepository; +use App\Module\Mail\Domain\Entity\MailConfiguration; +use App\Module\Mail\Domain\Repository\MailConfigurationRepositoryInterface; +use App\Module\Mail\Infrastructure\ApiPlatform\Resource\MailSettings; use App\Service\TokenEncryptor; use Doctrine\ORM\EntityManagerInterface; @@ -16,7 +16,7 @@ final readonly class MailSettingsProcessor implements ProcessorInterface { public function __construct( private EntityManagerInterface $em, - private MailConfigurationRepository $configRepository, + private MailConfigurationRepositoryInterface $configRepository, private TokenEncryptor $tokenEncryptor, ) {} diff --git a/src/State/Mail/MailSettingsProvider.php b/src/Module/Mail/Infrastructure/ApiPlatform/State/MailSettingsProvider.php similarity index 80% rename from src/State/Mail/MailSettingsProvider.php rename to src/Module/Mail/Infrastructure/ApiPlatform/State/MailSettingsProvider.php index 9a60292..4274a69 100644 --- a/src/State/Mail/MailSettingsProvider.php +++ b/src/Module/Mail/Infrastructure/ApiPlatform/State/MailSettingsProvider.php @@ -2,17 +2,17 @@ declare(strict_types=1); -namespace App\State\Mail; +namespace App\Module\Mail\Infrastructure\ApiPlatform\State; use ApiPlatform\Metadata\Operation; use ApiPlatform\State\ProviderInterface; -use App\ApiResource\MailSettings; -use App\Repository\MailConfigurationRepository; +use App\Module\Mail\Domain\Repository\MailConfigurationRepositoryInterface; +use App\Module\Mail\Infrastructure\ApiPlatform\Resource\MailSettings; final readonly class MailSettingsProvider implements ProviderInterface { public function __construct( - private MailConfigurationRepository $configRepository, + private MailConfigurationRepositoryInterface $configRepository, ) {} public function provide(Operation $operation, array $uriVariables = [], array $context = []): MailSettings diff --git a/src/Command/MailRedecodeHeadersCommand.php b/src/Module/Mail/Infrastructure/Console/MailRedecodeHeadersCommand.php similarity index 90% rename from src/Command/MailRedecodeHeadersCommand.php rename to src/Module/Mail/Infrastructure/Console/MailRedecodeHeadersCommand.php index 5bb7f59..b4aaa9f 100644 --- a/src/Command/MailRedecodeHeadersCommand.php +++ b/src/Module/Mail/Infrastructure/Console/MailRedecodeHeadersCommand.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace App\Command; +namespace App\Module\Mail\Infrastructure\Console; -use App\Mail\MimeHeaderDecoder; -use App\Repository\MailMessageRepository; +use App\Module\Mail\Domain\Repository\MailMessageRepositoryInterface; +use App\Module\Mail\Infrastructure\Imap\MimeHeaderDecoder; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; @@ -21,7 +21,7 @@ use Symfony\Component\Console\Style\SymfonyStyle; final class MailRedecodeHeadersCommand extends Command { public function __construct( - private readonly MailMessageRepository $messageRepository, + private readonly MailMessageRepositoryInterface $messageRepository, private readonly EntityManagerInterface $entityManager, ) { parent::__construct(); diff --git a/src/Command/MailSyncCommand.php b/src/Module/Mail/Infrastructure/Console/MailSyncCommand.php similarity index 88% rename from src/Command/MailSyncCommand.php rename to src/Module/Mail/Infrastructure/Console/MailSyncCommand.php index 1f787af..517f806 100644 --- a/src/Command/MailSyncCommand.php +++ b/src/Module/Mail/Infrastructure/Console/MailSyncCommand.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace App\Command; +namespace App\Module\Mail\Infrastructure\Console; -use App\Repository\MailConfigurationRepository; -use App\Repository\MailFolderRepository; -use App\Service\MailSyncService; +use App\Module\Mail\Application\Service\MailSyncService; +use App\Module\Mail\Domain\Repository\MailConfigurationRepositoryInterface; +use App\Module\Mail\Domain\Repository\MailFolderRepositoryInterface; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -22,8 +22,8 @@ final class MailSyncCommand extends Command { public function __construct( private readonly MailSyncService $mailSyncService, - private readonly MailConfigurationRepository $configRepository, - private readonly MailFolderRepository $folderRepository, + private readonly MailConfigurationRepositoryInterface $configRepository, + private readonly MailFolderRepositoryInterface $folderRepository, ) { parent::__construct(); } diff --git a/src/Controller/Mail/MailAttachmentDownloadController.php b/src/Module/Mail/Infrastructure/Controller/MailAttachmentDownloadController.php similarity index 87% rename from src/Controller/Mail/MailAttachmentDownloadController.php rename to src/Module/Mail/Infrastructure/Controller/MailAttachmentDownloadController.php index f2be423..9a8ef2f 100644 --- a/src/Controller/Mail/MailAttachmentDownloadController.php +++ b/src/Module/Mail/Infrastructure/Controller/MailAttachmentDownloadController.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace App\Controller\Mail; +namespace App\Module\Mail\Infrastructure\Controller; -use App\Mail\Exception\MailProviderException; -use App\Mail\MailProviderInterface; -use App\Repository\MailMessageRepository; -use App\Security\MailAccessChecker; +use App\Module\Mail\Domain\Exception\MailProviderException; +use App\Module\Mail\Domain\Provider\MailProviderInterface; +use App\Module\Mail\Domain\Repository\MailMessageRepositoryInterface; +use App\Module\Mail\Infrastructure\Security\MailAccessChecker; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; @@ -20,7 +20,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class MailAttachmentDownloadController extends AbstractController { public function __construct( - private readonly MailMessageRepository $messageRepository, + private readonly MailMessageRepositoryInterface $messageRepository, private readonly MailProviderInterface $mailProvider, private readonly MailAccessChecker $accessChecker, ) {} @@ -37,7 +37,7 @@ class MailAttachmentDownloadController extends AbstractController [$messageDbIdStr, $partNumber] = explode(':', $decoded, 2); $messageDbId = (int) $messageDbIdStr; - $message = $this->messageRepository->find($messageDbId); + $message = $this->messageRepository->findById($messageDbId); if (null === $message) { throw new NotFoundHttpException('Message not found'); } diff --git a/src/Controller/Mail/MailCreateTaskController.php b/src/Module/Mail/Infrastructure/Controller/MailCreateTaskController.php similarity index 92% rename from src/Controller/Mail/MailCreateTaskController.php rename to src/Module/Mail/Infrastructure/Controller/MailCreateTaskController.php index 3c283ac..7a515d0 100644 --- a/src/Controller/Mail/MailCreateTaskController.php +++ b/src/Module/Mail/Infrastructure/Controller/MailCreateTaskController.php @@ -2,17 +2,17 @@ declare(strict_types=1); -namespace App\Controller\Mail; +namespace App\Module\Mail\Infrastructure\Controller; -use App\Entity\TaskMailLink; use App\Module\Core\Domain\Entity\User; +use App\Module\Mail\Domain\Entity\TaskMailLink; +use App\Module\Mail\Domain\Repository\MailMessageRepositoryInterface; +use App\Module\Mail\Infrastructure\Security\MailAccessChecker; use App\Module\ProjectManagement\Domain\Entity\Project; use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\ProjectManagement\Domain\Entity\TaskGroup; use App\Module\ProjectManagement\Domain\Entity\TaskStatus; use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface; -use App\Repository\MailMessageRepository; -use App\Security\MailAccessChecker; use DateTimeImmutable; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -28,7 +28,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class MailCreateTaskController extends AbstractController { public function __construct( - private readonly MailMessageRepository $messageRepository, + private readonly MailMessageRepositoryInterface $messageRepository, private readonly EntityManagerInterface $em, private readonly MailAccessChecker $accessChecker, private readonly TaskRepositoryInterface $taskRepository, @@ -38,7 +38,7 @@ class MailCreateTaskController extends AbstractController { $this->accessChecker->ensureCanAccessMail($this->getUser()); - $message = $this->messageRepository->find($id); + $message = $this->messageRepository->findById($id); if (null === $message) { throw new NotFoundHttpException('Message not found'); } diff --git a/src/Controller/Mail/MailFoldersListController.php b/src/Module/Mail/Infrastructure/Controller/MailFoldersListController.php similarity index 83% rename from src/Controller/Mail/MailFoldersListController.php rename to src/Module/Mail/Infrastructure/Controller/MailFoldersListController.php index 879ac19..3a91d6c 100644 --- a/src/Controller/Mail/MailFoldersListController.php +++ b/src/Module/Mail/Infrastructure/Controller/MailFoldersListController.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace App\Controller\Mail; +namespace App\Module\Mail\Infrastructure\Controller; -use App\Repository\MailFolderRepository; -use App\Security\MailAccessChecker; +use App\Module\Mail\Domain\Repository\MailFolderRepositoryInterface; +use App\Module\Mail\Infrastructure\Security\MailAccessChecker; use DateTimeInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; @@ -17,7 +17,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class MailFoldersListController extends AbstractController { public function __construct( - private readonly MailFolderRepository $folderRepository, + private readonly MailFolderRepositoryInterface $folderRepository, private readonly MailAccessChecker $accessChecker, ) {} diff --git a/src/Controller/Mail/MailLinkTaskController.php b/src/Module/Mail/Infrastructure/Controller/MailLinkTaskController.php similarity index 74% rename from src/Controller/Mail/MailLinkTaskController.php rename to src/Module/Mail/Infrastructure/Controller/MailLinkTaskController.php index 2cb3524..5496bc8 100644 --- a/src/Controller/Mail/MailLinkTaskController.php +++ b/src/Module/Mail/Infrastructure/Controller/MailLinkTaskController.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace App\Controller\Mail; +namespace App\Module\Mail\Infrastructure\Controller; -use App\Entity\TaskMailLink; -use App\Module\ProjectManagement\Domain\Entity\Task; -use App\Repository\MailMessageRepository; -use App\Repository\TaskMailLinkRepository; -use App\Security\MailAccessChecker; +use App\Module\Mail\Domain\Entity\TaskMailLink; +use App\Module\Mail\Domain\Repository\MailMessageRepositoryInterface; +use App\Module\Mail\Domain\Repository\TaskMailLinkRepositoryInterface; +use App\Module\Mail\Infrastructure\Security\MailAccessChecker; +use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface; use DateTimeImmutable; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -24,8 +24,9 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class MailLinkTaskController extends AbstractController { public function __construct( - private readonly MailMessageRepository $messageRepository, - private readonly TaskMailLinkRepository $linkRepository, + private readonly MailMessageRepositoryInterface $messageRepository, + private readonly TaskMailLinkRepositoryInterface $linkRepository, + private readonly TaskRepositoryInterface $taskRepository, private readonly EntityManagerInterface $em, private readonly MailAccessChecker $accessChecker, ) {} @@ -34,7 +35,7 @@ class MailLinkTaskController extends AbstractController { $this->accessChecker->ensureCanAccessMail($this->getUser()); - $message = $this->messageRepository->find($id); + $message = $this->messageRepository->findById($id); if (null === $message) { throw new NotFoundHttpException('Message not found'); } @@ -46,7 +47,7 @@ class MailLinkTaskController extends AbstractController throw new UnprocessableEntityHttpException('taskId is required'); } - $task = $this->em->getRepository(Task::class)->find($taskId); + $task = $this->taskRepository->findById((int) $taskId); if (null === $task) { throw new NotFoundHttpException('Task not found'); } diff --git a/src/Controller/Mail/MailMessageDetailController.php b/src/Module/Mail/Infrastructure/Controller/MailMessageDetailController.php similarity index 87% rename from src/Controller/Mail/MailMessageDetailController.php rename to src/Module/Mail/Infrastructure/Controller/MailMessageDetailController.php index c6a7e29..8fabc6b 100644 --- a/src/Controller/Mail/MailMessageDetailController.php +++ b/src/Module/Mail/Infrastructure/Controller/MailMessageDetailController.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace App\Controller\Mail; +namespace App\Module\Mail\Infrastructure\Controller; -use App\Mail\Exception\MailProviderException; -use App\Mail\MailProviderInterface; -use App\Repository\MailMessageRepository; -use App\Security\MailAccessChecker; +use App\Module\Mail\Domain\Exception\MailProviderException; +use App\Module\Mail\Domain\Provider\MailProviderInterface; +use App\Module\Mail\Domain\Repository\MailMessageRepositoryInterface; +use App\Module\Mail\Infrastructure\Security\MailAccessChecker; use DateTimeInterface; use Psr\Cache\CacheItemPoolInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -22,7 +22,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class MailMessageDetailController extends AbstractController { public function __construct( - private readonly MailMessageRepository $messageRepository, + private readonly MailMessageRepositoryInterface $messageRepository, private readonly MailProviderInterface $mailProvider, private readonly MailAccessChecker $accessChecker, private readonly CacheItemPoolInterface $cache, @@ -32,7 +32,7 @@ class MailMessageDetailController extends AbstractController { $this->accessChecker->ensureCanAccessMail($this->getUser()); - $message = $this->messageRepository->find($id); + $message = $this->messageRepository->findById($id); if (null === $message) { throw new NotFoundHttpException('Message not found'); } diff --git a/src/Controller/Mail/MailMessageFlagController.php b/src/Module/Mail/Infrastructure/Controller/MailMessageFlagController.php similarity index 78% rename from src/Controller/Mail/MailMessageFlagController.php rename to src/Module/Mail/Infrastructure/Controller/MailMessageFlagController.php index 262b13a..6eedfbe 100644 --- a/src/Controller/Mail/MailMessageFlagController.php +++ b/src/Module/Mail/Infrastructure/Controller/MailMessageFlagController.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace App\Controller\Mail; +namespace App\Module\Mail\Infrastructure\Controller; -use App\Mail\Exception\MailProviderException; -use App\Mail\MailProviderInterface; -use App\Repository\MailMessageRepository; -use App\Security\MailAccessChecker; +use App\Module\Mail\Domain\Exception\MailProviderException; +use App\Module\Mail\Domain\Provider\MailProviderInterface; +use App\Module\Mail\Domain\Repository\MailMessageRepositoryInterface; +use App\Module\Mail\Infrastructure\Security\MailAccessChecker; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; @@ -21,7 +21,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class MailMessageFlagController extends AbstractController { public function __construct( - private readonly MailMessageRepository $messageRepository, + private readonly MailMessageRepositoryInterface $messageRepository, private readonly MailProviderInterface $mailProvider, private readonly EntityManagerInterface $em, private readonly MailAccessChecker $accessChecker, @@ -31,7 +31,7 @@ class MailMessageFlagController extends AbstractController { $this->accessChecker->ensureCanAccessMail($this->getUser()); - $message = $this->messageRepository->find($id); + $message = $this->messageRepository->findById($id); if (null === $message) { throw new NotFoundHttpException('Message not found'); } diff --git a/src/Controller/Mail/MailMessageReadController.php b/src/Module/Mail/Infrastructure/Controller/MailMessageReadController.php similarity index 78% rename from src/Controller/Mail/MailMessageReadController.php rename to src/Module/Mail/Infrastructure/Controller/MailMessageReadController.php index 3ec9504..cc6ad7e 100644 --- a/src/Controller/Mail/MailMessageReadController.php +++ b/src/Module/Mail/Infrastructure/Controller/MailMessageReadController.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace App\Controller\Mail; +namespace App\Module\Mail\Infrastructure\Controller; -use App\Mail\Exception\MailProviderException; -use App\Mail\MailProviderInterface; -use App\Repository\MailMessageRepository; -use App\Security\MailAccessChecker; +use App\Module\Mail\Domain\Exception\MailProviderException; +use App\Module\Mail\Domain\Provider\MailProviderInterface; +use App\Module\Mail\Domain\Repository\MailMessageRepositoryInterface; +use App\Module\Mail\Infrastructure\Security\MailAccessChecker; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; @@ -21,7 +21,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class MailMessageReadController extends AbstractController { public function __construct( - private readonly MailMessageRepository $messageRepository, + private readonly MailMessageRepositoryInterface $messageRepository, private readonly MailProviderInterface $mailProvider, private readonly EntityManagerInterface $em, private readonly MailAccessChecker $accessChecker, @@ -31,7 +31,7 @@ class MailMessageReadController extends AbstractController { $this->accessChecker->ensureCanAccessMail($this->getUser()); - $message = $this->messageRepository->find($id); + $message = $this->messageRepository->findById($id); if (null === $message) { throw new NotFoundHttpException('Message not found'); } diff --git a/src/Controller/Mail/MailMessagesListController.php b/src/Module/Mail/Infrastructure/Controller/MailMessagesListController.php similarity index 84% rename from src/Controller/Mail/MailMessagesListController.php rename to src/Module/Mail/Infrastructure/Controller/MailMessagesListController.php index ccb4e02..1600164 100644 --- a/src/Controller/Mail/MailMessagesListController.php +++ b/src/Module/Mail/Infrastructure/Controller/MailMessagesListController.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace App\Controller\Mail; +namespace App\Module\Mail\Infrastructure\Controller; -use App\Repository\MailFolderRepository; -use App\Repository\MailMessageRepository; -use App\Security\MailAccessChecker; +use App\Module\Mail\Domain\Repository\MailFolderRepositoryInterface; +use App\Module\Mail\Domain\Repository\MailMessageRepositoryInterface; +use App\Module\Mail\Infrastructure\Security\MailAccessChecker; use DateTimeInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; @@ -20,8 +20,8 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class MailMessagesListController extends AbstractController { public function __construct( - private readonly MailFolderRepository $folderRepository, - private readonly MailMessageRepository $messageRepository, + private readonly MailFolderRepositoryInterface $folderRepository, + private readonly MailMessageRepositoryInterface $messageRepository, private readonly MailAccessChecker $accessChecker, ) {} diff --git a/src/Controller/Mail/MailSyncTriggerController.php b/src/Module/Mail/Infrastructure/Controller/MailSyncTriggerController.php similarity index 87% rename from src/Controller/Mail/MailSyncTriggerController.php rename to src/Module/Mail/Infrastructure/Controller/MailSyncTriggerController.php index 165293b..3d35524 100644 --- a/src/Controller/Mail/MailSyncTriggerController.php +++ b/src/Module/Mail/Infrastructure/Controller/MailSyncTriggerController.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace App\Controller\Mail; +namespace App\Module\Mail\Infrastructure\Controller; -use App\Message\MailSyncRequested; -use App\Security\MailAccessChecker; +use App\Module\Mail\Application\Message\MailSyncRequested; +use App\Module\Mail\Infrastructure\Security\MailAccessChecker; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; diff --git a/src/Controller/Mail/MailTestConnectionController.php b/src/Module/Mail/Infrastructure/Controller/MailTestConnectionController.php similarity index 88% rename from src/Controller/Mail/MailTestConnectionController.php rename to src/Module/Mail/Infrastructure/Controller/MailTestConnectionController.php index 6d25518..20d3f2d 100644 --- a/src/Controller/Mail/MailTestConnectionController.php +++ b/src/Module/Mail/Infrastructure/Controller/MailTestConnectionController.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace App\Controller\Mail; +namespace App\Module\Mail\Infrastructure\Controller; -use App\Mail\Exception\MailProviderException; -use App\Mail\MailProviderInterface; +use App\Module\Mail\Domain\Exception\MailProviderException; +use App\Module\Mail\Domain\Provider\MailProviderInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Routing\Attribute\Route; diff --git a/src/Controller/Mail/MailUnlinkTaskController.php b/src/Module/Mail/Infrastructure/Controller/MailUnlinkTaskController.php similarity index 69% rename from src/Controller/Mail/MailUnlinkTaskController.php rename to src/Module/Mail/Infrastructure/Controller/MailUnlinkTaskController.php index 09f646b..c7db3d0 100644 --- a/src/Controller/Mail/MailUnlinkTaskController.php +++ b/src/Module/Mail/Infrastructure/Controller/MailUnlinkTaskController.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace App\Controller\Mail; +namespace App\Module\Mail\Infrastructure\Controller; -use App\Module\ProjectManagement\Domain\Entity\Task; -use App\Repository\MailMessageRepository; -use App\Repository\TaskMailLinkRepository; -use App\Security\MailAccessChecker; +use App\Module\Mail\Domain\Repository\MailMessageRepositoryInterface; +use App\Module\Mail\Domain\Repository\TaskMailLinkRepositoryInterface; +use App\Module\Mail\Infrastructure\Security\MailAccessChecker; +use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; @@ -21,8 +21,9 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class MailUnlinkTaskController extends AbstractController { public function __construct( - private readonly MailMessageRepository $messageRepository, - private readonly TaskMailLinkRepository $linkRepository, + private readonly MailMessageRepositoryInterface $messageRepository, + private readonly TaskMailLinkRepositoryInterface $linkRepository, + private readonly TaskRepositoryInterface $taskRepository, private readonly EntityManagerInterface $em, private readonly MailAccessChecker $accessChecker, ) {} @@ -31,12 +32,12 @@ class MailUnlinkTaskController extends AbstractController { $this->accessChecker->ensureCanAccessMail($this->getUser()); - $message = $this->messageRepository->find($id); + $message = $this->messageRepository->findById($id); if (null === $message) { throw new NotFoundHttpException('Message not found'); } - $task = $this->em->getRepository(Task::class)->find($taskId); + $task = $this->taskRepository->findById($taskId); if (null === $task) { throw new NotFoundHttpException('Task not found'); } diff --git a/src/Controller/Mail/TaskMailsListController.php b/src/Module/Mail/Infrastructure/Controller/TaskMailsListController.php similarity index 79% rename from src/Controller/Mail/TaskMailsListController.php rename to src/Module/Mail/Infrastructure/Controller/TaskMailsListController.php index 8a9b0a4..b7f3975 100644 --- a/src/Controller/Mail/TaskMailsListController.php +++ b/src/Module/Mail/Infrastructure/Controller/TaskMailsListController.php @@ -2,13 +2,12 @@ declare(strict_types=1); -namespace App\Controller\Mail; +namespace App\Module\Mail\Infrastructure\Controller; -use App\Module\ProjectManagement\Domain\Entity\Task; -use App\Repository\TaskMailLinkRepository; -use App\Security\MailAccessChecker; +use App\Module\Mail\Domain\Repository\TaskMailLinkRepositoryInterface; +use App\Module\Mail\Infrastructure\Security\MailAccessChecker; +use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface; use DateTimeInterface; -use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -20,8 +19,8 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class TaskMailsListController extends AbstractController { public function __construct( - private readonly EntityManagerInterface $em, - private readonly TaskMailLinkRepository $linkRepository, + private readonly TaskRepositoryInterface $taskRepository, + private readonly TaskMailLinkRepositoryInterface $linkRepository, private readonly MailAccessChecker $accessChecker, ) {} @@ -29,7 +28,7 @@ class TaskMailsListController extends AbstractController { $this->accessChecker->ensureCanAccessMail($this->getUser()); - $task = $this->em->getRepository(Task::class)->find($id); + $task = $this->taskRepository->findById($id); if (null === $task) { throw new NotFoundHttpException('Task not found'); } diff --git a/src/Repository/MailConfigurationRepository.php b/src/Module/Mail/Infrastructure/Doctrine/DoctrineMailConfigurationRepository.php similarity index 58% rename from src/Repository/MailConfigurationRepository.php rename to src/Module/Mail/Infrastructure/Doctrine/DoctrineMailConfigurationRepository.php index 9be3993..8852d15 100644 --- a/src/Repository/MailConfigurationRepository.php +++ b/src/Module/Mail/Infrastructure/Doctrine/DoctrineMailConfigurationRepository.php @@ -2,13 +2,17 @@ declare(strict_types=1); -namespace App\Repository; +namespace App\Module\Mail\Infrastructure\Doctrine; -use App\Entity\MailConfiguration; +use App\Module\Mail\Domain\Entity\MailConfiguration; +use App\Module\Mail\Domain\Repository\MailConfigurationRepositoryInterface; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; -class MailConfigurationRepository extends ServiceEntityRepository +/** + * @extends ServiceEntityRepository + */ +class DoctrineMailConfigurationRepository extends ServiceEntityRepository implements MailConfigurationRepositoryInterface { public function __construct(ManagerRegistry $registry) { diff --git a/src/Repository/MailFolderRepository.php b/src/Module/Mail/Infrastructure/Doctrine/DoctrineMailFolderRepository.php similarity index 66% rename from src/Repository/MailFolderRepository.php rename to src/Module/Mail/Infrastructure/Doctrine/DoctrineMailFolderRepository.php index d228d35..662fd77 100644 --- a/src/Repository/MailFolderRepository.php +++ b/src/Module/Mail/Infrastructure/Doctrine/DoctrineMailFolderRepository.php @@ -2,13 +2,17 @@ declare(strict_types=1); -namespace App\Repository; +namespace App\Module\Mail\Infrastructure\Doctrine; -use App\Entity\MailFolder; +use App\Module\Mail\Domain\Entity\MailFolder; +use App\Module\Mail\Domain\Repository\MailFolderRepositoryInterface; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; -class MailFolderRepository extends ServiceEntityRepository +/** + * @extends ServiceEntityRepository + */ +class DoctrineMailFolderRepository extends ServiceEntityRepository implements MailFolderRepositoryInterface { public function __construct(ManagerRegistry $registry) { diff --git a/src/Repository/MailMessageRepository.php b/src/Module/Mail/Infrastructure/Doctrine/DoctrineMailMessageRepository.php similarity index 90% rename from src/Repository/MailMessageRepository.php rename to src/Module/Mail/Infrastructure/Doctrine/DoctrineMailMessageRepository.php index 78e07cd..f98c36b 100644 --- a/src/Repository/MailMessageRepository.php +++ b/src/Module/Mail/Infrastructure/Doctrine/DoctrineMailMessageRepository.php @@ -2,22 +2,31 @@ declare(strict_types=1); -namespace App\Repository; +namespace App\Module\Mail\Infrastructure\Doctrine; -use App\Entity\MailFolder; -use App\Entity\MailMessage; +use App\Module\Mail\Domain\Entity\MailFolder; +use App\Module\Mail\Domain\Entity\MailMessage; +use App\Module\Mail\Domain\Repository\MailMessageRepositoryInterface; use DateTimeImmutable; use DateTimeInterface; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; -class MailMessageRepository extends ServiceEntityRepository +/** + * @extends ServiceEntityRepository + */ +class DoctrineMailMessageRepository extends ServiceEntityRepository implements MailMessageRepositoryInterface { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, MailMessage::class); } + public function findById(int $id): ?MailMessage + { + return $this->find($id); + } + public function findByMessageId(string $messageId): ?MailMessage { return $this->findOneBy(['messageId' => $messageId]); diff --git a/src/Repository/TaskMailLinkRepository.php b/src/Module/Mail/Infrastructure/Doctrine/DoctrineTaskMailLinkRepository.php similarity index 59% rename from src/Repository/TaskMailLinkRepository.php rename to src/Module/Mail/Infrastructure/Doctrine/DoctrineTaskMailLinkRepository.php index da49bd5..68b4eb2 100644 --- a/src/Repository/TaskMailLinkRepository.php +++ b/src/Module/Mail/Infrastructure/Doctrine/DoctrineTaskMailLinkRepository.php @@ -2,15 +2,19 @@ declare(strict_types=1); -namespace App\Repository; +namespace App\Module\Mail\Infrastructure\Doctrine; -use App\Entity\MailMessage; -use App\Entity\TaskMailLink; -use App\Module\ProjectManagement\Domain\Entity\Task; +use App\Module\Mail\Domain\Entity\MailMessage; +use App\Module\Mail\Domain\Entity\TaskMailLink; +use App\Module\Mail\Domain\Repository\TaskMailLinkRepositoryInterface; +use App\Shared\Domain\Contract\TaskInterface; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; -class TaskMailLinkRepository extends ServiceEntityRepository +/** + * @extends ServiceEntityRepository + */ +class DoctrineTaskMailLinkRepository extends ServiceEntityRepository implements TaskMailLinkRepositoryInterface { public function __construct(ManagerRegistry $registry) { @@ -20,7 +24,7 @@ class TaskMailLinkRepository extends ServiceEntityRepository /** * @return list */ - public function findByTask(Task $task): array + public function findByTask(TaskInterface $task): array { return $this->createQueryBuilder('l') ->andWhere('l.task = :task') @@ -31,7 +35,7 @@ class TaskMailLinkRepository extends ServiceEntityRepository ; } - public function findByTaskAndMessage(Task $task, MailMessage $message): ?TaskMailLink + public function findByTaskAndMessage(TaskInterface $task, MailMessage $message): ?TaskMailLink { return $this->findOneBy(['task' => $task, 'mailMessage' => $message]); } diff --git a/src/Mail/ImapMailProvider.php b/src/Module/Mail/Infrastructure/Imap/ImapMailProvider.php similarity index 96% rename from src/Mail/ImapMailProvider.php rename to src/Module/Mail/Infrastructure/Imap/ImapMailProvider.php index 5db92c8..f08c35e 100644 --- a/src/Mail/ImapMailProvider.php +++ b/src/Module/Mail/Infrastructure/Imap/ImapMailProvider.php @@ -2,14 +2,15 @@ declare(strict_types=1); -namespace App\Mail; +namespace App\Module\Mail\Infrastructure\Imap; -use App\Mail\Dto\MailAttachmentDto; -use App\Mail\Dto\MailFolderDto; -use App\Mail\Dto\MailMessageDetailDto; -use App\Mail\Dto\MailMessageHeaderDto; -use App\Mail\Exception\MailProviderException; -use App\Repository\MailConfigurationRepository; +use App\Module\Mail\Application\Dto\MailAttachmentDto; +use App\Module\Mail\Application\Dto\MailFolderDto; +use App\Module\Mail\Application\Dto\MailMessageDetailDto; +use App\Module\Mail\Application\Dto\MailMessageHeaderDto; +use App\Module\Mail\Domain\Exception\MailProviderException; +use App\Module\Mail\Domain\Provider\MailProviderInterface; +use App\Module\Mail\Domain\Repository\MailConfigurationRepositoryInterface; use App\Service\TokenEncryptor; use DateTimeImmutable; use Psr\Log\LoggerInterface; @@ -24,7 +25,7 @@ final class ImapMailProvider implements MailProviderInterface private ?Client $client = null; public function __construct( - private readonly MailConfigurationRepository $configRepository, + private readonly MailConfigurationRepositoryInterface $configRepository, private readonly TokenEncryptor $tokenEncryptor, private readonly LoggerInterface $logger, ) {} diff --git a/src/Mail/MimeHeaderDecoder.php b/src/Module/Mail/Infrastructure/Imap/MimeHeaderDecoder.php similarity index 96% rename from src/Mail/MimeHeaderDecoder.php rename to src/Module/Mail/Infrastructure/Imap/MimeHeaderDecoder.php index 655282b..7809870 100644 --- a/src/Mail/MimeHeaderDecoder.php +++ b/src/Module/Mail/Infrastructure/Imap/MimeHeaderDecoder.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Mail; +namespace App\Module\Mail\Infrastructure\Imap; use const ICONV_MIME_DECODE_CONTINUE_ON_ERROR; diff --git a/src/Security/MailAccessChecker.php b/src/Module/Mail/Infrastructure/Security/MailAccessChecker.php similarity index 96% rename from src/Security/MailAccessChecker.php rename to src/Module/Mail/Infrastructure/Security/MailAccessChecker.php index 7055dbc..78e7f7a 100644 --- a/src/Security/MailAccessChecker.php +++ b/src/Module/Mail/Infrastructure/Security/MailAccessChecker.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Security; +namespace App\Module\Mail\Infrastructure\Security; use App\Shared\Domain\Contract\UserInterface as SharedUserInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; diff --git a/src/Module/Mail/MailModule.php b/src/Module/Mail/MailModule.php new file mode 100644 index 0000000..3d6b555 --- /dev/null +++ b/src/Module/Mail/MailModule.php @@ -0,0 +1,41 @@ + + */ + public static function permissions(): array + { + return [ + ['code' => 'mail.access', 'label' => 'Accéder à la messagerie'], + ['code' => 'mail.configure', 'label' => 'Configurer la messagerie'], + ]; + } +} diff --git a/tests/Functional/Controller/Mail/MailTaskIntegrationControllerTest.php b/tests/Functional/Controller/Mail/MailTaskIntegrationControllerTest.php index 5d37334..52322fe 100644 --- a/tests/Functional/Controller/Mail/MailTaskIntegrationControllerTest.php +++ b/tests/Functional/Controller/Mail/MailTaskIntegrationControllerTest.php @@ -4,9 +4,9 @@ declare(strict_types=1); namespace App\Tests\Functional\Controller\Mail; -use App\Entity\MailFolder; -use App\Entity\MailMessage; use App\Module\Core\Domain\Entity\User; +use App\Module\Mail\Domain\Entity\MailFolder; +use App\Module\Mail\Domain\Entity\MailMessage; use App\Module\ProjectManagement\Domain\Entity\Project; use App\Module\ProjectManagement\Domain\Entity\Task; use DateTimeImmutable; diff --git a/tests/Unit/Mail/ImapMailProviderTest.php b/tests/Unit/Mail/ImapMailProviderTest.php index 3720d35..be7982c 100644 --- a/tests/Unit/Mail/ImapMailProviderTest.php +++ b/tests/Unit/Mail/ImapMailProviderTest.php @@ -4,10 +4,10 @@ declare(strict_types=1); namespace App\Tests\Unit\Mail; -use App\Entity\MailConfiguration; -use App\Mail\Exception\MailProviderException; -use App\Mail\ImapMailProvider; -use App\Repository\MailConfigurationRepository; +use App\Module\Mail\Domain\Entity\MailConfiguration; +use App\Module\Mail\Domain\Exception\MailProviderException; +use App\Module\Mail\Domain\Repository\MailConfigurationRepositoryInterface; +use App\Module\Mail\Infrastructure\Imap\ImapMailProvider; use App\Service\TokenEncryptor; use PHPUnit\Framework\TestCase; use Psr\Log\NullLogger; @@ -22,7 +22,7 @@ class ImapMailProviderTest extends TestCase $config = new MailConfiguration(); $config->setEnabled(false); - $repo = $this->createMock(MailConfigurationRepository::class); + $repo = $this->createMock(MailConfigurationRepositoryInterface::class); $repo->method('findSingleton')->willReturn($config); $provider = new ImapMailProvider($repo, $this->makeEncryptor(), new NullLogger()); @@ -33,7 +33,7 @@ class ImapMailProviderTest extends TestCase public function testThrowsWhenConfigMissing(): void { - $repo = $this->createMock(MailConfigurationRepository::class); + $repo = $this->createMock(MailConfigurationRepositoryInterface::class); $repo->method('findSingleton')->willReturn(null); $provider = new ImapMailProvider($repo, $this->makeEncryptor(), new NullLogger()); diff --git a/tests/Unit/Mail/MailSyncReportTest.php b/tests/Unit/Mail/MailSyncReportTest.php index bea5283..032d5a2 100644 --- a/tests/Unit/Mail/MailSyncReportTest.php +++ b/tests/Unit/Mail/MailSyncReportTest.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Tests\Unit\Mail; -use App\Mail\Dto\MailSyncReport; +use App\Module\Mail\Application\Dto\MailSyncReport; use DateTimeImmutable; use PHPUnit\Framework\TestCase; diff --git a/tests/Unit/Mail/MimeHeaderDecoderTest.php b/tests/Unit/Mail/MimeHeaderDecoderTest.php index 75793e3..535b849 100644 --- a/tests/Unit/Mail/MimeHeaderDecoderTest.php +++ b/tests/Unit/Mail/MimeHeaderDecoderTest.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Tests\Unit\Mail; -use App\Mail\MimeHeaderDecoder; +use App\Module\Mail\Infrastructure\Imap\MimeHeaderDecoder; use PHPUnit\Framework\TestCase; /** diff --git a/tests/Unit/Repository/MailConfigurationRepositoryTest.php b/tests/Unit/Repository/MailConfigurationRepositoryTest.php index f903ee6..daec61c 100644 --- a/tests/Unit/Repository/MailConfigurationRepositoryTest.php +++ b/tests/Unit/Repository/MailConfigurationRepositoryTest.php @@ -4,8 +4,8 @@ declare(strict_types=1); namespace App\Tests\Unit\Repository; -use App\Entity\MailConfiguration; -use App\Repository\MailConfigurationRepository; +use App\Module\Mail\Domain\Entity\MailConfiguration; +use App\Module\Mail\Infrastructure\Doctrine\DoctrineMailConfigurationRepository; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; @@ -14,14 +14,14 @@ use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; */ class MailConfigurationRepositoryTest extends KernelTestCase { - private MailConfigurationRepository $repository; + private DoctrineMailConfigurationRepository $repository; private EntityManagerInterface $em; protected function setUp(): void { self::bootKernel(); $container = static::getContainer(); - $this->repository = $container->get(MailConfigurationRepository::class); + $this->repository = $container->get(DoctrineMailConfigurationRepository::class); $this->em = $container->get('doctrine.orm.entity_manager'); $this->em->getConnection()->executeStatement('TRUNCATE TABLE mail_configuration RESTART IDENTITY CASCADE'); } diff --git a/tests/Unit/Service/MailSyncServiceTest.php b/tests/Unit/Service/MailSyncServiceTest.php index 76abdf4..39c6eeb 100644 --- a/tests/Unit/Service/MailSyncServiceTest.php +++ b/tests/Unit/Service/MailSyncServiceTest.php @@ -4,14 +4,14 @@ declare(strict_types=1); namespace App\Tests\Unit\Service; -use App\Entity\MailConfiguration; -use App\Entity\MailFolder; -use App\Mail\Dto\MailFolderDto; -use App\Mail\MailProviderInterface; -use App\Repository\MailConfigurationRepository; -use App\Repository\MailFolderRepository; -use App\Repository\MailMessageRepository; -use App\Service\MailSyncService; +use App\Module\Mail\Application\Dto\MailFolderDto; +use App\Module\Mail\Application\Service\MailSyncService; +use App\Module\Mail\Domain\Entity\MailConfiguration; +use App\Module\Mail\Domain\Entity\MailFolder; +use App\Module\Mail\Domain\Provider\MailProviderInterface; +use App\Module\Mail\Domain\Repository\MailConfigurationRepositoryInterface; +use App\Module\Mail\Domain\Repository\MailFolderRepositoryInterface; +use App\Module\Mail\Domain\Repository\MailMessageRepositoryInterface; use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ManagerRegistry; use PHPUnit\Framework\TestCase; @@ -29,12 +29,12 @@ class MailSyncServiceTest extends TestCase $config = new MailConfiguration(); $config->setEnabled(false); - $configRepo = $this->createMock(MailConfigurationRepository::class); + $configRepo = $this->createMock(MailConfigurationRepositoryInterface::class); $configRepo->method('findSingleton')->willReturn($config); $provider = $this->createMock(MailProviderInterface::class); - $folderRepo = $this->createMock(MailFolderRepository::class); - $messageRepo = $this->createMock(MailMessageRepository::class); + $folderRepo = $this->createMock(MailFolderRepositoryInterface::class); + $messageRepo = $this->createMock(MailMessageRepositoryInterface::class); $em = $this->createMock(EntityManagerInterface::class); $lockFactory = $this->makeLockFactory(); @@ -62,12 +62,12 @@ class MailSyncServiceTest extends TestCase $config = new MailConfiguration(); $config->setEnabled(true); - $configRepo = $this->createMock(MailConfigurationRepository::class); + $configRepo = $this->createMock(MailConfigurationRepositoryInterface::class); $configRepo->method('findSingleton')->willReturn($config); $provider = $this->createMock(MailProviderInterface::class); - $folderRepo = $this->createMock(MailFolderRepository::class); - $messageRepo = $this->createMock(MailMessageRepository::class); + $folderRepo = $this->createMock(MailFolderRepositoryInterface::class); + $messageRepo = $this->createMock(MailMessageRepositoryInterface::class); $em = $this->createMock(EntityManagerInterface::class); $lockFactory = $this->makeLockFactory(false); @@ -93,7 +93,7 @@ class MailSyncServiceTest extends TestCase $config = new MailConfiguration(); $config->setEnabled(true); - $configRepo = $this->createMock(MailConfigurationRepository::class); + $configRepo = $this->createMock(MailConfigurationRepositoryInterface::class); $configRepo->method('findSingleton')->willReturn($config); $folderDto = new MailFolderDto( @@ -107,11 +107,11 @@ class MailSyncServiceTest extends TestCase $provider = $this->createMock(MailProviderInterface::class); $provider->method('listFolders')->willReturn([$folderDto]); - $folderRepo = $this->createMock(MailFolderRepository::class); + $folderRepo = $this->createMock(MailFolderRepositoryInterface::class); $folderRepo->method('findByPath')->willReturn(null); $folderRepo->method('findAllOrderedByPath')->willReturn([]); - $messageRepo = $this->createMock(MailMessageRepository::class); + $messageRepo = $this->createMock(MailMessageRepositoryInterface::class); $em = $this->createMock(EntityManagerInterface::class); $em->expects(self::once())->method('persist'); $em->expects(self::once())->method('flush'); @@ -137,13 +137,13 @@ class MailSyncServiceTest extends TestCase $config = new MailConfiguration(); $config->setEnabled(true); - $configRepo = $this->createMock(MailConfigurationRepository::class); + $configRepo = $this->createMock(MailConfigurationRepositoryInterface::class); $configRepo->method('findSingleton')->willReturn($config); $folder = new MailFolder(); $folder->setPath('INBOX'); - $messageRepo = $this->createMock(MailMessageRepository::class); + $messageRepo = $this->createMock(MailMessageRepositoryInterface::class); $messageRepo->method('findMaxUidInFolder')->willReturn(10); $messageRepo->method('findAllUidsByFolder')->willReturn([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); $messageRepo->method('findLastNByFolder')->willReturn([]); @@ -151,7 +151,7 @@ class MailSyncServiceTest extends TestCase $provider = $this->createMock(MailProviderInterface::class); $provider->method('listMessages')->willReturn([]); - $folderRepo = $this->createMock(MailFolderRepository::class); + $folderRepo = $this->createMock(MailFolderRepositoryInterface::class); $em = $this->createMock(EntityManagerInterface::class); $em->expects(self::never())->method('remove');