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\Core\CoreModule;
use App\Module\Directory\DirectoryModule;
use App\Module\Integration\IntegrationModule;
use App\Module\Mail\MailModule;
use App\Module\ProjectManagement\ProjectManagementModule;
use App\Module\TimeTracking\TimeTrackingModule;
@@ -21,4 +22,5 @@ return [
AbsenceModule::class,
DirectoryModule::class,
MailModule::class,
IntegrationModule::class,
];
+5
View File
@@ -63,6 +63,11 @@ doctrine:
is_bundle: false
dir: '%kernel.project_dir%/src/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:
auto_mapping: false
+11 -1
View File
@@ -65,7 +65,17 @@ services:
arguments:
$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'
+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;
use App\Entity\ZimbraConfiguration;
use App\Enum\ContractType;
use App\Module\Absence\Domain\Entity\AbsenceBalance;
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\Prospect;
use App\Module\Directory\Domain\Enum\ProspectStatus;
use App\Module\Integration\Domain\Entity\ZimbraConfiguration;
use App\Module\Mail\Domain\Entity\MailConfiguration;
use App\Module\ProjectManagement\Domain\Entity\Project;
use App\Module\ProjectManagement\Domain\Entity\Task;
@@ -2,15 +2,22 @@
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 Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: BookStackConfigurationRepository::class)]
class BookStackConfiguration
#[Auditable]
#[ORM\Entity(repositoryClass: DoctrineBookStackConfigurationRepository::class)]
class BookStackConfiguration implements TimestampableInterface, BlamableInterface
{
use TimestampableBlamableTrait;
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
@@ -2,15 +2,22 @@
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 Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: GiteaConfigurationRepository::class)]
class GiteaConfiguration
#[Auditable]
#[ORM\Entity(repositoryClass: DoctrineGiteaConfigurationRepository::class)]
class GiteaConfiguration implements TimestampableInterface, BlamableInterface
{
use TimestampableBlamableTrait;
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
@@ -2,14 +2,21 @@
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;
#[ORM\Entity(repositoryClass: ShareConfigurationRepository::class)]
class ShareConfiguration
#[Auditable]
#[ORM\Entity(repositoryClass: DoctrineShareConfigurationRepository::class)]
class ShareConfiguration implements TimestampableInterface, BlamableInterface
{
use TimestampableBlamableTrait;
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
@@ -2,15 +2,15 @@
declare(strict_types=1);
namespace App\Entity;
namespace App\Module\Integration\Domain\Entity;
use App\Module\ProjectManagement\Domain\Entity\Task;
use App\Repository\TaskBookStackLinkRepository;
use App\Module\Integration\Infrastructure\Doctrine\DoctrineTaskBookStackLinkRepository;
use App\Shared\Domain\Contract\TaskInterface;
use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM;
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'])]
class TaskBookStackLink
{
@@ -19,9 +19,9 @@ class TaskBookStackLink
#[ORM\Column]
private ?int $id = null;
#[ORM\ManyToOne(targetEntity: Task::class)]
#[ORM\ManyToOne(targetEntity: TaskInterface::class)]
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
private Task $task;
private TaskInterface $task;
#[ORM\Column]
private int $bookstackId;
@@ -49,12 +49,12 @@ class TaskBookStackLink
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;
@@ -2,15 +2,22 @@
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 Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: ZimbraConfigurationRepository::class)]
class ZimbraConfiguration
#[Auditable]
#[ORM\Entity(repositoryClass: DoctrineZimbraConfigurationRepository::class)]
class ZimbraConfiguration implements TimestampableInterface, BlamableInterface
{
use TimestampableBlamableTrait;
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Exception;
namespace App\Module\Integration\Domain\Exception;
use RuntimeException;
@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Exception;
namespace App\Module\Integration\Domain\Exception;
use RuntimeException;
@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Service\Share\Exception;
namespace App\Module\Integration\Domain\Exception;
use RuntimeException;
@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Service\Share\Exception;
namespace App\Module\Integration\Domain\Exception;
use RuntimeException;
@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Service\Share\Exception;
namespace App\Module\Integration\Domain\Exception;
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);
namespace App\Service\Share;
namespace App\Module\Integration\Domain\Service;
final readonly class FileEntry
{
@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Service\Share;
namespace App\Module\Integration\Domain\Service;
interface FileSource
{
@@ -2,9 +2,9 @@
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
{
@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Service\Share;
namespace App\Module\Integration\Domain\Service;
final readonly class ShareTestResult
{
@@ -2,17 +2,17 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link;
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\State\BookStackLinkProcessor;
use App\State\BookStackLinkProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link;
use App\Module\Integration\Infrastructure\ApiPlatform\State\BookStackSearchResultProvider;
use App\Module\ProjectManagement\Domain\Entity\Task;
use App\State\BookStackSearchResultProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Put;
use App\State\BookStackSettingsProcessor;
use App\State\BookStackSettingsProvider;
use App\Module\Integration\Infrastructure\ApiPlatform\State\BookStackSettingsProcessor;
use App\Module\Integration\Infrastructure\ApiPlatform\State\BookStackSettingsProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection;
use App\State\BookStackShelfProvider;
use App\Module\Integration\Infrastructure\ApiPlatform\State\BookStackShelfProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Post;
use App\State\BookStackTestConnectionProvider;
use App\Module\Integration\Infrastructure\ApiPlatform\State\BookStackTestConnectionProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use App\State\GiteaBranchProcessor;
use App\State\GiteaBranchProvider;
use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaBranchProcessor;
use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaBranchProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use App\State\GiteaBranchNameProvider;
use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaBranchNameProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection;
use App\State\GiteaPullRequestProvider;
use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaPullRequestProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection;
use App\State\GiteaRepositoryProvider;
use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaRepositoryProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Put;
use App\State\GiteaSettingsProcessor;
use App\State\GiteaSettingsProvider;
use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaSettingsProcessor;
use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaSettingsProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Post;
use App\State\GiteaTestConnectionProvider;
use App\Module\Integration\Infrastructure\ApiPlatform\State\GiteaTestConnectionProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Put;
use App\State\ShareSettingsProcessor;
use App\State\ShareSettingsProvider;
use App\Module\Integration\Infrastructure\ApiPlatform\State\ShareSettingsProcessor;
use App\Module\Integration\Infrastructure\ApiPlatform\State\ShareSettingsProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Post;
use App\State\ShareTestConnectionProvider;
use App\Module\Integration\Infrastructure\ApiPlatform\State\ShareTestConnectionProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Put;
use App\State\ZimbraSettingsProcessor;
use App\State\ZimbraSettingsProvider;
use App\Module\Integration\Infrastructure\ApiPlatform\State\ZimbraSettingsProcessor;
use App\Module\Integration\Infrastructure\ApiPlatform\State\ZimbraSettingsProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,11 +2,11 @@
declare(strict_types=1);
namespace App\ApiResource;
namespace App\Module\Integration\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Post;
use App\State\ZimbraTestConnectionProvider;
use App\Module\Integration\Infrastructure\ApiPlatform\State\ZimbraTestConnectionProvider;
use Symfony\Component\Serializer\Attribute\Groups;
#[ApiResource(
@@ -2,15 +2,15 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\ApiResource\BookStackLink;
use App\Entity\TaskBookStackLink;
use App\Module\ProjectManagement\Domain\Entity\Task;
use App\Repository\TaskBookStackLinkRepository;
use App\Module\Integration\Domain\Entity\TaskBookStackLink;
use App\Module\Integration\Domain\Repository\TaskBookStackLinkRepositoryInterface;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackLink;
use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -18,7 +18,8 @@ final readonly class BookStackLinkProcessor implements ProcessorInterface
{
public function __construct(
private EntityManagerInterface $em,
private TaskBookStackLinkRepository $linkRepository,
private TaskBookStackLinkRepositoryInterface $linkRepository,
private TaskRepositoryInterface $taskRepository,
) {}
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);
$taskId = $uriVariables['taskId'] ?? 0;
$task = $this->em->getRepository(Task::class)->find($taskId);
$task = $this->taskRepository->findById((int) $taskId);
if (null === $task) {
throw new NotFoundHttpException('Task not found.');
@@ -65,7 +66,7 @@ final readonly class BookStackLinkProcessor implements ProcessorInterface
private function handleDelete(array $uriVariables): null
{
$linkId = $uriVariables['id'] ?? 0;
$link = $this->linkRepository->find($linkId);
$link = $this->linkRepository->findById((int) $linkId);
if (null === $link) {
throw new NotFoundHttpException('Link not found.');
@@ -2,21 +2,21 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Post;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\BookStackLink;
use App\Entity\TaskBookStackLink;
use App\Repository\TaskBookStackLinkRepository;
use App\Module\Integration\Domain\Entity\TaskBookStackLink;
use App\Module\Integration\Domain\Repository\TaskBookStackLinkRepositoryInterface;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackLink;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
final readonly class BookStackLinkProvider implements ProviderInterface
{
public function __construct(
private TaskBookStackLinkRepository $linkRepository,
private TaskBookStackLinkRepositoryInterface $linkRepository,
) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array|BookStackLink
@@ -2,15 +2,14 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\BookStackSearchResult;
use App\Exception\BookStackApiException;
use App\Module\ProjectManagement\Domain\Entity\Task;
use App\Service\BookStackApiService;
use Doctrine\ORM\EntityManagerInterface;
use App\Module\Integration\Domain\Exception\BookStackApiException;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackSearchResult;
use App\Module\Integration\Infrastructure\Service\BookStackApiService;
use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
@@ -18,14 +17,14 @@ final readonly class BookStackSearchResultProvider implements ProviderInterface
{
public function __construct(
private BookStackApiService $bookStackApiService,
private EntityManagerInterface $em,
private TaskRepositoryInterface $taskRepository,
private RequestStack $requestStack,
) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
{
$taskId = $uriVariables['taskId'] ?? 0;
$task = $this->em->getRepository(Task::class)->find($taskId);
$task = $this->taskRepository->findById((int) $taskId);
if (null === $task || null === $task->getProject()) {
return [];
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\ApiResource\BookStackSettings;
use App\Entity\BookStackConfiguration;
use App\Repository\BookStackConfigurationRepository;
use App\Module\Integration\Domain\Entity\BookStackConfiguration;
use App\Module\Integration\Domain\Repository\BookStackConfigurationRepositoryInterface;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackSettings;
use App\Service\TokenEncryptor;
use Doctrine\ORM\EntityManagerInterface;
@@ -16,7 +16,7 @@ final readonly class BookStackSettingsProcessor implements ProcessorInterface
{
public function __construct(
private EntityManagerInterface $em,
private BookStackConfigurationRepository $configRepository,
private BookStackConfigurationRepositoryInterface $configRepository,
private TokenEncryptor $tokenEncryptor,
) {}
@@ -2,17 +2,17 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\BookStackSettings;
use App\Repository\BookStackConfigurationRepository;
use App\Module\Integration\Domain\Repository\BookStackConfigurationRepositoryInterface;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackSettings;
final readonly class BookStackSettingsProvider implements ProviderInterface
{
public function __construct(
private BookStackConfigurationRepository $configRepository,
private BookStackConfigurationRepositoryInterface $configRepository,
) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): BookStackSettings
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\BookStackShelf;
use App\Exception\BookStackApiException;
use App\Service\BookStackApiService;
use App\Module\Integration\Domain\Exception\BookStackApiException;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackShelf;
use App\Module\Integration\Infrastructure\Service\BookStackApiService;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
final readonly class BookStackShelfProvider implements ProviderInterface
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\BookStackTestConnection;
use App\Service\BookStackApiService;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackTestConnection;
use App\Module\Integration\Infrastructure\Service\BookStackApiService;
final readonly class BookStackTestConnectionProvider implements ProviderInterface, ProcessorInterface
{
@@ -2,14 +2,13 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\GiteaBranchName;
use App\Module\ProjectManagement\Domain\Entity\Task;
use App\Service\GiteaApiService;
use Doctrine\ORM\EntityManagerInterface;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaBranchName;
use App\Module\Integration\Infrastructure\Service\GiteaApiService;
use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -20,12 +19,12 @@ final readonly class GiteaBranchNameProvider implements ProviderInterface
public function __construct(
private GiteaApiService $giteaApiService,
private EntityManagerInterface $em,
private TaskRepositoryInterface $taskRepository,
) {}
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) {
throw new NotFoundHttpException('Task not found.');
}
@@ -2,15 +2,14 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\ApiResource\GiteaBranch;
use App\Exception\GiteaApiException;
use App\Module\ProjectManagement\Domain\Entity\Task;
use App\Service\GiteaApiService;
use Doctrine\ORM\EntityManagerInterface;
use App\Module\Integration\Domain\Exception\GiteaApiException;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaBranch;
use App\Module\Integration\Infrastructure\Service\GiteaApiService;
use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -20,14 +19,14 @@ final readonly class GiteaBranchProcessor implements ProcessorInterface
public function __construct(
private GiteaApiService $giteaApiService,
private EntityManagerInterface $em,
private TaskRepositoryInterface $taskRepository,
) {}
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): 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()) {
throw new NotFoundHttpException('Task not found.');
}
@@ -2,23 +2,22 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Post;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\GiteaBranch;
use App\Exception\GiteaApiException;
use App\Module\ProjectManagement\Domain\Entity\Task;
use App\Service\GiteaApiService;
use Doctrine\ORM\EntityManagerInterface;
use App\Module\Integration\Domain\Exception\GiteaApiException;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaBranch;
use App\Module\Integration\Infrastructure\Service\GiteaApiService;
use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
final readonly class GiteaBranchProvider implements ProviderInterface
{
public function __construct(
private GiteaApiService $giteaApiService,
private EntityManagerInterface $em,
private TaskRepositoryInterface $taskRepository,
) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array|GiteaBranch
@@ -27,7 +26,7 @@ final readonly class GiteaBranchProvider implements ProviderInterface
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()) {
return [];
}
@@ -2,27 +2,26 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\GiteaPullRequest;
use App\Exception\GiteaApiException;
use App\Module\ProjectManagement\Domain\Entity\Task;
use App\Service\GiteaApiService;
use Doctrine\ORM\EntityManagerInterface;
use App\Module\Integration\Domain\Exception\GiteaApiException;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaPullRequest;
use App\Module\Integration\Infrastructure\Service\GiteaApiService;
use App\Module\ProjectManagement\Domain\Repository\TaskRepositoryInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
final readonly class GiteaPullRequestProvider implements ProviderInterface
{
public function __construct(
private GiteaApiService $giteaApiService,
private EntityManagerInterface $em,
private TaskRepositoryInterface $taskRepository,
) {}
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()) {
return [];
}
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\GiteaRepository;
use App\Exception\GiteaApiException;
use App\Service\GiteaApiService;
use App\Module\Integration\Domain\Exception\GiteaApiException;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaRepository;
use App\Module\Integration\Infrastructure\Service\GiteaApiService;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
final readonly class GiteaRepositoryProvider implements ProviderInterface
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\ApiResource\GiteaSettings;
use App\Entity\GiteaConfiguration;
use App\Repository\GiteaConfigurationRepository;
use App\Module\Integration\Domain\Entity\GiteaConfiguration;
use App\Module\Integration\Domain\Repository\GiteaConfigurationRepositoryInterface;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaSettings;
use App\Service\TokenEncryptor;
use Doctrine\ORM\EntityManagerInterface;
@@ -16,7 +16,7 @@ final readonly class GiteaSettingsProcessor implements ProcessorInterface
{
public function __construct(
private EntityManagerInterface $em,
private GiteaConfigurationRepository $configRepository,
private GiteaConfigurationRepositoryInterface $configRepository,
private TokenEncryptor $tokenEncryptor,
) {}
@@ -2,17 +2,17 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\GiteaSettings;
use App\Repository\GiteaConfigurationRepository;
use App\Module\Integration\Domain\Repository\GiteaConfigurationRepositoryInterface;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaSettings;
final readonly class GiteaSettingsProvider implements ProviderInterface
{
public function __construct(
private GiteaConfigurationRepository $configRepository,
private GiteaConfigurationRepositoryInterface $configRepository,
) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): GiteaSettings
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\GiteaTestConnection;
use App\Service\GiteaApiService;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaTestConnection;
use App\Module\Integration\Infrastructure\Service\GiteaApiService;
final readonly class GiteaTestConnectionProvider implements ProviderInterface, ProcessorInterface
{
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\ApiResource\ShareSettings;
use App\Entity\ShareConfiguration;
use App\Repository\ShareConfigurationRepository;
use App\Module\Integration\Domain\Entity\ShareConfiguration;
use App\Module\Integration\Domain\Repository\ShareConfigurationRepositoryInterface;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\ShareSettings;
use App\Service\TokenEncryptor;
use Doctrine\ORM\EntityManagerInterface;
@@ -16,7 +16,7 @@ final readonly class ShareSettingsProcessor implements ProcessorInterface
{
public function __construct(
private EntityManagerInterface $em,
private ShareConfigurationRepository $configRepository,
private ShareConfigurationRepositoryInterface $configRepository,
private TokenEncryptor $tokenEncryptor,
) {}
@@ -2,17 +2,17 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\ShareSettings;
use App\Repository\ShareConfigurationRepository;
use App\Module\Integration\Domain\Repository\ShareConfigurationRepositoryInterface;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\ShareSettings;
final readonly class ShareSettingsProvider implements ProviderInterface
{
public function __construct(
private ShareConfigurationRepository $configRepository,
private ShareConfigurationRepositoryInterface $configRepository,
) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ShareSettings
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\ShareTestConnection;
use App\Service\Share\FileSource;
use App\Module\Integration\Domain\Service\FileSource;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\ShareTestConnection;
final readonly class ShareTestConnectionProvider implements ProviderInterface, ProcessorInterface
{
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\ApiResource\ZimbraSettings;
use App\Entity\ZimbraConfiguration;
use App\Repository\ZimbraConfigurationRepository;
use App\Module\Integration\Domain\Entity\ZimbraConfiguration;
use App\Module\Integration\Domain\Repository\ZimbraConfigurationRepositoryInterface;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\ZimbraSettings;
use App\Service\TokenEncryptor;
use Doctrine\ORM\EntityManagerInterface;
@@ -16,7 +16,7 @@ final readonly class ZimbraSettingsProcessor implements ProcessorInterface
{
public function __construct(
private EntityManagerInterface $em,
private ZimbraConfigurationRepository $configRepository,
private ZimbraConfigurationRepositoryInterface $configRepository,
private TokenEncryptor $tokenEncryptor,
) {}
@@ -2,17 +2,17 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\ZimbraSettings;
use App\Repository\ZimbraConfigurationRepository;
use App\Module\Integration\Domain\Repository\ZimbraConfigurationRepositoryInterface;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\ZimbraSettings;
final readonly class ZimbraSettingsProvider implements ProviderInterface
{
public function __construct(
private ZimbraConfigurationRepository $configRepository,
private ZimbraConfigurationRepositoryInterface $configRepository,
) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ZimbraSettings
@@ -2,12 +2,12 @@
declare(strict_types=1);
namespace App\State;
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\ZimbraTestConnection;
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\ZimbraTestConnection;
use App\Module\ProjectManagement\Infrastructure\Service\CalDavService;
use Throwable;
@@ -2,14 +2,14 @@
declare(strict_types=1);
namespace App\Controller\Share;
namespace App\Module\Integration\Infrastructure\Controller;
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 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 Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
@@ -2,13 +2,13 @@
declare(strict_types=1);
namespace App\Controller\Share;
namespace App\Module\Integration\Infrastructure\Controller;
use App\Service\Share\Exception\InvalidPathException;
use App\Service\Share\Exception\ShareConnectionException;
use App\Service\Share\Exception\ShareNotConfiguredException;
use App\Service\Share\FileSource;
use App\Service\Share\SharePathResolver;
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\FileSource;
use App\Module\Integration\Domain\Service\SharePathResolver;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\HeaderUtils;
use Symfony\Component\HttpFoundation\Request;
@@ -2,12 +2,12 @@
declare(strict_types=1);
namespace App\Controller\Share;
namespace App\Module\Integration\Infrastructure\Controller;
use App\Service\Share\Exception\ShareConnectionException;
use App\Service\Share\Exception\ShareNotConfiguredException;
use App\Service\Share\FileEntry;
use App\Service\Share\FileSource;
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 Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
@@ -2,9 +2,9 @@
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\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Attribute\Route;
@@ -13,7 +13,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
class ShareStatusController extends AbstractController
{
public function __construct(
private readonly ShareConfigurationRepository $configRepository,
private readonly ShareConfigurationRepositoryInterface $configRepository,
) {}
#[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);
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\Persistence\ManagerRegistry;
class GiteaConfigurationRepository extends ServiceEntityRepository
/**
* @extends ServiceEntityRepository<GiteaConfiguration>
*/
class DoctrineGiteaConfigurationRepository extends ServiceEntityRepository implements GiteaConfigurationRepositoryInterface
{
public function __construct(ManagerRegistry $registry)
{
@@ -2,13 +2,17 @@
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\Persistence\ManagerRegistry;
class ShareConfigurationRepository extends ServiceEntityRepository
/**
* @extends ServiceEntityRepository<ShareConfiguration>
*/
class DoctrineShareConfigurationRepository extends ServiceEntityRepository implements ShareConfigurationRepositoryInterface
{
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);
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\Persistence\ManagerRegistry;
class ZimbraConfigurationRepository extends ServiceEntityRepository
/**
* @extends ServiceEntityRepository<ZimbraConfiguration>
*/
class DoctrineZimbraConfigurationRepository extends ServiceEntityRepository implements ZimbraConfigurationRepositoryInterface
{
public function __construct(ManagerRegistry $registry)
{
@@ -2,11 +2,12 @@
declare(strict_types=1);
namespace App\Service;
namespace App\Module\Integration\Infrastructure\Service;
use App\Entity\BookStackConfiguration;
use App\Exception\BookStackApiException;
use App\Repository\BookStackConfigurationRepository;
use App\Module\Integration\Domain\Entity\BookStackConfiguration;
use App\Module\Integration\Domain\Exception\BookStackApiException;
use App\Module\Integration\Domain\Repository\BookStackConfigurationRepositoryInterface;
use App\Service\TokenEncryptor;
use Symfony\Contracts\HttpClient\Exception\ExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
@@ -19,7 +20,7 @@ final class BookStackApiService
public function __construct(
private readonly HttpClientInterface $httpClient,
private readonly BookStackConfigurationRepository $configRepository,
private readonly BookStackConfigurationRepositoryInterface $configRepository,
private readonly TokenEncryptor $tokenEncryptor,
) {}
@@ -2,13 +2,14 @@
declare(strict_types=1);
namespace App\Service;
namespace App\Module\Integration\Infrastructure\Service;
use App\Entity\GiteaConfiguration;
use App\Exception\GiteaApiException;
use App\Module\Integration\Domain\Entity\GiteaConfiguration;
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\Task;
use App\Repository\GiteaConfigurationRepository;
use App\Service\TokenEncryptor;
use Symfony\Component\String\Slugger\AsciiSlugger;
use Symfony\Component\String\Slugger\SluggerInterface;
use Symfony\Contracts\HttpClient\Exception\ExceptionInterface;
@@ -22,7 +23,7 @@ final readonly class GiteaApiService
public function __construct(
private HttpClientInterface $httpClient,
private GiteaConfigurationRepository $configRepository,
private GiteaConfigurationRepositoryInterface $configRepository,
private TokenEncryptor $tokenEncryptor,
) {
$this->slugger = new AsciiSlugger('fr');
@@ -2,12 +2,16 @@
declare(strict_types=1);
namespace App\Service\Share;
namespace App\Module\Integration\Infrastructure\Service;
use App\Entity\ShareConfiguration;
use App\Repository\ShareConfigurationRepository;
use App\Service\Share\Exception\ShareConnectionException;
use App\Service\Share\Exception\ShareNotConfiguredException;
use App\Module\Integration\Domain\Entity\ShareConfiguration;
use App\Module\Integration\Domain\Exception\ShareConnectionException;
use App\Module\Integration\Domain\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 Icewind\SMB\BasicAuth;
use Icewind\SMB\IFileInfo;
@@ -24,7 +28,7 @@ final class SmbFileSource implements FileSource
private const int SEARCH_MAX_DIRS = 2000;
public function __construct(
private readonly ShareConfigurationRepository $configRepository,
private readonly ShareConfigurationRepositoryInterface $configRepository,
private readonly TokenEncryptor $tokenEncryptor,
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\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\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 Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\SecurityBundle\Security;
@@ -4,10 +4,10 @@ declare(strict_types=1);
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\Service\Share\Exception\ShareConnectionException;
use App\Service\Share\Exception\ShareNotConfiguredException;
use App\Service\Share\FileSource;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
@@ -4,10 +4,10 @@ declare(strict_types=1);
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\TaskRecurrence;
use App\Module\ProjectManagement\Domain\Enum\RecurrenceType;
use App\Repository\ZimbraConfigurationRepository;
use App\Service\TokenEncryptor;
use DateTimeZone;
use Psr\Log\LoggerInterface;
@@ -21,7 +21,7 @@ use const ENT_QUOTES;
final class CalDavService
{
public function __construct(
private readonly ZimbraConfigurationRepository $configRepository,
private readonly ZimbraConfigurationRepositoryInterface $configRepository,
private readonly TokenEncryptor $tokenEncryptor,
private readonly HttpClientInterface $httpClient,
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;
use App\Service\Share\Exception\InvalidPathException;
use App\Service\Share\SharePathResolver;
use App\Module\Integration\Domain\Exception\InvalidPathException;
use App\Module\Integration\Domain\Service\SharePathResolver;
use PHPUnit\Framework\TestCase;
/**