feat(integration) : migrate Gitea/BookStack/Zimbra/Share into module (back)

LST-68 (2.6) backend. Behaviour-preserving move of the external integrations
into src/Module/Integration/. All 26 routes and securities unchanged.

- 5 entities (4 *Configuration singletons + TaskBookStackLink) + 5 repositories
  (Domain interfaces + Doctrine impls, bound). TaskBookStackLink.task now
  references TaskInterface (contract).
- Domain (FileSource interface, SharePathResolver, share DTOs + exceptions);
  Infrastructure (GiteaApiService, BookStackApiService, SmbFileSource, 15
  ApiResources, 21 State, 4 Share controllers).
- Cross-module couplings via abstractions: CalDavService (PM) injects
  ZimbraConfigurationRepositoryInterface; PM TaskDocument consumers repointed
  to the module's FileSource/SharePathResolver; Gitea/BookStack State load
  tasks via TaskRepositoryInterface (concrete Project read for integration
  fields — documented). ZimbraTestConnection keeps CalDavService (no build
  cycle). TokenEncryptor stays shared.
- IntegrationModule registered; doctrine mapping added.
- #[Auditable] + Timestampable on the 4 Configuration entities (additive
  migration on the 4 *_configuration tables).

163 tests green, container compiles (no cycle), no route regression, cs-fixer clean.
This commit is contained in:
Matthieu
2026-06-20 20:16:20 +02:00
parent bb7d7e7953
commit 90682e809c
79 changed files with 589 additions and 284 deletions
+2
View File
@@ -10,6 +10,7 @@ declare(strict_types=1);
use App\Module\Absence\AbsenceModule; use App\Module\Absence\AbsenceModule;
use App\Module\Core\CoreModule; use App\Module\Core\CoreModule;
use App\Module\Directory\DirectoryModule; use App\Module\Directory\DirectoryModule;
use App\Module\Integration\IntegrationModule;
use App\Module\Mail\MailModule; use App\Module\Mail\MailModule;
use App\Module\ProjectManagement\ProjectManagementModule; use App\Module\ProjectManagement\ProjectManagementModule;
use App\Module\TimeTracking\TimeTrackingModule; use App\Module\TimeTracking\TimeTrackingModule;
@@ -21,4 +22,5 @@ return [
AbsenceModule::class, AbsenceModule::class,
DirectoryModule::class, DirectoryModule::class,
MailModule::class, MailModule::class,
IntegrationModule::class,
]; ];
+5
View File
@@ -63,6 +63,11 @@ doctrine:
is_bundle: false is_bundle: false
dir: '%kernel.project_dir%/src/Module/Mail/Domain/Entity' dir: '%kernel.project_dir%/src/Module/Mail/Domain/Entity'
prefix: 'App\Module\Mail\Domain\Entity' prefix: 'App\Module\Mail\Domain\Entity'
Integration:
type: attribute
is_bundle: false
dir: '%kernel.project_dir%/src/Module/Integration/Domain/Entity'
prefix: 'App\Module\Integration\Domain\Entity'
controller_resolver: controller_resolver:
auto_mapping: false auto_mapping: false
+11 -1
View File
@@ -65,7 +65,17 @@ services:
arguments: arguments:
$uploadDir: '%absence_justification_upload_dir%' $uploadDir: '%absence_justification_upload_dir%'
App\Service\Share\FileSource: '@App\Service\Share\SmbFileSource' App\Module\Integration\Domain\Service\FileSource: '@App\Module\Integration\Infrastructure\Service\SmbFileSource'
App\Module\Integration\Domain\Repository\GiteaConfigurationRepositoryInterface: '@App\Module\Integration\Infrastructure\Doctrine\DoctrineGiteaConfigurationRepository'
App\Module\Integration\Domain\Repository\BookStackConfigurationRepositoryInterface: '@App\Module\Integration\Infrastructure\Doctrine\DoctrineBookStackConfigurationRepository'
App\Module\Integration\Domain\Repository\ZimbraConfigurationRepositoryInterface: '@App\Module\Integration\Infrastructure\Doctrine\DoctrineZimbraConfigurationRepository'
App\Module\Integration\Domain\Repository\ShareConfigurationRepositoryInterface: '@App\Module\Integration\Infrastructure\Doctrine\DoctrineShareConfigurationRepository'
App\Module\Integration\Domain\Repository\TaskBookStackLinkRepositoryInterface: '@App\Module\Integration\Infrastructure\Doctrine\DoctrineTaskBookStackLinkRepository'
App\Module\Core\Domain\Repository\UserRepositoryInterface: '@App\Module\Core\Infrastructure\Doctrine\DoctrineUserRepository' App\Module\Core\Domain\Repository\UserRepositoryInterface: '@App\Module\Core\Infrastructure\Doctrine\DoctrineUserRepository'
+125
View File
@@ -0,0 +1,125 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Integration module: add Timestampable + Blamable tracking on the four
* external-integration configuration tables (Gitea, BookStack, Zimbra, Share).
*
* Purely additive — adds nullable audit columns to existing tables:
* created_at / updated_at (Timestampable)
* created_by / updated_by -> "user"(id) ON DELETE SET NULL (Blamable)
* No DROP/ALTER on existing data. Columns are lowercase snake_case. FK/index
* names mirror Doctrine's generated identifiers so schema:validate stays clean.
* down() drops the new columns and their FKs/indexes.
*/
final class Version20260620201000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Integration: add Timestampable/Blamable columns on gitea/bookstack/zimbra/share configuration (additive)';
}
public function up(Schema $schema): void
{
// gitea_configuration
$this->addSql('ALTER TABLE gitea_configuration ADD created_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('ALTER TABLE gitea_configuration ADD updated_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('ALTER TABLE gitea_configuration ADD created_by INT DEFAULT NULL');
$this->addSql('ALTER TABLE gitea_configuration ADD updated_by INT DEFAULT NULL');
$this->addSql('ALTER TABLE gitea_configuration ADD CONSTRAINT FK_901AB3BDDE12AB56 FOREIGN KEY (created_by) REFERENCES "user" (id) ON DELETE SET NULL NOT DEFERRABLE');
$this->addSql('ALTER TABLE gitea_configuration ADD CONSTRAINT FK_901AB3BD16FE72E1 FOREIGN KEY (updated_by) REFERENCES "user" (id) ON DELETE SET NULL NOT DEFERRABLE');
$this->addSql('CREATE INDEX IDX_901AB3BDDE12AB56 ON gitea_configuration (created_by)');
$this->addSql('CREATE INDEX IDX_901AB3BD16FE72E1 ON gitea_configuration (updated_by)');
$this->addSql("COMMENT ON COLUMN gitea_configuration.created_at IS 'Creation timestamp (Timestampable, set on prePersist)'");
$this->addSql("COMMENT ON COLUMN gitea_configuration.updated_at IS 'Last update timestamp (Timestampable, set on prePersist/preUpdate)'");
$this->addSql("COMMENT ON COLUMN gitea_configuration.created_by IS 'User who created the entry (Blamable, FK user.id, SET NULL on delete)'");
$this->addSql("COMMENT ON COLUMN gitea_configuration.updated_by IS 'User who last updated the entry (Blamable, FK user.id, SET NULL on delete)'");
// book_stack_configuration
$this->addSql('ALTER TABLE book_stack_configuration ADD created_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('ALTER TABLE book_stack_configuration ADD updated_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('ALTER TABLE book_stack_configuration ADD created_by INT DEFAULT NULL');
$this->addSql('ALTER TABLE book_stack_configuration ADD updated_by INT DEFAULT NULL');
$this->addSql('ALTER TABLE book_stack_configuration ADD CONSTRAINT FK_63A143E0DE12AB56 FOREIGN KEY (created_by) REFERENCES "user" (id) ON DELETE SET NULL NOT DEFERRABLE');
$this->addSql('ALTER TABLE book_stack_configuration ADD CONSTRAINT FK_63A143E016FE72E1 FOREIGN KEY (updated_by) REFERENCES "user" (id) ON DELETE SET NULL NOT DEFERRABLE');
$this->addSql('CREATE INDEX IDX_63A143E0DE12AB56 ON book_stack_configuration (created_by)');
$this->addSql('CREATE INDEX IDX_63A143E016FE72E1 ON book_stack_configuration (updated_by)');
$this->addSql("COMMENT ON COLUMN book_stack_configuration.created_at IS 'Creation timestamp (Timestampable, set on prePersist)'");
$this->addSql("COMMENT ON COLUMN book_stack_configuration.updated_at IS 'Last update timestamp (Timestampable, set on prePersist/preUpdate)'");
$this->addSql("COMMENT ON COLUMN book_stack_configuration.created_by IS 'User who created the entry (Blamable, FK user.id, SET NULL on delete)'");
$this->addSql("COMMENT ON COLUMN book_stack_configuration.updated_by IS 'User who last updated the entry (Blamable, FK user.id, SET NULL on delete)'");
// zimbra_configuration
$this->addSql('ALTER TABLE zimbra_configuration ADD created_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('ALTER TABLE zimbra_configuration ADD updated_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('ALTER TABLE zimbra_configuration ADD created_by INT DEFAULT NULL');
$this->addSql('ALTER TABLE zimbra_configuration ADD updated_by INT DEFAULT NULL');
$this->addSql('ALTER TABLE zimbra_configuration ADD CONSTRAINT FK_E97E3357DE12AB56 FOREIGN KEY (created_by) REFERENCES "user" (id) ON DELETE SET NULL NOT DEFERRABLE');
$this->addSql('ALTER TABLE zimbra_configuration ADD CONSTRAINT FK_E97E335716FE72E1 FOREIGN KEY (updated_by) REFERENCES "user" (id) ON DELETE SET NULL NOT DEFERRABLE');
$this->addSql('CREATE INDEX IDX_E97E3357DE12AB56 ON zimbra_configuration (created_by)');
$this->addSql('CREATE INDEX IDX_E97E335716FE72E1 ON zimbra_configuration (updated_by)');
$this->addSql("COMMENT ON COLUMN zimbra_configuration.created_at IS 'Creation timestamp (Timestampable, set on prePersist)'");
$this->addSql("COMMENT ON COLUMN zimbra_configuration.updated_at IS 'Last update timestamp (Timestampable, set on prePersist/preUpdate)'");
$this->addSql("COMMENT ON COLUMN zimbra_configuration.created_by IS 'User who created the entry (Blamable, FK user.id, SET NULL on delete)'");
$this->addSql("COMMENT ON COLUMN zimbra_configuration.updated_by IS 'User who last updated the entry (Blamable, FK user.id, SET NULL on delete)'");
// share_configuration
$this->addSql('ALTER TABLE share_configuration ADD created_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('ALTER TABLE share_configuration ADD updated_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('ALTER TABLE share_configuration ADD created_by INT DEFAULT NULL');
$this->addSql('ALTER TABLE share_configuration ADD updated_by INT DEFAULT NULL');
$this->addSql('ALTER TABLE share_configuration ADD CONSTRAINT FK_F73FE5CDDE12AB56 FOREIGN KEY (created_by) REFERENCES "user" (id) ON DELETE SET NULL NOT DEFERRABLE');
$this->addSql('ALTER TABLE share_configuration ADD CONSTRAINT FK_F73FE5CD16FE72E1 FOREIGN KEY (updated_by) REFERENCES "user" (id) ON DELETE SET NULL NOT DEFERRABLE');
$this->addSql('CREATE INDEX IDX_F73FE5CDDE12AB56 ON share_configuration (created_by)');
$this->addSql('CREATE INDEX IDX_F73FE5CD16FE72E1 ON share_configuration (updated_by)');
$this->addSql("COMMENT ON COLUMN share_configuration.created_at IS 'Creation timestamp (Timestampable, set on prePersist)'");
$this->addSql("COMMENT ON COLUMN share_configuration.updated_at IS 'Last update timestamp (Timestampable, set on prePersist/preUpdate)'");
$this->addSql("COMMENT ON COLUMN share_configuration.created_by IS 'User who created the entry (Blamable, FK user.id, SET NULL on delete)'");
$this->addSql("COMMENT ON COLUMN share_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 gitea_configuration DROP CONSTRAINT FK_901AB3BDDE12AB56');
$this->addSql('ALTER TABLE gitea_configuration DROP CONSTRAINT FK_901AB3BD16FE72E1');
$this->addSql('DROP INDEX IDX_901AB3BDDE12AB56');
$this->addSql('DROP INDEX IDX_901AB3BD16FE72E1');
$this->addSql('ALTER TABLE gitea_configuration DROP created_at');
$this->addSql('ALTER TABLE gitea_configuration DROP updated_at');
$this->addSql('ALTER TABLE gitea_configuration DROP created_by');
$this->addSql('ALTER TABLE gitea_configuration DROP updated_by');
$this->addSql('ALTER TABLE book_stack_configuration DROP CONSTRAINT FK_63A143E0DE12AB56');
$this->addSql('ALTER TABLE book_stack_configuration DROP CONSTRAINT FK_63A143E016FE72E1');
$this->addSql('DROP INDEX IDX_63A143E0DE12AB56');
$this->addSql('DROP INDEX IDX_63A143E016FE72E1');
$this->addSql('ALTER TABLE book_stack_configuration DROP created_at');
$this->addSql('ALTER TABLE book_stack_configuration DROP updated_at');
$this->addSql('ALTER TABLE book_stack_configuration DROP created_by');
$this->addSql('ALTER TABLE book_stack_configuration DROP updated_by');
$this->addSql('ALTER TABLE zimbra_configuration DROP CONSTRAINT FK_E97E3357DE12AB56');
$this->addSql('ALTER TABLE zimbra_configuration DROP CONSTRAINT FK_E97E335716FE72E1');
$this->addSql('DROP INDEX IDX_E97E3357DE12AB56');
$this->addSql('DROP INDEX IDX_E97E335716FE72E1');
$this->addSql('ALTER TABLE zimbra_configuration DROP created_at');
$this->addSql('ALTER TABLE zimbra_configuration DROP updated_at');
$this->addSql('ALTER TABLE zimbra_configuration DROP created_by');
$this->addSql('ALTER TABLE zimbra_configuration DROP updated_by');
$this->addSql('ALTER TABLE share_configuration DROP CONSTRAINT FK_F73FE5CDDE12AB56');
$this->addSql('ALTER TABLE share_configuration DROP CONSTRAINT FK_F73FE5CD16FE72E1');
$this->addSql('DROP INDEX IDX_F73FE5CDDE12AB56');
$this->addSql('DROP INDEX IDX_F73FE5CD16FE72E1');
$this->addSql('ALTER TABLE share_configuration DROP created_at');
$this->addSql('ALTER TABLE share_configuration DROP updated_at');
$this->addSql('ALTER TABLE share_configuration DROP created_by');
$this->addSql('ALTER TABLE share_configuration DROP updated_by');
}
}
+1 -1
View File
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\DataFixtures; namespace App\DataFixtures;
use App\Entity\ZimbraConfiguration;
use App\Enum\ContractType; use App\Enum\ContractType;
use App\Module\Absence\Domain\Entity\AbsenceBalance; use App\Module\Absence\Domain\Entity\AbsenceBalance;
use App\Module\Absence\Domain\Entity\AbsencePolicy; use App\Module\Absence\Domain\Entity\AbsencePolicy;
@@ -16,6 +15,7 @@ use App\Module\Core\Domain\Entity\User;
use App\Module\Directory\Domain\Entity\Client; use App\Module\Directory\Domain\Entity\Client;
use App\Module\Directory\Domain\Entity\Prospect; use App\Module\Directory\Domain\Entity\Prospect;
use App\Module\Directory\Domain\Enum\ProspectStatus; use App\Module\Directory\Domain\Enum\ProspectStatus;
use App\Module\Integration\Domain\Entity\ZimbraConfiguration;
use App\Module\Mail\Domain\Entity\MailConfiguration; use App\Module\Mail\Domain\Entity\MailConfiguration;
use App\Module\ProjectManagement\Domain\Entity\Project; use App\Module\ProjectManagement\Domain\Entity\Project;
use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\ProjectManagement\Domain\Entity\Task;
@@ -2,15 +2,22 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Entity; namespace App\Module\Integration\Domain\Entity;
use App\Repository\BookStackConfigurationRepository; use App\Module\Integration\Infrastructure\Doctrine\DoctrineBookStackConfigurationRepository;
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; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: BookStackConfigurationRepository::class)] #[Auditable]
class BookStackConfiguration #[ORM\Entity(repositoryClass: DoctrineBookStackConfigurationRepository::class)]
class BookStackConfiguration implements TimestampableInterface, BlamableInterface
{ {
use TimestampableBlamableTrait;
#[ORM\Id] #[ORM\Id]
#[ORM\GeneratedValue] #[ORM\GeneratedValue]
#[ORM\Column] #[ORM\Column]
@@ -2,15 +2,22 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Entity; namespace App\Module\Integration\Domain\Entity;
use App\Repository\GiteaConfigurationRepository; use App\Module\Integration\Infrastructure\Doctrine\DoctrineGiteaConfigurationRepository;
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; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: GiteaConfigurationRepository::class)] #[Auditable]
class GiteaConfiguration #[ORM\Entity(repositoryClass: DoctrineGiteaConfigurationRepository::class)]
class GiteaConfiguration implements TimestampableInterface, BlamableInterface
{ {
use TimestampableBlamableTrait;
#[ORM\Id] #[ORM\Id]
#[ORM\GeneratedValue] #[ORM\GeneratedValue]
#[ORM\Column] #[ORM\Column]
@@ -2,14 +2,21 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Entity; namespace App\Module\Integration\Domain\Entity;
use App\Repository\ShareConfigurationRepository; use App\Module\Integration\Infrastructure\Doctrine\DoctrineShareConfigurationRepository;
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; use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: ShareConfigurationRepository::class)] #[Auditable]
class ShareConfiguration #[ORM\Entity(repositoryClass: DoctrineShareConfigurationRepository::class)]
class ShareConfiguration implements TimestampableInterface, BlamableInterface
{ {
use TimestampableBlamableTrait;
#[ORM\Id] #[ORM\Id]
#[ORM\GeneratedValue] #[ORM\GeneratedValue]
#[ORM\Column] #[ORM\Column]
@@ -2,15 +2,15 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Entity; namespace App\Module\Integration\Domain\Entity;
use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\Integration\Infrastructure\Doctrine\DoctrineTaskBookStackLinkRepository;
use App\Repository\TaskBookStackLinkRepository; use App\Shared\Domain\Contract\TaskInterface;
use DateTimeImmutable; use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: TaskBookStackLinkRepository::class)] #[ORM\Entity(repositoryClass: DoctrineTaskBookStackLinkRepository::class)]
#[ORM\UniqueConstraint(name: 'UNIQ_task_bookstack_link', columns: ['task_id', 'bookstack_id', 'bookstack_type'])] #[ORM\UniqueConstraint(name: 'UNIQ_task_bookstack_link', columns: ['task_id', 'bookstack_id', 'bookstack_type'])]
class TaskBookStackLink class TaskBookStackLink
{ {
@@ -19,9 +19,9 @@ class TaskBookStackLink
#[ORM\Column] #[ORM\Column]
private ?int $id = null; private ?int $id = null;
#[ORM\ManyToOne(targetEntity: Task::class)] #[ORM\ManyToOne(targetEntity: TaskInterface::class)]
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')] #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
private Task $task; private TaskInterface $task;
#[ORM\Column] #[ORM\Column]
private int $bookstackId; private int $bookstackId;
@@ -49,12 +49,12 @@ class TaskBookStackLink
return $this->id; return $this->id;
} }
public function getTask(): Task public function getTask(): TaskInterface
{ {
return $this->task; return $this->task;
} }
public function setTask(Task $task): static public function setTask(TaskInterface $task): static
{ {
$this->task = $task; $this->task = $task;
@@ -2,15 +2,22 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Entity; namespace App\Module\Integration\Domain\Entity;
use App\Repository\ZimbraConfigurationRepository; use App\Module\Integration\Infrastructure\Doctrine\DoctrineZimbraConfigurationRepository;
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; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: ZimbraConfigurationRepository::class)] #[Auditable]
class ZimbraConfiguration #[ORM\Entity(repositoryClass: DoctrineZimbraConfigurationRepository::class)]
class ZimbraConfiguration implements TimestampableInterface, BlamableInterface
{ {
use TimestampableBlamableTrait;
#[ORM\Id] #[ORM\Id]
#[ORM\GeneratedValue] #[ORM\GeneratedValue]
#[ORM\Column] #[ORM\Column]
@@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Exception; namespace App\Module\Integration\Domain\Exception;
use RuntimeException; use RuntimeException;
@@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Exception; namespace App\Module\Integration\Domain\Exception;
use RuntimeException; use RuntimeException;
@@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Service\Share\Exception; namespace App\Module\Integration\Domain\Exception;
use RuntimeException; use RuntimeException;
@@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Service\Share\Exception; namespace App\Module\Integration\Domain\Exception;
use RuntimeException; use RuntimeException;
@@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Service\Share\Exception; namespace App\Module\Integration\Domain\Exception;
use RuntimeException; use RuntimeException;
@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace App\Module\Integration\Domain\Repository;
use App\Module\Integration\Domain\Entity\BookStackConfiguration;
interface BookStackConfigurationRepositoryInterface
{
public function findSingleton(): ?BookStackConfiguration;
}
@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace App\Module\Integration\Domain\Repository;
use App\Module\Integration\Domain\Entity\GiteaConfiguration;
interface GiteaConfigurationRepositoryInterface
{
public function findSingleton(): ?GiteaConfiguration;
}
@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace App\Module\Integration\Domain\Repository;
use App\Module\Integration\Domain\Entity\ShareConfiguration;
interface ShareConfigurationRepositoryInterface
{
public function findSingleton(): ?ShareConfiguration;
}
@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace App\Module\Integration\Domain\Repository;
use App\Module\Integration\Domain\Entity\TaskBookStackLink;
interface TaskBookStackLinkRepositoryInterface
{
public function findById(int $id): ?TaskBookStackLink;
/**
* @return TaskBookStackLink[]
*/
public function findByTaskId(int $taskId): array;
}
@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace App\Module\Integration\Domain\Repository;
use App\Module\Integration\Domain\Entity\ZimbraConfiguration;
interface ZimbraConfigurationRepositoryInterface
{
public function findSingleton(): ?ZimbraConfiguration;
}
@@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Service\Share; namespace App\Module\Integration\Domain\Service;
final readonly class FileEntry final readonly class FileEntry
{ {
@@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Service\Share; namespace App\Module\Integration\Domain\Service;
interface FileSource interface FileSource
{ {
@@ -2,9 +2,9 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Service\Share; namespace App\Module\Integration\Domain\Service;
use App\Service\Share\Exception\InvalidPathException; use App\Module\Integration\Domain\Exception\InvalidPathException;
final class SharePathResolver final class SharePathResolver
{ {
@@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Service\Share; namespace App\Module\Integration\Domain\Service;
final readonly class ShareTestResult final readonly class ShareTestResult
{ {
@@ -2,17 +2,17 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete; use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\GetCollection; use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link; use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Post;
use App\Entity\TaskBookStackLink; use App\Module\Integration\Domain\Entity\TaskBookStackLink;
use App\Module\Integration\Infrastructure\ApiPlatform\State\BookStackLinkProcessor;
use App\Module\Integration\Infrastructure\ApiPlatform\State\BookStackLinkProvider;
use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\ProjectManagement\Domain\Entity\Task;
use App\State\BookStackLinkProcessor;
use App\State\BookStackLinkProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection; use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link; use ApiPlatform\Metadata\Link;
use App\Module\Integration\Infrastructure\ApiPlatform\State\BookStackSearchResultProvider;
use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\ProjectManagement\Domain\Entity\Task;
use App\State\BookStackSearchResultProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Put; use ApiPlatform\Metadata\Put;
use App\State\BookStackSettingsProcessor; use App\Module\Integration\Infrastructure\ApiPlatform\State\BookStackSettingsProcessor;
use App\State\BookStackSettingsProvider; use App\Module\Integration\Infrastructure\ApiPlatform\State\BookStackSettingsProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection; use ApiPlatform\Metadata\GetCollection;
use App\State\BookStackShelfProvider; use App\Module\Integration\Infrastructure\ApiPlatform\State\BookStackShelfProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Post;
use App\State\BookStackTestConnectionProvider; use App\Module\Integration\Infrastructure\ApiPlatform\State\BookStackTestConnectionProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection; use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Post;
use App\State\GiteaBranchProcessor; use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaBranchProcessor;
use App\State\GiteaBranchProvider; use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaBranchProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\Get;
use App\State\GiteaBranchNameProvider; use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaBranchNameProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection; use ApiPlatform\Metadata\GetCollection;
use App\State\GiteaPullRequestProvider; use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaPullRequestProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection; use ApiPlatform\Metadata\GetCollection;
use App\State\GiteaRepositoryProvider; use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaRepositoryProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Put; use ApiPlatform\Metadata\Put;
use App\State\GiteaSettingsProcessor; use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaSettingsProcessor;
use App\State\GiteaSettingsProvider; use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaSettingsProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Post;
use App\State\GiteaTestConnectionProvider; use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaTestConnectionProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Put; use ApiPlatform\Metadata\Put;
use App\State\ShareSettingsProcessor; use App\Module\Integration\Infrastructure\ApiPlatform\State\ShareSettingsProcessor;
use App\State\ShareSettingsProvider; use App\Module\Integration\Infrastructure\ApiPlatform\State\ShareSettingsProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Post;
use App\State\ShareTestConnectionProvider; use App\Module\Integration\Infrastructure\ApiPlatform\State\ShareTestConnectionProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Put; use ApiPlatform\Metadata\Put;
use App\State\ZimbraSettingsProcessor; use App\Module\Integration\Infrastructure\ApiPlatform\State\ZimbraSettingsProcessor;
use App\State\ZimbraSettingsProvider; use App\Module\Integration\Infrastructure\ApiPlatform\State\ZimbraSettingsProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\ApiResource; namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Post;
use App\State\ZimbraTestConnectionProvider; use App\Module\Integration\Infrastructure\ApiPlatform\State\ZimbraTestConnectionProvider;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource( #[ApiResource(
@@ -2,15 +2,15 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Delete; use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface; use ApiPlatform\State\ProcessorInterface;
use App\ApiResource\BookStackLink; use App\Module\Integration\Domain\Entity\TaskBookStackLink;
use App\Entity\TaskBookStackLink; use App\Module\Integration\Domain\Repository\TaskBookStackLinkRepositoryInterface;
use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackLink;
use App\Repository\TaskBookStackLinkRepository; use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -18,7 +18,8 @@ final readonly class BookStackLinkProcessor implements ProcessorInterface
{ {
public function __construct( public function __construct(
private EntityManagerInterface $em, private EntityManagerInterface $em,
private TaskBookStackLinkRepository $linkRepository, private TaskBookStackLinkRepositoryInterface $linkRepository,
private TaskRepositoryInterface $taskRepository,
) {} ) {}
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ?BookStackLink public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ?BookStackLink
@@ -35,7 +36,7 @@ final readonly class BookStackLinkProcessor implements ProcessorInterface
assert($data instanceof BookStackLink); assert($data instanceof BookStackLink);
$taskId = $uriVariables['taskId'] ?? 0; $taskId = $uriVariables['taskId'] ?? 0;
$task = $this->em->getRepository(Task::class)->find($taskId); $task = $this->taskRepository->findById((int) $taskId);
if (null === $task) { if (null === $task) {
throw new NotFoundHttpException('Task not found.'); throw new NotFoundHttpException('Task not found.');
@@ -65,7 +66,7 @@ final readonly class BookStackLinkProcessor implements ProcessorInterface
private function handleDelete(array $uriVariables): null private function handleDelete(array $uriVariables): null
{ {
$linkId = $uriVariables['id'] ?? 0; $linkId = $uriVariables['id'] ?? 0;
$link = $this->linkRepository->find($linkId); $link = $this->linkRepository->findById((int) $linkId);
if (null === $link) { if (null === $link) {
throw new NotFoundHttpException('Link not found.'); throw new NotFoundHttpException('Link not found.');
@@ -2,21 +2,21 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Delete; use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Post;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\BookStackLink; use App\Module\Integration\Domain\Entity\TaskBookStackLink;
use App\Entity\TaskBookStackLink; use App\Module\Integration\Domain\Repository\TaskBookStackLinkRepositoryInterface;
use App\Repository\TaskBookStackLinkRepository; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackLink;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
final readonly class BookStackLinkProvider implements ProviderInterface final readonly class BookStackLinkProvider implements ProviderInterface
{ {
public function __construct( public function __construct(
private TaskBookStackLinkRepository $linkRepository, private TaskBookStackLinkRepositoryInterface $linkRepository,
) {} ) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array|BookStackLink public function provide(Operation $operation, array $uriVariables = [], array $context = []): array|BookStackLink
@@ -2,15 +2,14 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\BookStackSearchResult; use App\Module\Integration\Domain\Exception\BookStackApiException;
use App\Exception\BookStackApiException; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackSearchResult;
use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\Integration\Infrastructure\Service\BookStackApiService;
use App\Service\BookStackApiService; use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
@@ -18,14 +17,14 @@ final readonly class BookStackSearchResultProvider implements ProviderInterface
{ {
public function __construct( public function __construct(
private BookStackApiService $bookStackApiService, private BookStackApiService $bookStackApiService,
private EntityManagerInterface $em, private TaskRepositoryInterface $taskRepository,
private RequestStack $requestStack, private RequestStack $requestStack,
) {} ) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
{ {
$taskId = $uriVariables['taskId'] ?? 0; $taskId = $uriVariables['taskId'] ?? 0;
$task = $this->em->getRepository(Task::class)->find($taskId); $task = $this->taskRepository->findById((int) $taskId);
if (null === $task || null === $task->getProject()) { if (null === $task || null === $task->getProject()) {
return []; return [];
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface; use ApiPlatform\State\ProcessorInterface;
use App\ApiResource\BookStackSettings; use App\Module\Integration\Domain\Entity\BookStackConfiguration;
use App\Entity\BookStackConfiguration; use App\Module\Integration\Domain\Repository\BookStackConfigurationRepositoryInterface;
use App\Repository\BookStackConfigurationRepository; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackSettings;
use App\Service\TokenEncryptor; use App\Service\TokenEncryptor;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
@@ -16,7 +16,7 @@ final readonly class BookStackSettingsProcessor implements ProcessorInterface
{ {
public function __construct( public function __construct(
private EntityManagerInterface $em, private EntityManagerInterface $em,
private BookStackConfigurationRepository $configRepository, private BookStackConfigurationRepositoryInterface $configRepository,
private TokenEncryptor $tokenEncryptor, private TokenEncryptor $tokenEncryptor,
) {} ) {}
@@ -2,17 +2,17 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\BookStackSettings; use App\Module\Integration\Domain\Repository\BookStackConfigurationRepositoryInterface;
use App\Repository\BookStackConfigurationRepository; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackSettings;
final readonly class BookStackSettingsProvider implements ProviderInterface final readonly class BookStackSettingsProvider implements ProviderInterface
{ {
public function __construct( public function __construct(
private BookStackConfigurationRepository $configRepository, private BookStackConfigurationRepositoryInterface $configRepository,
) {} ) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): BookStackSettings public function provide(Operation $operation, array $uriVariables = [], array $context = []): BookStackSettings
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\BookStackShelf; use App\Module\Integration\Domain\Exception\BookStackApiException;
use App\Exception\BookStackApiException; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackShelf;
use App\Service\BookStackApiService; use App\Module\Integration\Infrastructure\Service\BookStackApiService;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
final readonly class BookStackShelfProvider implements ProviderInterface final readonly class BookStackShelfProvider implements ProviderInterface
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface; use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\BookStackTestConnection; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackTestConnection;
use App\Service\BookStackApiService; use App\Module\Integration\Infrastructure\Service\BookStackApiService;
final readonly class BookStackTestConnectionProvider implements ProviderInterface, ProcessorInterface final readonly class BookStackTestConnectionProvider implements ProviderInterface, ProcessorInterface
{ {
@@ -2,14 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\GiteaBranchName; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaBranchName;
use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\Integration\Infrastructure\Service\GiteaApiService;
use App\Service\GiteaApiService; use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -20,12 +19,12 @@ final readonly class GiteaBranchNameProvider implements ProviderInterface
public function __construct( public function __construct(
private GiteaApiService $giteaApiService, private GiteaApiService $giteaApiService,
private EntityManagerInterface $em, private TaskRepositoryInterface $taskRepository,
) {} ) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): GiteaBranchName public function provide(Operation $operation, array $uriVariables = [], array $context = []): GiteaBranchName
{ {
$task = $this->em->getRepository(Task::class)->find($uriVariables['taskId'] ?? 0); $task = $this->taskRepository->findById((int) ($uriVariables['taskId'] ?? 0));
if (null === $task) { if (null === $task) {
throw new NotFoundHttpException('Task not found.'); throw new NotFoundHttpException('Task not found.');
} }
@@ -2,15 +2,14 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface; use ApiPlatform\State\ProcessorInterface;
use App\ApiResource\GiteaBranch; use App\Module\Integration\Domain\Exception\GiteaApiException;
use App\Exception\GiteaApiException; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaBranch;
use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\Integration\Infrastructure\Service\GiteaApiService;
use App\Service\GiteaApiService; use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -20,14 +19,14 @@ final readonly class GiteaBranchProcessor implements ProcessorInterface
public function __construct( public function __construct(
private GiteaApiService $giteaApiService, private GiteaApiService $giteaApiService,
private EntityManagerInterface $em, private TaskRepositoryInterface $taskRepository,
) {} ) {}
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): GiteaBranch public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): GiteaBranch
{ {
assert($data instanceof GiteaBranch); assert($data instanceof GiteaBranch);
$task = $this->em->getRepository(Task::class)->find($uriVariables['taskId'] ?? 0); $task = $this->taskRepository->findById((int) ($uriVariables['taskId'] ?? 0));
if (null === $task || null === $task->getProject()) { if (null === $task || null === $task->getProject()) {
throw new NotFoundHttpException('Task not found.'); throw new NotFoundHttpException('Task not found.');
} }
@@ -2,23 +2,22 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Post;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\GiteaBranch; use App\Module\Integration\Domain\Exception\GiteaApiException;
use App\Exception\GiteaApiException; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaBranch;
use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\Integration\Infrastructure\Service\GiteaApiService;
use App\Service\GiteaApiService; use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
final readonly class GiteaBranchProvider implements ProviderInterface final readonly class GiteaBranchProvider implements ProviderInterface
{ {
public function __construct( public function __construct(
private GiteaApiService $giteaApiService, private GiteaApiService $giteaApiService,
private EntityManagerInterface $em, private TaskRepositoryInterface $taskRepository,
) {} ) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array|GiteaBranch public function provide(Operation $operation, array $uriVariables = [], array $context = []): array|GiteaBranch
@@ -27,7 +26,7 @@ final readonly class GiteaBranchProvider implements ProviderInterface
return new GiteaBranch(); return new GiteaBranch();
} }
$task = $this->em->getRepository(Task::class)->find($uriVariables['taskId'] ?? 0); $task = $this->taskRepository->findById((int) ($uriVariables['taskId'] ?? 0));
if (null === $task || null === $task->getProject()) { if (null === $task || null === $task->getProject()) {
return []; return [];
} }
@@ -2,27 +2,26 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\GiteaPullRequest; use App\Module\Integration\Domain\Exception\GiteaApiException;
use App\Exception\GiteaApiException; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaPullRequest;
use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\Integration\Infrastructure\Service\GiteaApiService;
use App\Service\GiteaApiService; use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
final readonly class GiteaPullRequestProvider implements ProviderInterface final readonly class GiteaPullRequestProvider implements ProviderInterface
{ {
public function __construct( public function __construct(
private GiteaApiService $giteaApiService, private GiteaApiService $giteaApiService,
private EntityManagerInterface $em, private TaskRepositoryInterface $taskRepository,
) {} ) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
{ {
$task = $this->em->getRepository(Task::class)->find($uriVariables['taskId'] ?? 0); $task = $this->taskRepository->findById((int) ($uriVariables['taskId'] ?? 0));
if (null === $task || null === $task->getProject()) { if (null === $task || null === $task->getProject()) {
return []; return [];
} }
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\GiteaRepository; use App\Module\Integration\Domain\Exception\GiteaApiException;
use App\Exception\GiteaApiException; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaRepository;
use App\Service\GiteaApiService; use App\Module\Integration\Infrastructure\Service\GiteaApiService;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
final readonly class GiteaRepositoryProvider implements ProviderInterface final readonly class GiteaRepositoryProvider implements ProviderInterface
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface; use ApiPlatform\State\ProcessorInterface;
use App\ApiResource\GiteaSettings; use App\Module\Integration\Domain\Entity\GiteaConfiguration;
use App\Entity\GiteaConfiguration; use App\Module\Integration\Domain\Repository\GiteaConfigurationRepositoryInterface;
use App\Repository\GiteaConfigurationRepository; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaSettings;
use App\Service\TokenEncryptor; use App\Service\TokenEncryptor;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
@@ -16,7 +16,7 @@ final readonly class GiteaSettingsProcessor implements ProcessorInterface
{ {
public function __construct( public function __construct(
private EntityManagerInterface $em, private EntityManagerInterface $em,
private GiteaConfigurationRepository $configRepository, private GiteaConfigurationRepositoryInterface $configRepository,
private TokenEncryptor $tokenEncryptor, private TokenEncryptor $tokenEncryptor,
) {} ) {}
@@ -2,17 +2,17 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\GiteaSettings; use App\Module\Integration\Domain\Repository\GiteaConfigurationRepositoryInterface;
use App\Repository\GiteaConfigurationRepository; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaSettings;
final readonly class GiteaSettingsProvider implements ProviderInterface final readonly class GiteaSettingsProvider implements ProviderInterface
{ {
public function __construct( public function __construct(
private GiteaConfigurationRepository $configRepository, private GiteaConfigurationRepositoryInterface $configRepository,
) {} ) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): GiteaSettings public function provide(Operation $operation, array $uriVariables = [], array $context = []): GiteaSettings
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface; use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\GiteaTestConnection; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaTestConnection;
use App\Service\GiteaApiService; use App\Module\Integration\Infrastructure\Service\GiteaApiService;
final readonly class GiteaTestConnectionProvider implements ProviderInterface, ProcessorInterface final readonly class GiteaTestConnectionProvider implements ProviderInterface, ProcessorInterface
{ {
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface; use ApiPlatform\State\ProcessorInterface;
use App\ApiResource\ShareSettings; use App\Module\Integration\Domain\Entity\ShareConfiguration;
use App\Entity\ShareConfiguration; use App\Module\Integration\Domain\Repository\ShareConfigurationRepositoryInterface;
use App\Repository\ShareConfigurationRepository; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\ShareSettings;
use App\Service\TokenEncryptor; use App\Service\TokenEncryptor;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
@@ -16,7 +16,7 @@ final readonly class ShareSettingsProcessor implements ProcessorInterface
{ {
public function __construct( public function __construct(
private EntityManagerInterface $em, private EntityManagerInterface $em,
private ShareConfigurationRepository $configRepository, private ShareConfigurationRepositoryInterface $configRepository,
private TokenEncryptor $tokenEncryptor, private TokenEncryptor $tokenEncryptor,
) {} ) {}
@@ -2,17 +2,17 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\ShareSettings; use App\Module\Integration\Domain\Repository\ShareConfigurationRepositoryInterface;
use App\Repository\ShareConfigurationRepository; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\ShareSettings;
final readonly class ShareSettingsProvider implements ProviderInterface final readonly class ShareSettingsProvider implements ProviderInterface
{ {
public function __construct( public function __construct(
private ShareConfigurationRepository $configRepository, private ShareConfigurationRepositoryInterface $configRepository,
) {} ) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ShareSettings public function provide(Operation $operation, array $uriVariables = [], array $context = []): ShareSettings
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface; use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\ShareTestConnection; use App\Module\Integration\Domain\Service\FileSource;
use App\Service\Share\FileSource; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\ShareTestConnection;
final readonly class ShareTestConnectionProvider implements ProviderInterface, ProcessorInterface final readonly class ShareTestConnectionProvider implements ProviderInterface, ProcessorInterface
{ {
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface; use ApiPlatform\State\ProcessorInterface;
use App\ApiResource\ZimbraSettings; use App\Module\Integration\Domain\Entity\ZimbraConfiguration;
use App\Entity\ZimbraConfiguration; use App\Module\Integration\Domain\Repository\ZimbraConfigurationRepositoryInterface;
use App\Repository\ZimbraConfigurationRepository; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\ZimbraSettings;
use App\Service\TokenEncryptor; use App\Service\TokenEncryptor;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
@@ -16,7 +16,7 @@ final readonly class ZimbraSettingsProcessor implements ProcessorInterface
{ {
public function __construct( public function __construct(
private EntityManagerInterface $em, private EntityManagerInterface $em,
private ZimbraConfigurationRepository $configRepository, private ZimbraConfigurationRepositoryInterface $configRepository,
private TokenEncryptor $tokenEncryptor, private TokenEncryptor $tokenEncryptor,
) {} ) {}
@@ -2,17 +2,17 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\ZimbraSettings; use App\Module\Integration\Domain\Repository\ZimbraConfigurationRepositoryInterface;
use App\Repository\ZimbraConfigurationRepository; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\ZimbraSettings;
final readonly class ZimbraSettingsProvider implements ProviderInterface final readonly class ZimbraSettingsProvider implements ProviderInterface
{ {
public function __construct( public function __construct(
private ZimbraConfigurationRepository $configRepository, private ZimbraConfigurationRepositoryInterface $configRepository,
) {} ) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ZimbraSettings public function provide(Operation $operation, array $uriVariables = [], array $context = []): ZimbraSettings
@@ -2,12 +2,12 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\State; namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface; use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\State\ProviderInterface; use ApiPlatform\State\ProviderInterface;
use App\ApiResource\ZimbraTestConnection; use App\Module\Integration\Infrastructure\ApiPlatform\Resource\ZimbraTestConnection;
use App\Module\ProjectManagement\Infrastructure\Service\CalDavService; use App\Module\ProjectManagement\Infrastructure\Service\CalDavService;
use Throwable; use Throwable;
@@ -2,14 +2,14 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Controller\Share; namespace App\Module\Integration\Infrastructure\Controller;
use App\Service\Share\Exception\InvalidPathException; use App\Module\Integration\Domain\Exception\InvalidPathException;
use App\Service\Share\Exception\ShareConnectionException; use App\Module\Integration\Domain\Exception\ShareConnectionException;
use App\Service\Share\Exception\ShareNotConfiguredException; use App\Module\Integration\Domain\Exception\ShareNotConfiguredException;
use App\Service\Share\FileEntry; use App\Module\Integration\Domain\Service\FileEntry;
use App\Service\Share\FileSource; use App\Module\Integration\Domain\Service\FileSource;
use App\Service\Share\SharePathResolver; use App\Module\Integration\Domain\Service\SharePathResolver;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@@ -2,13 +2,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Controller\Share; namespace App\Module\Integration\Infrastructure\Controller;
use App\Service\Share\Exception\InvalidPathException; use App\Module\Integration\Domain\Exception\InvalidPathException;
use App\Service\Share\Exception\ShareConnectionException; use App\Module\Integration\Domain\Exception\ShareConnectionException;
use App\Service\Share\Exception\ShareNotConfiguredException; use App\Module\Integration\Domain\Exception\ShareNotConfiguredException;
use App\Service\Share\FileSource; use App\Module\Integration\Domain\Service\FileSource;
use App\Service\Share\SharePathResolver; use App\Module\Integration\Domain\Service\SharePathResolver;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\HeaderUtils; use Symfony\Component\HttpFoundation\HeaderUtils;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@@ -2,12 +2,12 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Controller\Share; namespace App\Module\Integration\Infrastructure\Controller;
use App\Service\Share\Exception\ShareConnectionException; use App\Module\Integration\Domain\Exception\ShareConnectionException;
use App\Service\Share\Exception\ShareNotConfiguredException; use App\Module\Integration\Domain\Exception\ShareNotConfiguredException;
use App\Service\Share\FileEntry; use App\Module\Integration\Domain\Service\FileEntry;
use App\Service\Share\FileSource; use App\Module\Integration\Domain\Service\FileSource;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@@ -2,9 +2,9 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Controller\Share; namespace App\Module\Integration\Infrastructure\Controller;
use App\Repository\ShareConfigurationRepository; use App\Module\Integration\Domain\Repository\ShareConfigurationRepositoryInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Attribute\Route;
@@ -13,7 +13,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
class ShareStatusController extends AbstractController class ShareStatusController extends AbstractController
{ {
public function __construct( public function __construct(
private readonly ShareConfigurationRepository $configRepository, private readonly ShareConfigurationRepositoryInterface $configRepository,
) {} ) {}
#[Route('/api/share/status', name: 'share_status', methods: ['GET'], priority: 1)] #[Route('/api/share/status', name: 'share_status', methods: ['GET'], priority: 1)]
@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace App\Module\Integration\Infrastructure\Doctrine;
use App\Module\Integration\Domain\Entity\BookStackConfiguration;
use App\Module\Integration\Domain\Repository\BookStackConfigurationRepositoryInterface;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<BookStackConfiguration>
*/
class DoctrineBookStackConfigurationRepository extends ServiceEntityRepository implements BookStackConfigurationRepositoryInterface
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, BookStackConfiguration::class);
}
public function findSingleton(): ?BookStackConfiguration
{
return $this->findOneBy([]);
}
}
@@ -2,13 +2,17 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Repository; namespace App\Module\Integration\Infrastructure\Doctrine;
use App\Entity\GiteaConfiguration; use App\Module\Integration\Domain\Entity\GiteaConfiguration;
use App\Module\Integration\Domain\Repository\GiteaConfigurationRepositoryInterface;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
class GiteaConfigurationRepository extends ServiceEntityRepository /**
* @extends ServiceEntityRepository<GiteaConfiguration>
*/
class DoctrineGiteaConfigurationRepository extends ServiceEntityRepository implements GiteaConfigurationRepositoryInterface
{ {
public function __construct(ManagerRegistry $registry) public function __construct(ManagerRegistry $registry)
{ {
@@ -2,13 +2,17 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Repository; namespace App\Module\Integration\Infrastructure\Doctrine;
use App\Entity\ShareConfiguration; use App\Module\Integration\Domain\Entity\ShareConfiguration;
use App\Module\Integration\Domain\Repository\ShareConfigurationRepositoryInterface;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
class ShareConfigurationRepository extends ServiceEntityRepository /**
* @extends ServiceEntityRepository<ShareConfiguration>
*/
class DoctrineShareConfigurationRepository extends ServiceEntityRepository implements ShareConfigurationRepositoryInterface
{ {
public function __construct(ManagerRegistry $registry) public function __construct(ManagerRegistry $registry)
{ {
@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace App\Module\Integration\Infrastructure\Doctrine;
use App\Module\Integration\Domain\Entity\TaskBookStackLink;
use App\Module\Integration\Domain\Repository\TaskBookStackLinkRepositoryInterface;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<TaskBookStackLink>
*/
class DoctrineTaskBookStackLinkRepository extends ServiceEntityRepository implements TaskBookStackLinkRepositoryInterface
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, TaskBookStackLink::class);
}
public function findById(int $id): ?TaskBookStackLink
{
return $this->find($id);
}
/**
* @return TaskBookStackLink[]
*/
public function findByTaskId(int $taskId): array
{
return $this->findBy(['task' => $taskId], ['createdAt' => 'DESC']);
}
}
@@ -2,13 +2,17 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Repository; namespace App\Module\Integration\Infrastructure\Doctrine;
use App\Entity\ZimbraConfiguration; use App\Module\Integration\Domain\Entity\ZimbraConfiguration;
use App\Module\Integration\Domain\Repository\ZimbraConfigurationRepositoryInterface;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
class ZimbraConfigurationRepository extends ServiceEntityRepository /**
* @extends ServiceEntityRepository<ZimbraConfiguration>
*/
class DoctrineZimbraConfigurationRepository extends ServiceEntityRepository implements ZimbraConfigurationRepositoryInterface
{ {
public function __construct(ManagerRegistry $registry) public function __construct(ManagerRegistry $registry)
{ {
@@ -2,11 +2,12 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Service; namespace App\Module\Integration\Infrastructure\Service;
use App\Entity\BookStackConfiguration; use App\Module\Integration\Domain\Entity\BookStackConfiguration;
use App\Exception\BookStackApiException; use App\Module\Integration\Domain\Exception\BookStackApiException;
use App\Repository\BookStackConfigurationRepository; use App\Module\Integration\Domain\Repository\BookStackConfigurationRepositoryInterface;
use App\Service\TokenEncryptor;
use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface; use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\HttpClientInterface;
@@ -19,7 +20,7 @@ final class BookStackApiService
public function __construct( public function __construct(
private readonly HttpClientInterface $httpClient, private readonly HttpClientInterface $httpClient,
private readonly BookStackConfigurationRepository $configRepository, private readonly BookStackConfigurationRepositoryInterface $configRepository,
private readonly TokenEncryptor $tokenEncryptor, private readonly TokenEncryptor $tokenEncryptor,
) {} ) {}
@@ -2,13 +2,14 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Service; namespace App\Module\Integration\Infrastructure\Service;
use App\Entity\GiteaConfiguration; use App\Module\Integration\Domain\Entity\GiteaConfiguration;
use App\Exception\GiteaApiException; use App\Module\Integration\Domain\Exception\GiteaApiException;
use App\Module\Integration\Domain\Repository\GiteaConfigurationRepositoryInterface;
use App\Module\ProjectManagement\Domain\Entity\Project; use App\Module\ProjectManagement\Domain\Entity\Project;
use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\ProjectManagement\Domain\Entity\Task;
use App\Repository\GiteaConfigurationRepository; use App\Service\TokenEncryptor;
use Symfony\Component\String\Slugger\AsciiSlugger; use Symfony\Component\String\Slugger\AsciiSlugger;
use Symfony\Component\String\Slugger\SluggerInterface; use Symfony\Component\String\Slugger\SluggerInterface;
use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ExceptionInterface;
@@ -22,7 +23,7 @@ final readonly class GiteaApiService
public function __construct( public function __construct(
private HttpClientInterface $httpClient, private HttpClientInterface $httpClient,
private GiteaConfigurationRepository $configRepository, private GiteaConfigurationRepositoryInterface $configRepository,
private TokenEncryptor $tokenEncryptor, private TokenEncryptor $tokenEncryptor,
) { ) {
$this->slugger = new AsciiSlugger('fr'); $this->slugger = new AsciiSlugger('fr');
@@ -2,12 +2,16 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Service\Share; namespace App\Module\Integration\Infrastructure\Service;
use App\Entity\ShareConfiguration; use App\Module\Integration\Domain\Entity\ShareConfiguration;
use App\Repository\ShareConfigurationRepository; use App\Module\Integration\Domain\Exception\ShareConnectionException;
use App\Service\Share\Exception\ShareConnectionException; use App\Module\Integration\Domain\Exception\ShareNotConfiguredException;
use App\Service\Share\Exception\ShareNotConfiguredException; use App\Module\Integration\Domain\Repository\ShareConfigurationRepositoryInterface;
use App\Module\Integration\Domain\Service\FileEntry;
use App\Module\Integration\Domain\Service\FileSource;
use App\Module\Integration\Domain\Service\SharePathResolver;
use App\Module\Integration\Domain\Service\ShareTestResult;
use App\Service\TokenEncryptor; use App\Service\TokenEncryptor;
use Icewind\SMB\BasicAuth; use Icewind\SMB\BasicAuth;
use Icewind\SMB\IFileInfo; use Icewind\SMB\IFileInfo;
@@ -24,7 +28,7 @@ final class SmbFileSource implements FileSource
private const int SEARCH_MAX_DIRS = 2000; private const int SEARCH_MAX_DIRS = 2000;
public function __construct( public function __construct(
private readonly ShareConfigurationRepository $configRepository, private readonly ShareConfigurationRepositoryInterface $configRepository,
private readonly TokenEncryptor $tokenEncryptor, private readonly TokenEncryptor $tokenEncryptor,
private readonly SharePathResolver $pathResolver, private readonly SharePathResolver $pathResolver,
) {} ) {}
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace App\Module\Integration;
use App\Shared\Domain\Module\ModuleInterface;
final class IntegrationModule implements ModuleInterface
{
public static function id(): string
{
return 'integration';
}
public static function label(): string
{
return 'Intégrations';
}
public static function isRequired(): bool
{
return false;
}
/**
* Permissions RBAC fin du Module Integration (Gitea, BookStack, Zimbra, Share).
*
* Additif : alimente le catalogue RBAC. La sécurité des opérations API
* reste en ROLE_USER/ROLE_ADMIN (non recâblée ici).
*
* @return list<array{code: string, label: string}>
*/
public static function permissions(): array
{
return [
['code' => 'integration.settings.manage', 'label' => 'Gérer les intégrations externes'],
['code' => 'integration.share.access', 'label' => 'Accéder au partage de fichiers'],
];
}
}
@@ -6,14 +6,14 @@ namespace App\Module\ProjectManagement\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface; use ApiPlatform\State\ProcessorInterface;
use App\Module\Integration\Domain\Exception\InvalidPathException;
use App\Module\Integration\Domain\Exception\ShareConnectionException;
use App\Module\Integration\Domain\Exception\ShareNotConfiguredException;
use App\Module\Integration\Domain\Service\FileEntry;
use App\Module\Integration\Domain\Service\FileSource;
use App\Module\Integration\Domain\Service\SharePathResolver;
use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\ProjectManagement\Domain\Entity\Task;
use App\Module\ProjectManagement\Domain\Entity\TaskDocument; use App\Module\ProjectManagement\Domain\Entity\TaskDocument;
use App\Service\Share\Exception\InvalidPathException;
use App\Service\Share\Exception\ShareConnectionException;
use App\Service\Share\Exception\ShareNotConfiguredException;
use App\Service\Share\FileEntry;
use App\Service\Share\FileSource;
use App\Service\Share\SharePathResolver;
use DateTimeImmutable; use DateTimeImmutable;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\SecurityBundle\Security; use Symfony\Bundle\SecurityBundle\Security;
@@ -4,10 +4,10 @@ declare(strict_types=1);
namespace App\Module\ProjectManagement\Infrastructure\Controller; namespace App\Module\ProjectManagement\Infrastructure\Controller;
use App\Module\Integration\Domain\Exception\ShareConnectionException;
use App\Module\Integration\Domain\Exception\ShareNotConfiguredException;
use App\Module\Integration\Domain\Service\FileSource;
use App\Module\ProjectManagement\Domain\Entity\TaskDocument; use App\Module\ProjectManagement\Domain\Entity\TaskDocument;
use App\Service\Share\Exception\ShareConnectionException;
use App\Service\Share\Exception\ShareNotConfiguredException;
use App\Service\Share\FileSource;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\BinaryFileResponse;
@@ -4,10 +4,10 @@ declare(strict_types=1);
namespace App\Module\ProjectManagement\Infrastructure\Service; namespace App\Module\ProjectManagement\Infrastructure\Service;
use App\Module\Integration\Domain\Repository\ZimbraConfigurationRepositoryInterface;
use App\Module\ProjectManagement\Domain\Entity\Task; use App\Module\ProjectManagement\Domain\Entity\Task;
use App\Module\ProjectManagement\Domain\Entity\TaskRecurrence; use App\Module\ProjectManagement\Domain\Entity\TaskRecurrence;
use App\Module\ProjectManagement\Domain\Enum\RecurrenceType; use App\Module\ProjectManagement\Domain\Enum\RecurrenceType;
use App\Repository\ZimbraConfigurationRepository;
use App\Service\TokenEncryptor; use App\Service\TokenEncryptor;
use DateTimeZone; use DateTimeZone;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@@ -21,7 +21,7 @@ use const ENT_QUOTES;
final class CalDavService final class CalDavService
{ {
public function __construct( public function __construct(
private readonly ZimbraConfigurationRepository $configRepository, private readonly ZimbraConfigurationRepositoryInterface $configRepository,
private readonly TokenEncryptor $tokenEncryptor, private readonly TokenEncryptor $tokenEncryptor,
private readonly HttpClientInterface $httpClient, private readonly HttpClientInterface $httpClient,
private readonly LoggerInterface $logger, private readonly LoggerInterface $logger,
@@ -1,22 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Repository;
use App\Entity\BookStackConfiguration;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class BookStackConfigurationRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, BookStackConfiguration::class);
}
public function findSingleton(): ?BookStackConfiguration
{
return $this->findOneBy([]);
}
}
@@ -1,23 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Repository;
use App\Entity\TaskBookStackLink;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class TaskBookStackLinkRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, TaskBookStackLink::class);
}
/** @return TaskBookStackLink[] */
public function findByTaskId(int $taskId): array
{
return $this->findBy(['task' => $taskId], ['createdAt' => 'DESC']);
}
}
+2 -2
View File
@@ -4,8 +4,8 @@ declare(strict_types=1);
namespace App\Tests\Unit\Service; namespace App\Tests\Unit\Service;
use App\Service\Share\Exception\InvalidPathException; use App\Module\Integration\Domain\Exception\InvalidPathException;
use App\Service\Share\SharePathResolver; use App\Module\Integration\Domain\Service\SharePathResolver;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
/** /**