feat: 2 way conversion and export
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -13,6 +13,7 @@ use InvalidArgumentException;
|
||||
use KTXC\Http\Response\JsonResponse;
|
||||
use KTXC\Http\Response\Response;
|
||||
use KTXC\Http\Response\StreamedNdJsonResponse;
|
||||
use KTXC\Http\Response\StreamedResponse;
|
||||
use KTXC\SessionIdentity;
|
||||
use KTXC\SessionTenant;
|
||||
use KTXF\Controller\ControllerAbstract;
|
||||
@@ -23,6 +24,7 @@ use KTXF\Resource\Identifier\ResourceIdentifier;
|
||||
use KTXF\Resource\Identifier\ResourceIdentifiers;
|
||||
use KTXF\Resource\Identifier\ServiceIdentifier;
|
||||
use KTXF\Routing\Attributes\AuthenticatedRoute;
|
||||
use KTXM\ChronoManager\Export\ExportService;
|
||||
use KTXM\ChronoManager\Import\ImportOptions;
|
||||
use KTXM\ChronoManager\Import\ImportService;
|
||||
use KTXM\ChronoManager\Manager;
|
||||
@@ -53,6 +55,7 @@ class DefaultController extends ControllerAbstract {
|
||||
private readonly SessionIdentity $userIdentity,
|
||||
private readonly Manager $manager,
|
||||
private readonly ImportService $importService,
|
||||
private readonly ExportService $exportService,
|
||||
private readonly LoggerInterface $logger,
|
||||
) {}
|
||||
|
||||
@@ -156,6 +159,7 @@ class DefaultController extends ControllerAbstract {
|
||||
'entity.delete' => $this->entityDelete($tenantId, $userId, $data),
|
||||
'entity.move' => $this->entityMove($tenantId, $userId, $data),
|
||||
'entity.import' => $this->entityImport($tenantId, $userId, $data, $version, $transaction),
|
||||
'entity.export' => $this->entityExport($tenantId, $userId, $data),
|
||||
|
||||
default => throw new InvalidArgumentException(self::ERR_INVALID_OPERATION . $operation)
|
||||
};
|
||||
@@ -607,6 +611,45 @@ class DefaultController extends ControllerAbstract {
|
||||
return new StreamedNdJsonResponse($response, 1, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export calendar entities as a streamed iCalendar document.
|
||||
*
|
||||
* Request data: { sources: ["provider:service:collection", "provider:service:collection:entity", ...], filename?: "calendar.ics" }
|
||||
*/
|
||||
private function entityExport(string $tenantId, string $userId, array $data): StreamedResponse {
|
||||
|
||||
if (!isset($data['sources'])) {
|
||||
throw new InvalidArgumentException(self::ERR_MISSING_SOURCES);
|
||||
}
|
||||
if (!is_array($data['sources']) || $data['sources'] === []) {
|
||||
throw new InvalidArgumentException(self::ERR_INVALID_SOURCES);
|
||||
}
|
||||
|
||||
$sources = ResourceIdentifiers::fromArray($data['sources']);
|
||||
foreach ($sources as $source) {
|
||||
if (!$source instanceof CollectionIdentifier && !$source instanceof EntityIdentifier) {
|
||||
throw new InvalidArgumentException('Invalid parameter: sources must contain provider:service:collection or provider:service:collection:entity identifiers');
|
||||
}
|
||||
}
|
||||
|
||||
$filename = 'export.ics';
|
||||
if (isset($data['filename']) && is_string($data['filename'])) {
|
||||
$sanitized = preg_replace('/[^A-Za-z0-9._-]+/', '_', trim($data['filename']));
|
||||
if ($sanitized !== '' && $sanitized !== null) {
|
||||
$filename = str_ends_with(strtolower($sanitized), '.ics') ? $sanitized : $sanitized . '.ics';
|
||||
}
|
||||
}
|
||||
|
||||
return new StreamedResponse(
|
||||
$this->exportService->export($sources, $tenantId, $userId),
|
||||
200,
|
||||
[
|
||||
'Content-Type' => 'text/calendar; charset=utf-8',
|
||||
'Content-Disposition' => 'attachment; filename="' . $filename . '"',
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a generator of JsonSerializable domain objects in the canonical NDJSON
|
||||
* stream envelope shared by every streaming operation:
|
||||
|
||||
Reference in New Issue
Block a user