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:
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Delete;
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
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;
|
||||
|
||||
final readonly class BookStackLinkProcessor implements ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private TaskBookStackLinkRepositoryInterface $linkRepository,
|
||||
private TaskRepositoryInterface $taskRepository,
|
||||
) {}
|
||||
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ?BookStackLink
|
||||
{
|
||||
if ($operation instanceof Delete) {
|
||||
return $this->handleDelete($uriVariables);
|
||||
}
|
||||
|
||||
return $this->handleCreate($data, $uriVariables);
|
||||
}
|
||||
|
||||
private function handleCreate(mixed $data, array $uriVariables): BookStackLink
|
||||
{
|
||||
assert($data instanceof BookStackLink);
|
||||
|
||||
$taskId = $uriVariables['taskId'] ?? 0;
|
||||
$task = $this->taskRepository->findById((int) $taskId);
|
||||
|
||||
if (null === $task) {
|
||||
throw new NotFoundHttpException('Task not found.');
|
||||
}
|
||||
|
||||
$link = new TaskBookStackLink();
|
||||
$link->setTask($task);
|
||||
$link->setBookstackId($data->bookstackId);
|
||||
$link->setBookstackType($data->bookstackType);
|
||||
$link->setTitle($data->title);
|
||||
$link->setUrl($data->url);
|
||||
|
||||
$this->em->persist($link);
|
||||
$this->em->flush();
|
||||
|
||||
$result = new BookStackLink();
|
||||
$result->id = $link->getId();
|
||||
$result->bookstackId = $link->getBookstackId();
|
||||
$result->bookstackType = $link->getBookstackType();
|
||||
$result->title = $link->getTitle();
|
||||
$result->url = $link->getUrl();
|
||||
$result->createdAt = $link->getCreatedAt()->format('c');
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function handleDelete(array $uriVariables): null
|
||||
{
|
||||
$linkId = $uriVariables['id'] ?? 0;
|
||||
$link = $this->linkRepository->findById((int) $linkId);
|
||||
|
||||
if (null === $link) {
|
||||
throw new NotFoundHttpException('Link not found.');
|
||||
}
|
||||
|
||||
$this->em->remove($link);
|
||||
$this->em->flush();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
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\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 TaskBookStackLinkRepositoryInterface $linkRepository,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array|BookStackLink
|
||||
{
|
||||
if ($operation instanceof Post) {
|
||||
return new BookStackLink();
|
||||
}
|
||||
|
||||
if ($operation instanceof Delete) {
|
||||
$link = $this->linkRepository->find($uriVariables['id'] ?? 0);
|
||||
if (null === $link) {
|
||||
throw new NotFoundHttpException('Link not found.');
|
||||
}
|
||||
$dto = new BookStackLink();
|
||||
$dto->id = $link->getId();
|
||||
|
||||
return $dto;
|
||||
}
|
||||
|
||||
$taskId = $uriVariables['taskId'] ?? 0;
|
||||
$links = $this->linkRepository->findByTaskId($taskId);
|
||||
|
||||
return array_map(static function (TaskBookStackLink $link): BookStackLink {
|
||||
$dto = new BookStackLink();
|
||||
$dto->id = $link->getId();
|
||||
$dto->bookstackId = $link->getBookstackId();
|
||||
$dto->bookstackType = $link->getBookstackType();
|
||||
$dto->title = $link->getTitle();
|
||||
$dto->url = $link->getUrl();
|
||||
$dto->createdAt = $link->getCreatedAt()->format('c');
|
||||
|
||||
return $dto;
|
||||
}, $links);
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
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;
|
||||
|
||||
final readonly class BookStackSearchResultProvider implements ProviderInterface
|
||||
{
|
||||
public function __construct(
|
||||
private BookStackApiService $bookStackApiService,
|
||||
private TaskRepositoryInterface $taskRepository,
|
||||
private RequestStack $requestStack,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
|
||||
{
|
||||
$taskId = $uriVariables['taskId'] ?? 0;
|
||||
$task = $this->taskRepository->findById((int) $taskId);
|
||||
|
||||
if (null === $task || null === $task->getProject()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$shelfId = $task->getProject()->getBookstackShelfId();
|
||||
if (null === $shelfId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$request = $this->requestStack->getCurrentRequest();
|
||||
$query = $request?->query->get('q', '') ?? '';
|
||||
|
||||
if ('' === trim($query)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
$results = $this->bookStackApiService->searchInShelf($shelfId, $query);
|
||||
} catch (BookStackApiException $e) {
|
||||
throw new BadRequestHttpException($e->getMessage(), $e);
|
||||
}
|
||||
|
||||
return array_map(static function (array $item): BookStackSearchResult {
|
||||
$dto = new BookStackSearchResult();
|
||||
$dto->id = $item['id'];
|
||||
$dto->type = $item['type'];
|
||||
$dto->name = $item['name'];
|
||||
$dto->url = $item['url'];
|
||||
|
||||
return $dto;
|
||||
}, $results);
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
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;
|
||||
|
||||
final readonly class BookStackSettingsProcessor implements ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private BookStackConfigurationRepositoryInterface $configRepository,
|
||||
private TokenEncryptor $tokenEncryptor,
|
||||
) {}
|
||||
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): BookStackSettings
|
||||
{
|
||||
assert($data instanceof BookStackSettings);
|
||||
|
||||
$config = $this->configRepository->findSingleton();
|
||||
if (null === $config) {
|
||||
$config = new BookStackConfiguration();
|
||||
}
|
||||
|
||||
$config->setUrl($data->url);
|
||||
|
||||
if (null !== $data->tokenId && '' !== $data->tokenId
|
||||
&& null !== $data->tokenSecret && '' !== $data->tokenSecret) {
|
||||
$config->setEncryptedTokenId($this->tokenEncryptor->encrypt($data->tokenId));
|
||||
$config->setEncryptedTokenSecret($this->tokenEncryptor->encrypt($data->tokenSecret));
|
||||
}
|
||||
|
||||
$this->em->persist($config);
|
||||
$this->em->flush();
|
||||
|
||||
$result = new BookStackSettings();
|
||||
$result->url = $config->getUrl();
|
||||
$result->hasToken = $config->hasToken();
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
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 BookStackConfigurationRepositoryInterface $configRepository,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): BookStackSettings
|
||||
{
|
||||
$config = $this->configRepository->findSingleton();
|
||||
$dto = new BookStackSettings();
|
||||
|
||||
if (null !== $config) {
|
||||
$dto->url = $config->getUrl();
|
||||
$dto->hasToken = $config->hasToken();
|
||||
}
|
||||
|
||||
return $dto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
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
|
||||
{
|
||||
public function __construct(
|
||||
private BookStackApiService $bookStackApiService,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
|
||||
{
|
||||
try {
|
||||
$shelves = $this->bookStackApiService->listShelves();
|
||||
} catch (BookStackApiException $e) {
|
||||
throw new BadRequestHttpException($e->getMessage(), $e);
|
||||
}
|
||||
|
||||
return array_map(static function (array $shelf): BookStackShelf {
|
||||
$dto = new BookStackShelf();
|
||||
$dto->id = $shelf['id'] ?? 0;
|
||||
$dto->name = $shelf['name'] ?? '';
|
||||
|
||||
return $dto;
|
||||
}, $shelves);
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\BookStackTestConnection;
|
||||
use App\Module\Integration\Infrastructure\Service\BookStackApiService;
|
||||
|
||||
final readonly class BookStackTestConnectionProvider implements ProviderInterface, ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private BookStackApiService $bookStackApiService,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): BookStackTestConnection
|
||||
{
|
||||
return new BookStackTestConnection();
|
||||
}
|
||||
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): BookStackTestConnection
|
||||
{
|
||||
$result = new BookStackTestConnection();
|
||||
$result->success = $this->bookStackApiService->testConnection();
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
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;
|
||||
|
||||
final readonly class GiteaBranchNameProvider implements ProviderInterface
|
||||
{
|
||||
/** @see GiteaBranchProcessor::ALLOWED_TYPES */
|
||||
private const array ALLOWED_TYPES = ['feature', 'fix', 'refactor', 'hotfix', 'chore'];
|
||||
|
||||
public function __construct(
|
||||
private GiteaApiService $giteaApiService,
|
||||
private TaskRepositoryInterface $taskRepository,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): GiteaBranchName
|
||||
{
|
||||
$task = $this->taskRepository->findById((int) ($uriVariables['taskId'] ?? 0));
|
||||
if (null === $task) {
|
||||
throw new NotFoundHttpException('Task not found.');
|
||||
}
|
||||
|
||||
$type = $uriVariables['type'] ?? 'feature';
|
||||
if (!in_array($type, self::ALLOWED_TYPES, true)) {
|
||||
throw new BadRequestHttpException('Invalid branch type.');
|
||||
}
|
||||
|
||||
$dto = new GiteaBranchName();
|
||||
$dto->name = $this->giteaApiService->generateBranchName($task, $type);
|
||||
|
||||
return $dto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
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;
|
||||
|
||||
final readonly class GiteaBranchProcessor implements ProcessorInterface
|
||||
{
|
||||
private const array ALLOWED_TYPES = ['feature', 'fix', 'refactor', 'hotfix', 'chore'];
|
||||
|
||||
public function __construct(
|
||||
private GiteaApiService $giteaApiService,
|
||||
private TaskRepositoryInterface $taskRepository,
|
||||
) {}
|
||||
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): GiteaBranch
|
||||
{
|
||||
assert($data instanceof GiteaBranch);
|
||||
|
||||
$task = $this->taskRepository->findById((int) ($uriVariables['taskId'] ?? 0));
|
||||
if (null === $task || null === $task->getProject()) {
|
||||
throw new NotFoundHttpException('Task not found.');
|
||||
}
|
||||
|
||||
$project = $task->getProject();
|
||||
if (!$project->hasGiteaRepo()) {
|
||||
throw new BadRequestHttpException('Project has no Gitea repository.');
|
||||
}
|
||||
|
||||
if (!in_array($data->type, self::ALLOWED_TYPES, true)) {
|
||||
throw new BadRequestHttpException('Invalid branch type.');
|
||||
}
|
||||
|
||||
try {
|
||||
$branchName = $this->giteaApiService->createBranch($project, $task, $data->type, $data->baseBranch);
|
||||
} catch (GiteaApiException $e) {
|
||||
throw new BadRequestHttpException($e->getMessage());
|
||||
}
|
||||
|
||||
$result = new GiteaBranch();
|
||||
$result->name = $branchName;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\Metadata\Post;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
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 TaskRepositoryInterface $taskRepository,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array|GiteaBranch
|
||||
{
|
||||
if ($operation instanceof Post) {
|
||||
return new GiteaBranch();
|
||||
}
|
||||
|
||||
$task = $this->taskRepository->findById((int) ($uriVariables['taskId'] ?? 0));
|
||||
if (null === $task || null === $task->getProject()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$project = $task->getProject();
|
||||
if (!$project->hasGiteaRepo()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$taskCode = $project->getCode().'-'.$task->getNumber();
|
||||
|
||||
try {
|
||||
$branches = $this->giteaApiService->listBranches($project, $taskCode);
|
||||
} catch (GiteaApiException $e) {
|
||||
throw new BadRequestHttpException($e->getMessage(), $e);
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach ($branches as $branch) {
|
||||
$dto = new GiteaBranch();
|
||||
$dto->name = $branch['name'];
|
||||
|
||||
try {
|
||||
$commits = $this->giteaApiService->listBranchCommits($project, $branch['name']);
|
||||
$dto->commits = array_map(static fn (array $c): array => [
|
||||
'sha' => substr($c['sha'] ?? '', 0, 7),
|
||||
'message' => $c['commit']['message'] ?? '',
|
||||
'author' => $c['commit']['author']['name'] ?? '',
|
||||
'date' => $c['commit']['author']['date'] ?? $c['created'] ?? '',
|
||||
], $commits);
|
||||
} catch (GiteaApiException) {
|
||||
// Commits fetch failure should not block branch listing
|
||||
$dto->commits = [];
|
||||
}
|
||||
|
||||
$result[] = $dto;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
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 TaskRepositoryInterface $taskRepository,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
|
||||
{
|
||||
$task = $this->taskRepository->findById((int) ($uriVariables['taskId'] ?? 0));
|
||||
if (null === $task || null === $task->getProject()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$project = $task->getProject();
|
||||
if (!$project->hasGiteaRepo()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$taskCode = $project->getCode().'-'.$task->getNumber();
|
||||
|
||||
try {
|
||||
$prs = $this->giteaApiService->listPullRequests($project, $taskCode);
|
||||
} catch (GiteaApiException $e) {
|
||||
throw new BadRequestHttpException($e->getMessage(), $e);
|
||||
}
|
||||
|
||||
return array_map(static function (array $pr): GiteaPullRequest {
|
||||
$dto = new GiteaPullRequest();
|
||||
$dto->number = $pr['number'] ?? 0;
|
||||
$dto->title = $pr['title'] ?? '';
|
||||
$dto->state = $pr['state'] ?? '';
|
||||
$dto->merged = $pr['merged'] ?? false;
|
||||
$dto->headBranch = $pr['head']['ref'] ?? '';
|
||||
$dto->author = $pr['user']['login'] ?? '';
|
||||
$dto->url = $pr['html_url'] ?? '';
|
||||
$dto->ciStatuses = array_map(static fn (array $s): array => [
|
||||
'context' => $s['context'] ?? '',
|
||||
'status' => $s['status'] ?? '',
|
||||
'target_url' => $s['target_url'] ?? '',
|
||||
], $pr['ci_statuses'] ?? []);
|
||||
|
||||
return $dto;
|
||||
}, $prs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
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
|
||||
{
|
||||
public function __construct(
|
||||
private GiteaApiService $giteaApiService,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
|
||||
{
|
||||
try {
|
||||
$repos = $this->giteaApiService->listRepositories();
|
||||
} catch (GiteaApiException $e) {
|
||||
throw new BadRequestHttpException($e->getMessage(), $e);
|
||||
}
|
||||
|
||||
return array_map(static function (array $repo): GiteaRepository {
|
||||
$dto = new GiteaRepository();
|
||||
$dto->fullName = $repo['full_name'] ?? '';
|
||||
$dto->name = $repo['name'] ?? '';
|
||||
$dto->owner = $repo['owner']['login'] ?? '';
|
||||
|
||||
return $dto;
|
||||
}, $repos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
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;
|
||||
|
||||
final readonly class GiteaSettingsProcessor implements ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private GiteaConfigurationRepositoryInterface $configRepository,
|
||||
private TokenEncryptor $tokenEncryptor,
|
||||
) {}
|
||||
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): GiteaSettings
|
||||
{
|
||||
assert($data instanceof GiteaSettings);
|
||||
|
||||
$config = $this->configRepository->findSingleton();
|
||||
if (null === $config) {
|
||||
$config = new GiteaConfiguration();
|
||||
}
|
||||
|
||||
$config->setUrl($data->url);
|
||||
|
||||
if (null !== $data->token && '' !== $data->token) {
|
||||
$config->setEncryptedToken($this->tokenEncryptor->encrypt($data->token));
|
||||
}
|
||||
|
||||
$this->em->persist($config);
|
||||
$this->em->flush();
|
||||
|
||||
$result = new GiteaSettings();
|
||||
$result->url = $config->getUrl();
|
||||
$result->hasToken = $config->hasToken();
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
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 GiteaConfigurationRepositoryInterface $configRepository,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): GiteaSettings
|
||||
{
|
||||
$config = $this->configRepository->findSingleton();
|
||||
$dto = new GiteaSettings();
|
||||
|
||||
if (null !== $config) {
|
||||
$dto->url = $config->getUrl();
|
||||
$dto->hasToken = $config->hasToken();
|
||||
}
|
||||
|
||||
return $dto;
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\GiteaTestConnection;
|
||||
use App\Module\Integration\Infrastructure\Service\GiteaApiService;
|
||||
|
||||
final readonly class GiteaTestConnectionProvider implements ProviderInterface, ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private GiteaApiService $giteaApiService,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): GiteaTestConnection
|
||||
{
|
||||
return new GiteaTestConnection();
|
||||
}
|
||||
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): GiteaTestConnection
|
||||
{
|
||||
$result = new GiteaTestConnection();
|
||||
$result->success = $this->giteaApiService->testConnection();
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
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;
|
||||
|
||||
final readonly class ShareSettingsProcessor implements ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private ShareConfigurationRepositoryInterface $configRepository,
|
||||
private TokenEncryptor $tokenEncryptor,
|
||||
) {}
|
||||
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ShareSettings
|
||||
{
|
||||
assert($data instanceof ShareSettings);
|
||||
|
||||
$config = $this->configRepository->findSingleton() ?? new ShareConfiguration();
|
||||
|
||||
$config->setHost($data->host);
|
||||
$config->setShareName($data->shareName);
|
||||
$config->setBasePath($data->basePath);
|
||||
$config->setDomain($data->domain);
|
||||
$config->setUsername($data->username);
|
||||
$config->setEnabled($data->enabled);
|
||||
|
||||
if (null !== $data->password && '' !== $data->password) {
|
||||
$config->setEncryptedPassword($this->tokenEncryptor->encrypt($data->password));
|
||||
}
|
||||
|
||||
$this->em->persist($config);
|
||||
$this->em->flush();
|
||||
|
||||
$result = new ShareSettings();
|
||||
$result->host = $config->getHost();
|
||||
$result->shareName = $config->getShareName();
|
||||
$result->basePath = $config->getBasePath();
|
||||
$result->domain = $config->getDomain();
|
||||
$result->username = $config->getUsername();
|
||||
$result->enabled = $config->isEnabled();
|
||||
$result->hasPassword = $config->hasPassword();
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
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 ShareConfigurationRepositoryInterface $configRepository,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ShareSettings
|
||||
{
|
||||
$config = $this->configRepository->findSingleton();
|
||||
$dto = new ShareSettings();
|
||||
|
||||
if (null !== $config) {
|
||||
$dto->host = $config->getHost();
|
||||
$dto->shareName = $config->getShareName();
|
||||
$dto->basePath = $config->getBasePath();
|
||||
$dto->domain = $config->getDomain();
|
||||
$dto->username = $config->getUsername();
|
||||
$dto->enabled = $config->isEnabled();
|
||||
$dto->hasPassword = $config->hasPassword();
|
||||
}
|
||||
|
||||
return $dto;
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Module\Integration\Domain\Service\FileSource;
|
||||
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\ShareTestConnection;
|
||||
|
||||
final readonly class ShareTestConnectionProvider implements ProviderInterface, ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private FileSource $fileSource,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ShareTestConnection
|
||||
{
|
||||
return new ShareTestConnection();
|
||||
}
|
||||
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ShareTestConnection
|
||||
{
|
||||
$result = $this->fileSource->test();
|
||||
|
||||
$dto = new ShareTestConnection();
|
||||
$dto->success = $result->success;
|
||||
$dto->message = $result->message;
|
||||
|
||||
return $dto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
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;
|
||||
|
||||
final readonly class ZimbraSettingsProcessor implements ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private ZimbraConfigurationRepositoryInterface $configRepository,
|
||||
private TokenEncryptor $tokenEncryptor,
|
||||
) {}
|
||||
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ZimbraSettings
|
||||
{
|
||||
assert($data instanceof ZimbraSettings);
|
||||
|
||||
$config = $this->configRepository->findSingleton();
|
||||
if (null === $config) {
|
||||
$config = new ZimbraConfiguration();
|
||||
}
|
||||
|
||||
$config->setServerUrl($data->serverUrl);
|
||||
$config->setUsername($data->username);
|
||||
$config->setCalendarPath($data->calendarPath);
|
||||
$config->setEnabled($data->enabled);
|
||||
|
||||
if (null !== $data->password && '' !== $data->password) {
|
||||
$config->setEncryptedPassword($this->tokenEncryptor->encrypt($data->password));
|
||||
}
|
||||
|
||||
$this->em->persist($config);
|
||||
$this->em->flush();
|
||||
|
||||
$result = new ZimbraSettings();
|
||||
$result->serverUrl = $config->getServerUrl();
|
||||
$result->username = $config->getUsername();
|
||||
$result->calendarPath = $config->getCalendarPath();
|
||||
$result->enabled = $config->isEnabled();
|
||||
$result->hasPassword = $config->hasPassword();
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
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 ZimbraConfigurationRepositoryInterface $configRepository,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ZimbraSettings
|
||||
{
|
||||
$config = $this->configRepository->findSingleton();
|
||||
$dto = new ZimbraSettings();
|
||||
|
||||
if (null !== $config) {
|
||||
$dto->serverUrl = $config->getServerUrl();
|
||||
$dto->username = $config->getUsername();
|
||||
$dto->calendarPath = $config->getCalendarPath();
|
||||
$dto->enabled = $config->isEnabled();
|
||||
$dto->hasPassword = $config->hasPassword();
|
||||
}
|
||||
|
||||
return $dto;
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Integration\Infrastructure\ApiPlatform\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProcessorInterface;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Module\Integration\Infrastructure\ApiPlatform\Resource\ZimbraTestConnection;
|
||||
use App\Module\ProjectManagement\Infrastructure\Service\CalDavService;
|
||||
use Throwable;
|
||||
|
||||
final readonly class ZimbraTestConnectionProvider implements ProviderInterface, ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private CalDavService $calDavService,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ZimbraTestConnection
|
||||
{
|
||||
return new ZimbraTestConnection();
|
||||
}
|
||||
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ZimbraTestConnection
|
||||
{
|
||||
$result = new ZimbraTestConnection();
|
||||
|
||||
try {
|
||||
$result->success = $this->calDavService->testConnection();
|
||||
} catch (Throwable) {
|
||||
$result->success = false;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user