From b986081ce3f71126aea9fc736eec37a2523dcea4 Mon Sep 17 00:00:00 2001
From: mcop1 <89011527+mcop1@users.noreply.github.com>
Date: Wed, 22 Jan 2025 10:59:33 +0100
Subject: [PATCH] [Improvement] Reports export csv (#709)
* Added csv export messages, handler and controller
* Refactor csv export service part I
* Refactor csv export service part I
* Apply php-cs-fixer changes
* Refactor csv export service part 2
* Apply php-cs-fixer changes
* Added custom report csv endpoint
* Apply php-cs-fixer changes
* Deleted unnecessary class
* Changed endpoint to post
* Apply php-cs-fixer changes
* Moved download/delete csv endpoint to export tag
* Apply php-cs-fixer changes
* Fix tests
* Apply php-cs-fixer changes
* Permissions
* Apply php-cs-fixer changes
* Inject interface instead of service, added api tag
---
config/assets.yaml | 2 -
config/custom_reports.yaml | 18 ++-
config/export.yaml | 33 +++++
config/pimcore/execution_engine.yaml | 5 +-
.../Download/DeleteZipController.php | 2 +-
.../Download/DownloadZipController.php | 2 +-
.../Handler/CsvAssetDataCollectionHandler.php | 2 +-
.../CsvFolderDataCollectionHandler.php | 2 +-
src/Asset/ExecutionEngine/Util/JobSteps.php | 1 -
src/Asset/Service/DownloadService.php | 95 -------------
.../Service/DownloadServiceInterface.php | 24 ----
.../Service/ExecutionEngine/CsvService.php | 77 +----------
.../ExecutionEngine/CsvServiceInterface.php | 21 ---
.../Request/CsvExportRequestBody.php | 75 ++++++++++
.../Controller/Chart/GetController.php | 6 +-
.../Export/Csv/ExportController.php | 75 ++++++++++
.../Handler/CsvCollectionHandler.php | 101 ++++++++++++++
.../Messages/CsvCollectionMessage.php | 26 ++++
.../ExecutionEngine/Util/JobSteps.php | 21 +++
...tDataParameter.php => ExportParameter.php} | 42 +++++-
.../Repository/CustomReportRepository.php | 2 +-
.../CustomReportRepositoryInterface.php | 2 +-
src/CustomReport/Service/AdapterService.php | 6 +-
.../Service/AdapterServiceInterface.php | 4 +-
src/CustomReport/Service/CsvService.php | 81 +++++++++++
.../Service/CsvServiceInterface.php | 27 ++++
.../Service/CustomReportService.php | 31 ++++-
.../Service/CustomReportServiceInterface.php | 10 +-
.../PimcoreStudioBackendExtension.php | 4 +-
src/ExecutionEngine/Util/StepConfig.php | 8 +-
.../Download/DeleteCsvController.php | 27 ++--
.../Download/DownloadCsvController.php | 31 ++---
src/Export/Csv/CsvExportService.php | 129 ++++++++++++++++++
.../Csv}/CsvCreationSubscriber.php | 19 +--
.../Messenger/Handler/CsvCreationHandler.php | 38 +++---
.../Messenger/Messages/CsvCreationMessage.php | 2 +-
src/Export/ExecutionEngine/Util/JobSteps.php | 21 +++
src/Export/ExportServiceInterface.php | 36 +++++
src/Export/Service/DownloadService.php | 129 ++++++++++++++++++
.../Service/DownloadServiceInterface.php | 49 +++++++
.../Parameter/Query/BoolParameter.php | 40 ++++++
.../Parameter/Query/FilterParameter.php | 4 +-
src/OpenApi/Config/Tags.php | 5 +
translations/studio.en.yaml | 2 +-
translations/studio_api_docs.en.yaml | 26 +++-
45 files changed, 1046 insertions(+), 317 deletions(-)
create mode 100644 config/export.yaml
create mode 100644 src/CustomReport/Attribute/Request/CsvExportRequestBody.php
create mode 100644 src/CustomReport/Controller/Export/Csv/ExportController.php
create mode 100644 src/CustomReport/ExecutionEngine/AutomationAction/Messenger/Handler/CsvCollectionHandler.php
create mode 100644 src/CustomReport/ExecutionEngine/AutomationAction/Messenger/Messages/CsvCollectionMessage.php
create mode 100644 src/CustomReport/ExecutionEngine/Util/JobSteps.php
rename src/CustomReport/MappedParameter/{ChartDataParameter.php => ExportParameter.php} (59%)
create mode 100644 src/CustomReport/Service/CsvService.php
create mode 100644 src/CustomReport/Service/CsvServiceInterface.php
rename src/{Asset => Export}/Controller/Download/DeleteCsvController.php (69%)
rename src/{Asset => Export}/Controller/Download/DownloadCsvController.php (71%)
create mode 100644 src/Export/Csv/CsvExportService.php
rename src/{Asset/EventSubscriber => Export/EventSubscriber/Csv}/CsvCreationSubscriber.php (73%)
rename src/{Asset => Export}/ExecutionEngine/AutomationAction/Messenger/Handler/CsvCreationHandler.php (69%)
rename src/{Asset => Export}/ExecutionEngine/AutomationAction/Messenger/Messages/CsvCreationMessage.php (86%)
create mode 100644 src/Export/ExecutionEngine/Util/JobSteps.php
create mode 100644 src/Export/ExportServiceInterface.php
create mode 100644 src/Export/Service/DownloadService.php
create mode 100644 src/Export/Service/DownloadServiceInterface.php
create mode 100644 src/OpenApi/Attribute/Parameter/Query/BoolParameter.php
diff --git a/config/assets.yaml b/config/assets.yaml
index 8cb85b579..375559793 100644
--- a/config/assets.yaml
+++ b/config/assets.yaml
@@ -85,7 +85,6 @@ services:
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Handler\AssetCloneHandler: ~
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Handler\AssetUploadHandler: ~
- Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Handler\CsvCreationHandler: ~
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Handler\CsvAssetDataCollectionHandler: ~
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Handler\CsvFolderDataCollectionHandler: ~
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Handler\ZipDownloadHandler: ~
@@ -96,7 +95,6 @@ services:
#
Pimcore\Bundle\StudioBackendBundle\Asset\EventSubscriber\CloneSubscriber: ~
- Pimcore\Bundle\StudioBackendBundle\Asset\EventSubscriber\CsvCreationSubscriber: ~
Pimcore\Bundle\StudioBackendBundle\Asset\EventSubscriber\UploadSubscriber: ~
Pimcore\Bundle\StudioBackendBundle\Asset\EventSubscriber\ZipDownloadSubscriber: ~
Pimcore\Bundle\StudioBackendBundle\Asset\EventSubscriber\ZipUploadSubscriber: ~
diff --git a/config/custom_reports.yaml b/config/custom_reports.yaml
index 65163a048..0fabba62c 100644
--- a/config/custom_reports.yaml
+++ b/config/custom_reports.yaml
@@ -30,10 +30,26 @@ services:
# Services
#
+ Pimcore\Bundle\StudioBackendBundle\CustomReport\Service\CsvServiceInterface:
+ class: Pimcore\Bundle\StudioBackendBundle\CustomReport\Service\CsvService
+
Pimcore\Bundle\StudioBackendBundle\CustomReport\Service\CustomReportServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\CustomReport\Service\CustomReportService
Pimcore\Bundle\StudioBackendBundle\CustomReport\Service\AdapterServiceInterface:
class: Pimcore\Bundle\StudioBackendBundle\CustomReport\Service\AdapterService
arguments:
- $adapters: '@pimcore.custom_report.adapter.factories'
\ No newline at end of file
+ $adapters: '@pimcore.custom_report.adapter.factories'
+
+ #
+ # Messages
+ #
+
+ Pimcore\Bundle\StudioBackendBundle\CustomReport\ExecutionEngine\AutomationAction\Messenger\Messages\CsvCollectionMessage: ~
+
+ #
+ # Handler
+ #
+
+ Pimcore\Bundle\StudioBackendBundle\CustomReport\ExecutionEngine\AutomationAction\Messenger\Handler\CsvCollectionHandler: ~
+
diff --git a/config/export.yaml b/config/export.yaml
new file mode 100644
index 000000000..3ab52404e
--- /dev/null
+++ b/config/export.yaml
@@ -0,0 +1,33 @@
+services:
+ _defaults:
+ autowire: true
+ autoconfigure: true
+ public: false
+
+ # controllers are imported separately to make sure they're public
+ # and have a tag that allows actions to type-hint services
+ Pimcore\Bundle\StudioBackendBundle\Export\Controller\:
+ resource: '../src/Export/Controller'
+ public: true
+ tags: [ 'controller.service_arguments' ]
+
+ #
+ # Handler
+ #
+
+ Pimcore\Bundle\StudioBackendBundle\Export\ExecutionEngine\AutomationAction\Messenger\Handler\CsvCreationHandler: ~
+
+ #
+ # Services
+ #
+
+ Pimcore\Bundle\StudioBackendBundle\Export\Csv\CsvExportService: ~
+ Pimcore\Bundle\StudioBackendBundle\Export\ExportServiceInterface: '@Pimcore\Bundle\StudioBackendBundle\Export\Csv\CsvExportService'
+ Pimcore\Bundle\StudioBackendBundle\Export\Service\DownloadServiceInterface:
+ class: Pimcore\Bundle\StudioBackendBundle\Export\Service\DownloadService
+
+ #
+ # Event Subscriber
+ #
+
+ Pimcore\Bundle\StudioBackendBundle\Export\EventSubscriber\Csv\CsvCreationSubscriber: ~
\ No newline at end of file
diff --git a/config/pimcore/execution_engine.yaml b/config/pimcore/execution_engine.yaml
index b2140025f..77185cd68 100644
--- a/config/pimcore/execution_engine.yaml
+++ b/config/pimcore/execution_engine.yaml
@@ -13,7 +13,6 @@ framework:
routing:
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\CsvAssetCollectionMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\CsvFolderCollectionMessage: pimcore_generic_execution_engine
- Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\CsvCreationMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\AssetCloneMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\AssetUploadMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\ZipDownloadMessage: pimcore_generic_execution_engine
@@ -23,5 +22,7 @@ framework:
Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Messages\PatchMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Messages\PatchFolderMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\Element\ExecutionEngine\AutomationAction\Messenger\Messages\RewriteRefMessage: pimcore_generic_execution_engine
+ Pimcore\Bundle\StudioBackendBundle\Export\ExecutionEngine\AutomationAction\Messenger\Messages\CsvCreationMessage: pimcore_generic_execution_engine
Pimcore\Bundle\StudioBackendBundle\DataObject\ExecutionEngine\AutomationAction\Messenger\Messages\CloneMessage: pimcore_generic_execution_engine
- Pimcore\Bundle\StudioBackendBundle\Tag\ExecutionEngine\AutomationAction\Messenger\Messages\BatchTagOperationMessage: pimcore_generic_execution_engine
\ No newline at end of file
+ Pimcore\Bundle\StudioBackendBundle\Tag\ExecutionEngine\AutomationAction\Messenger\Messages\BatchTagOperationMessage: pimcore_generic_execution_engine
+ Pimcore\Bundle\StudioBackendBundle\CustomReport\ExecutionEngine\AutomationAction\Messenger\Messages\CsvCollectionMessage: pimcore_generic_execution_engine
\ No newline at end of file
diff --git a/src/Asset/Controller/Download/DeleteZipController.php b/src/Asset/Controller/Download/DeleteZipController.php
index 7c7282091..4f0f8ee7f 100644
--- a/src/Asset/Controller/Download/DeleteZipController.php
+++ b/src/Asset/Controller/Download/DeleteZipController.php
@@ -17,11 +17,11 @@
namespace Pimcore\Bundle\StudioBackendBundle\Asset\Controller\Download;
use OpenApi\Attributes\Delete;
-use Pimcore\Bundle\StudioBackendBundle\Asset\Service\DownloadServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Asset\Service\ExecutionEngine\ZipServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ForbiddenException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
+use Pimcore\Bundle\StudioBackendBundle\Export\Service\DownloadServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Parameter\Path\IdParameter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\DefaultResponses;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\SuccessResponse;
diff --git a/src/Asset/Controller/Download/DownloadZipController.php b/src/Asset/Controller/Download/DownloadZipController.php
index 2986f5f87..ffe746725 100644
--- a/src/Asset/Controller/Download/DownloadZipController.php
+++ b/src/Asset/Controller/Download/DownloadZipController.php
@@ -18,13 +18,13 @@
use OpenApi\Attributes\Get;
use Pimcore\Bundle\StudioBackendBundle\Asset\Attribute\Response\Header\ContentDisposition;
-use Pimcore\Bundle\StudioBackendBundle\Asset\Service\DownloadServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Asset\Service\ExecutionEngine\ZipServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\EnvironmentException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ForbiddenException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\StreamResourceNotFoundException;
+use Pimcore\Bundle\StudioBackendBundle\Export\Service\DownloadServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Parameter\Path\IdParameter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\Content\MediaType;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\DefaultResponses;
diff --git a/src/Asset/ExecutionEngine/AutomationAction/Messenger/Handler/CsvAssetDataCollectionHandler.php b/src/Asset/ExecutionEngine/AutomationAction/Messenger/Handler/CsvAssetDataCollectionHandler.php
index 64feb6a97..be09c6d05 100644
--- a/src/Asset/ExecutionEngine/AutomationAction/Messenger/Handler/CsvAssetDataCollectionHandler.php
+++ b/src/Asset/ExecutionEngine/AutomationAction/Messenger/Handler/CsvAssetDataCollectionHandler.php
@@ -98,7 +98,7 @@ public function __invoke(CsvAssetCollectionMessage $message): void
),
];
- $this->updateContextArrayValues($jobRun, StepConfig::ASSET_EXPORT_DATA->value, $assetData);
+ $this->updateContextArrayValues($jobRun, StepConfig::CSV_EXPORT_DATA->value, $assetData);
} catch (Exception $e) {
$this->abort($this->getAbortData(
Config::CSV_DATA_COLLECTION_FAILED_MESSAGE->value,
diff --git a/src/Asset/ExecutionEngine/AutomationAction/Messenger/Handler/CsvFolderDataCollectionHandler.php b/src/Asset/ExecutionEngine/AutomationAction/Messenger/Handler/CsvFolderDataCollectionHandler.php
index 2347c3d84..5c170fa8b 100644
--- a/src/Asset/ExecutionEngine/AutomationAction/Messenger/Handler/CsvFolderDataCollectionHandler.php
+++ b/src/Asset/ExecutionEngine/AutomationAction/Messenger/Handler/CsvFolderDataCollectionHandler.php
@@ -107,7 +107,7 @@ public function __invoke(CsvFolderCollectionMessage $message): void
),
];
- $this->updateContextArrayValues($jobRun, StepConfig::ASSET_EXPORT_DATA->value, $assetData);
+ $this->updateContextArrayValues($jobRun, StepConfig::CSV_EXPORT_DATA->value, $assetData);
} catch (Exception $e) {
$this->abort($this->getAbortData(
Config::CSV_DATA_COLLECTION_FAILED_MESSAGE->value,
diff --git a/src/Asset/ExecutionEngine/Util/JobSteps.php b/src/Asset/ExecutionEngine/Util/JobSteps.php
index 0c8c5d9b8..7ca4345b8 100644
--- a/src/Asset/ExecutionEngine/Util/JobSteps.php
+++ b/src/Asset/ExecutionEngine/Util/JobSteps.php
@@ -23,5 +23,4 @@ enum JobSteps: string
case ASSET_CLONING = 'studio_ee_job_step_asset_cloning';
case ASSET_UPLOADING = 'studio_ee_job_step_asset_uploading';
case CSV_COLLECTION = 'studio_ee_job_step_csv_collection';
- case CSV_CREATION = 'studio_ee_job_step_csv_creation';
}
diff --git a/src/Asset/Service/DownloadService.php b/src/Asset/Service/DownloadService.php
index 4b023e191..495f8c361 100644
--- a/src/Asset/Service/DownloadService.php
+++ b/src/Asset/Service/DownloadService.php
@@ -17,20 +17,12 @@
namespace Pimcore\Bundle\StudioBackendBundle\Asset\Service;
use Exception;
-use League\Flysystem\FilesystemException;
-use League\Flysystem\FilesystemOperator;
use Pimcore\Bundle\StudioBackendBundle\Asset\MappedParameter\ImageDownloadConfigParameter;
-use Pimcore\Bundle\StudioBackendBundle\Element\Service\StorageServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ElementStreamResourceNotFoundException;
-use Pimcore\Bundle\StudioBackendBundle\Exception\Api\EnvironmentException;
-use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ForbiddenException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidAssetFormatTypeException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidElementTypeException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidThumbnailException;
-use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
-use Pimcore\Bundle\StudioBackendBundle\Exception\Api\StreamResourceNotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ThumbnailResizingFailedException;
-use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Service\ExecutionEngineServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\Asset\FormatTypes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseHeaders;
use Pimcore\Bundle\StudioBackendBundle\Util\Trait\StreamedResponseTrait;
@@ -41,7 +33,6 @@
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\StreamedResponse;
use function in_array;
-use function sprintf;
/**
* @internal
@@ -52,8 +43,6 @@
use TempFilePathTrait;
public function __construct(
- private ExecutionEngineServiceInterface $executionEngineService,
- private StorageServiceInterface $storageService,
private ThumbnailServiceInterface $thumbnailService,
private array $defaultFormats,
) {
@@ -145,88 +134,4 @@ public function downloadImageByThumbnail(
false
);
}
-
- /**
- * @throws EnvironmentException|ForbiddenException|NotFoundException|StreamResourceNotFoundException
- */
- public function downloadResourceByJobRunId(
- int $jobRunId,
- string $tempFileName,
- string $tempFolderName,
- string $mimeType,
- string $downloadName,
- ): StreamedResponse {
- $this->executionEngineService->validateJobRun($jobRunId);
- $fileName = $this->getTempFileName($jobRunId, $tempFileName);
- $folderName = $this->getTempFileName($jobRunId, $tempFolderName);
- $filePath = $folderName . '/' . $fileName;
-
- $streamedResponse = $this->getFileStreamedResponse(
- $filePath,
- $mimeType,
- $downloadName,
- $this->validateStorage($filePath, $jobRunId)
- );
-
- try {
- $this->storageService->cleanUpFolder($folderName);
- } catch (FilesystemException) {
- throw new EnvironmentException(
- sprintf(
- 'Failed to clean up temporary folder %s',
- $folderName
- )
- );
- }
-
- return $streamedResponse;
- }
-
- /**
- * @throws EnvironmentException|NotFoundException
- */
- public function cleanupDataByJobRunId(
- int $jobRunId,
- string $folderName,
- string $fileName
- ): void {
- $this->executionEngineService->validateJobRun($jobRunId);
- $this->validateStorage($this->getTempFilePath($jobRunId, $folderName . '/' . $fileName), $jobRunId);
-
- try {
- $this->storageService->cleanUpFolder(
- $this->getTempFileName(
- $jobRunId,
- $folderName
- ),
- true
- );
- } catch (FilesystemException $e) {
- throw new EnvironmentException(
- sprintf(
- 'Failed to delete file based on jobRunId %d: %s',
- $jobRunId,
- $e->getMessage()
- ),
- );
- }
- }
-
- /**
- * @throws EnvironmentException
- */
- private function validateStorage(string $filePath, int $jobRunId): FilesystemOperator
- {
- $storage = $this->storageService->getTempStorage();
- if (!$this->storageService->tempFileExists($filePath)) {
- throw new EnvironmentException(
- sprintf(
- 'Resource not found for jobRun with Id %d',
- $jobRunId
- )
- );
- }
-
- return $storage;
- }
}
diff --git a/src/Asset/Service/DownloadServiceInterface.php b/src/Asset/Service/DownloadServiceInterface.php
index e9af47e4d..28cafaae5 100644
--- a/src/Asset/Service/DownloadServiceInterface.php
+++ b/src/Asset/Service/DownloadServiceInterface.php
@@ -18,12 +18,8 @@
use Pimcore\Bundle\StudioBackendBundle\Asset\MappedParameter\ImageDownloadConfigParameter;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ElementStreamResourceNotFoundException;
-use Pimcore\Bundle\StudioBackendBundle\Exception\Api\EnvironmentException;
-use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ForbiddenException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidAssetFormatTypeException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidElementTypeException;
-use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
-use Pimcore\Bundle\StudioBackendBundle\Exception\Api\StreamResourceNotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ThumbnailResizingFailedException;
use Pimcore\Model\Asset;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
@@ -64,24 +60,4 @@ public function downloadImageByThumbnail(
Asset $image,
string $thumbnailName
): BinaryFileResponse;
-
- /**
- * @throws EnvironmentException|ForbiddenException|NotFoundException|StreamResourceNotFoundException
- */
- public function downloadResourceByJobRunId(
- int $jobRunId,
- string $tempFileName,
- string $tempFolderName,
- string $mimeType,
- string $downloadName,
- ): StreamedResponse;
-
- /**
- * @throws EnvironmentException|NotFoundException
- */
- public function cleanupDataByJobRunId(
- int $jobRunId,
- string $folderName,
- string $fileName
- ): void;
}
diff --git a/src/Asset/Service/ExecutionEngine/CsvService.php b/src/Asset/Service/ExecutionEngine/CsvService.php
index 0a917fba8..3c0efb7c2 100644
--- a/src/Asset/Service/ExecutionEngine/CsvService.php
+++ b/src/Asset/Service/ExecutionEngine/CsvService.php
@@ -16,25 +16,20 @@
namespace Pimcore\Bundle\StudioBackendBundle\Asset\Service\ExecutionEngine;
-use League\Flysystem\FilesystemException;
-use League\Flysystem\FilesystemOperator;
use Pimcore\Bundle\GenericExecutionEngineBundle\Agent\JobExecutionAgentInterface;
use Pimcore\Bundle\GenericExecutionEngineBundle\Model\Job;
use Pimcore\Bundle\GenericExecutionEngineBundle\Model\JobStep;
use Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\CsvAssetCollectionMessage;
-use Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\CsvCreationMessage;
use Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\CsvFolderCollectionMessage;
use Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\Util\JobSteps;
use Pimcore\Bundle\StudioBackendBundle\Asset\MappedParameter\ExportAssetParameter;
use Pimcore\Bundle\StudioBackendBundle\Asset\MappedParameter\ExportFolderParameter;
-use Pimcore\Bundle\StudioBackendBundle\Element\Service\StorageServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\Config;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\Jobs;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\StepConfig;
-use Pimcore\Bundle\StudioBackendBundle\Grid\Service\GridServiceInterface;
-use Pimcore\Bundle\StudioBackendBundle\Grid\Util\Collection\ColumnCollection;
+use Pimcore\Bundle\StudioBackendBundle\Export\ExecutionEngine\AutomationAction\Messenger\Messages\CsvCreationMessage;
+use Pimcore\Bundle\StudioBackendBundle\Export\ExecutionEngine\Util\JobSteps as ExportJobSteps;
use Pimcore\Bundle\StudioBackendBundle\Security\Service\SecurityServiceInterface;
-use Pimcore\Bundle\StudioBackendBundle\Util\Trait\TempFilePathTrait;
use Pimcore\Model\Element\ElementDescriptor;
/**
@@ -42,14 +37,9 @@
*/
final readonly class CsvService implements CsvServiceInterface
{
- use TempFilePathTrait;
-
public function __construct(
private JobExecutionAgentInterface $jobExecutionAgent,
- private SecurityServiceInterface $securityService,
- private StorageServiceInterface $storageService,
- private GridServiceInterface $gridService,
- private string $defaultDelimiter,
+ private SecurityServiceInterface $securityService
) {
}
@@ -93,32 +83,6 @@ public function generateCsvFileForFolders(ExportFolderParameter $exportFolderPar
);
}
- /**
- * @throws FilesystemException
- */
- public function createCsvFile(
- int $id,
- ColumnCollection $columnCollection,
- array $settings,
- array $assetData,
- ?string $delimiter = null,
- ): void {
- $storage = $this->storageService->getTempStorage();
- $headers = $this->getHeaders($columnCollection, $settings);
- if ($delimiter === null) {
- $delimiter = $this->defaultDelimiter;
- }
- $data[] = implode($delimiter, $headers) . StepConfig::NEW_LINE->value;
- foreach ($assetData as $row) {
- $data[] = implode($delimiter, array_map([$this, 'encodeFunc'], $row)) . StepConfig::NEW_LINE->value;
- }
-
- $storage->write(
- $this->getCsvFilePath($id, $storage),
- implode($data)
- );
- }
-
private function generateCsvFileJob(
array $elements,
array $collectionSettings,
@@ -141,39 +105,6 @@ private function generateCsvFileJob(
return $jobRun->getId();
}
- /**
- * @throws FilesystemException
- */
- private function getCsvFilePath(int $id, FilesystemOperator $storage): string
- {
- $folderName = $this->getTempFileName($id, self::CSV_FOLDER_NAME);
- $file = $this->getTempFileName($id, self::CSV_FILE_NAME);
- $storage->createDirectory($folderName);
-
- return $folderName . '/' . $file;
- }
-
- private function encodeFunc(?string $value): string
- {
- $value = str_replace('"', '""', $value ?? '');
-
- //force wrap value in quotes and return
- return '"' . $value . '"';
- }
-
- private function getHeaders(ColumnCollection $columnCollection, array $settings): array
- {
- $header = $settings[StepConfig::SETTINGS_HEADER->value] ?? StepConfig::SETTINGS_HEADER_NO_HEADER->value;
- if ($header === StepConfig::SETTINGS_HEADER_NO_HEADER->value) {
- return [];
- }
-
- return $this->gridService->getColumnKeys(
- $columnCollection,
- $header === StepConfig::SETTINGS_HEADER_NAME->value
- );
- }
-
private function mapJobSteps(
array $elements,
array $collectionSettings,
@@ -194,7 +125,7 @@ private function mapJobSteps(
private function getCsvCreationStep(array $settings): JobStep
{
return new JobStep(
- JobSteps::CSV_CREATION->value,
+ ExportJobSteps::CSV_CREATION->value,
CsvCreationMessage::class,
'',
$settings
diff --git a/src/Asset/Service/ExecutionEngine/CsvServiceInterface.php b/src/Asset/Service/ExecutionEngine/CsvServiceInterface.php
index 52f94b830..13ef2d7a8 100644
--- a/src/Asset/Service/ExecutionEngine/CsvServiceInterface.php
+++ b/src/Asset/Service/ExecutionEngine/CsvServiceInterface.php
@@ -16,36 +16,15 @@
namespace Pimcore\Bundle\StudioBackendBundle\Asset\Service\ExecutionEngine;
-use League\Flysystem\FilesystemException;
use Pimcore\Bundle\StudioBackendBundle\Asset\MappedParameter\ExportAssetParameter;
use Pimcore\Bundle\StudioBackendBundle\Asset\MappedParameter\ExportFolderParameter;
-use Pimcore\Bundle\StudioBackendBundle\Grid\Util\Collection\ColumnCollection;
/**
* @internal
*/
interface CsvServiceInterface
{
- public const CSV_FILE_NAME = 'download-csv-{id}.csv';
-
- public const CSV_FOLDER_NAME = 'download-csv-{id}';
-
public function generateCsvFileForAssets(ExportAssetParameter $exportAssetParameter): int;
public function generateCsvFileForFolders(ExportFolderParameter $exportFolderParameter): int;
-
- /**
- * @throws FilesystemException
- */
- public function createCsvFile(
- int $id,
- ColumnCollection $columnCollection,
- array $settings,
- array $assetData,
- ?string $delimiter = null,
- ): void;
-
- public function getTempFileName(int $id, string $path): string;
-
- public function getTempFilePath(int $id, string $path): string;
}
diff --git a/src/CustomReport/Attribute/Request/CsvExportRequestBody.php b/src/CustomReport/Attribute/Request/CsvExportRequestBody.php
new file mode 100644
index 000000000..e54854f93
--- /dev/null
+++ b/src/CustomReport/Attribute/Request/CsvExportRequestBody.php
@@ -0,0 +1,75 @@
+jsonResponse(
$this->customReportService->getChartData($name, $chartDataParameter)
diff --git a/src/CustomReport/Controller/Export/Csv/ExportController.php b/src/CustomReport/Controller/Export/Csv/ExportController.php
new file mode 100644
index 000000000..d225d3e6a
--- /dev/null
+++ b/src/CustomReport/Controller/Export/Csv/ExportController.php
@@ -0,0 +1,75 @@
+value)]
+ #[Post(
+ path: self::PREFIX . '/custom-report/export/csv',
+ operationId: 'custom_report_export_csv',
+ description: 'custom_report_export_csv_description',
+ summary: 'custom_report_export_csv_summary',
+ tags: [Tags::CustomReports->value]
+ )]
+ #[CsvExportRequestBody]
+ #[CreatedResponse(
+ description: 'custom_report_export_csv_created_response',
+ content: new IdJson('ID of created jobRun', 'jobRunId')
+ )]
+ #[DefaultResponses([
+ HttpResponseCodes::UNAUTHORIZED,
+ HttpResponseCodes::NOT_FOUND,
+ ])]
+ public function exportCsv(
+ #[MapRequestPayload] ExportParameter $exportParameter
+ ): Response {
+ return $this->jsonResponse(
+ $this->csvService->generateCsvFile(
+ $exportParameter
+ )
+ );
+ }
+}
diff --git a/src/CustomReport/ExecutionEngine/AutomationAction/Messenger/Handler/CsvCollectionHandler.php b/src/CustomReport/ExecutionEngine/AutomationAction/Messenger/Handler/CsvCollectionHandler.php
new file mode 100644
index 000000000..ae34029cd
--- /dev/null
+++ b/src/CustomReport/ExecutionEngine/AutomationAction/Messenger/Handler/CsvCollectionHandler.php
@@ -0,0 +1,101 @@
+getJobRun($message);
+ if (!$this->shouldBeExecuted($jobRun)) {
+ return;
+ }
+ $name = '';
+
+ try {
+ $exportParameter = ExportParameter::fromArray(
+ $this->extractConfigFieldFromJobStepConfig($message, StepConfig::CUSTOM_REPORT_CONFIG->value)
+ );
+ $name = $exportParameter->getName();
+ $reportConfig = $this->customReportService->getCustomReportByName($name);
+ $exportFields = $this->customReportService->getFieldsForExport($reportConfig);
+ $reportData = $this->customReportAdapterService->getData(
+ $reportConfig,
+ $exportParameter
+ );
+ $csvData = $this->customReportService->generateCsvData(
+ $reportData,
+ $exportFields,
+ $exportParameter->getIncludeHeaders()
+ );
+
+ $this->updateContextArrayValues(
+ $this->getJobRun($message),
+ StepConfig::CSV_EXPORT_DATA->value,
+ $csvData
+ );
+ } catch (Exception $e) {
+ $this->abort($this->getAbortData(
+ Config::CSV_DATA_COLLECTION_FAILED_MESSAGE->value,
+ [
+ 'id' => $name,
+ 'message' => $e->getMessage(),
+ ]
+ ));
+ }
+
+ $this->updateProgress($this->publishService, $jobRun, $this->getJobStep($message)->getName());
+ }
+
+ protected function configureStep(): void
+ {
+ $this->stepConfiguration->setRequired(StepConfig::CUSTOM_REPORT_CONFIG->value);
+ $this->stepConfiguration->setAllowedTypes(
+ StepConfig::CUSTOM_REPORT_CONFIG->value,
+ StepConfig::CONFIG_TYPE_ARRAY->value
+ );
+ }
+}
diff --git a/src/CustomReport/ExecutionEngine/AutomationAction/Messenger/Messages/CsvCollectionMessage.php b/src/CustomReport/ExecutionEngine/AutomationAction/Messenger/Messages/CsvCollectionMessage.php
new file mode 100644
index 000000000..1252036a5
--- /dev/null
+++ b/src/CustomReport/ExecutionEngine/AutomationAction/Messenger/Messages/CsvCollectionMessage.php
@@ -0,0 +1,26 @@
+validate();
}
@@ -40,6 +44,22 @@ public function getSortOrder(): ?string
return $this->sortOrder;
}
+ public static function fromArray(array $data): self
+ {
+ return new self(
+ name: $data['name'],
+ filters: $data['filters'] ?? null,
+ drillDownFilters: $data['drillDownFilters'] ?? null,
+ sortOrder: $data['sortOrder'] ?? null,
+ sortBy: $data['sortBy'] ?? null,
+ reportOffset: $data['reportOffset'] ?? null,
+ reportLimit: $data['reportLimit'] ?? null,
+ fields: $data['fields'] ?? null,
+ includeHeaders: $data['includeHeaders'] ?? false,
+ defaultDelimiter: $data['defaultDelimiter'] ?? null
+ );
+ }
+
public function getSortBy(): ?string
{
return $this->sortBy;
@@ -71,4 +91,24 @@ public function getDrillDownFilters(): ?array
{
return $this->drillDownFilters;
}
+
+ public function getFields(): ?array
+ {
+ return $this->fields;
+ }
+
+ public function getIncludeHeaders(): bool
+ {
+ return $this->includeHeaders;
+ }
+
+ public function getDefaultDelimiter(): ?string
+ {
+ return $this->defaultDelimiter;
+ }
+
+ public function getName(): string
+ {
+ return $this->name;
+ }
}
diff --git a/src/CustomReport/Repository/CustomReportRepository.php b/src/CustomReport/Repository/CustomReportRepository.php
index 7fd34b2d2..1193bf24c 100644
--- a/src/CustomReport/Repository/CustomReportRepository.php
+++ b/src/CustomReport/Repository/CustomReportRepository.php
@@ -56,7 +56,7 @@ public function loadForCurrentUser(): array
);
}
- public function loadByName(string $name): ?Config
+ public function loadByName(string $name): Config
{
$report = null;
$exception = null;
diff --git a/src/CustomReport/Repository/CustomReportRepositoryInterface.php b/src/CustomReport/Repository/CustomReportRepositoryInterface.php
index 76ade9647..b6c4dca57 100644
--- a/src/CustomReport/Repository/CustomReportRepositoryInterface.php
+++ b/src/CustomReport/Repository/CustomReportRepositoryInterface.php
@@ -32,5 +32,5 @@ public function loadForCurrentUser(): array;
/**
* @throws NotFoundException
*/
- public function loadByName(string $name): ?Config;
+ public function loadByName(string $name): Config;
}
diff --git a/src/CustomReport/Service/AdapterService.php b/src/CustomReport/Service/AdapterService.php
index 4d5e6b49b..5be201ed1 100644
--- a/src/CustomReport/Service/AdapterService.php
+++ b/src/CustomReport/Service/AdapterService.php
@@ -19,7 +19,7 @@
use Pimcore\Bundle\CustomReportsBundle\Tool\Adapter\CustomReportAdapterFactoryInterface;
use Pimcore\Bundle\CustomReportsBundle\Tool\Adapter\CustomReportAdapterInterface;
use Pimcore\Bundle\CustomReportsBundle\Tool\Config;
-use Pimcore\Bundle\StudioBackendBundle\CustomReport\MappedParameter\ChartDataParameter;
+use Pimcore\Bundle\StudioBackendBundle\CustomReport\MappedParameter\ExportParameter;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
use stdClass;
use Symfony\Component\DependencyInjection\ServiceLocator;
@@ -34,7 +34,7 @@ public function __construct(
) {
}
- public function getData(Config $report, ChartDataParameter $chartDataParameter): array
+ public function getData(Config $report, ExportParameter $chartDataParameter): array
{
return $this->getAdapter($report)->getData(
$chartDataParameter->getFilters(),
@@ -42,7 +42,7 @@ public function getData(Config $report, ChartDataParameter $chartDataParameter):
$chartDataParameter->getSortOrder(),
$chartDataParameter->getReportOffset(),
$chartDataParameter->getReportLimit(),
- null,
+ $chartDataParameter->getFields(),
$chartDataParameter->getDrillDownFilters()
);
}
diff --git a/src/CustomReport/Service/AdapterServiceInterface.php b/src/CustomReport/Service/AdapterServiceInterface.php
index 3973c1c2b..875594a31 100644
--- a/src/CustomReport/Service/AdapterServiceInterface.php
+++ b/src/CustomReport/Service/AdapterServiceInterface.php
@@ -17,7 +17,7 @@
namespace Pimcore\Bundle\StudioBackendBundle\CustomReport\Service;
use Pimcore\Bundle\CustomReportsBundle\Tool\Config;
-use Pimcore\Bundle\StudioBackendBundle\CustomReport\MappedParameter\ChartDataParameter;
+use Pimcore\Bundle\StudioBackendBundle\CustomReport\MappedParameter\ExportParameter;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
/**
@@ -28,5 +28,5 @@ interface AdapterServiceInterface
/**
* @throws NotFoundException
*/
- public function getData(Config $report, ChartDataParameter $chartDataParameter): array;
+ public function getData(Config $report, ExportParameter $chartDataParameter): array;
}
diff --git a/src/CustomReport/Service/CsvService.php b/src/CustomReport/Service/CsvService.php
new file mode 100644
index 000000000..d2ed44219
--- /dev/null
+++ b/src/CustomReport/Service/CsvService.php
@@ -0,0 +1,81 @@
+value => $exportParameter,
+ ];
+
+ return $this->generateCsvFileJob(
+ $collectionSettings,
+ );
+ }
+
+ private function generateCsvFileJob(
+ array $collectionSettings
+ ): int {
+
+ $jobSteps = [
+ new JobStep(
+ CustomReportJobSteps::CUSTOM_REPORT_CSV_COLLECTION->value,
+ CsvCollectionMessage::class,
+ '',
+ $collectionSettings
+ ),
+ new JobStep(
+ JobSteps::CSV_CREATION->value,
+ CsvCreationMessage::class,
+ '',
+ []
+ ),
+ ];
+
+ $jobRun = $this->jobExecutionAgent->startJobExecution(
+ new Job(Jobs::CREATE_CSV->value, $jobSteps),
+ $this->securityService->getCurrentUser()->getId(),
+ Config::CONTEXT_STOP_ON_ERROR->value
+ );
+
+ return $jobRun->getId();
+ }
+}
diff --git a/src/CustomReport/Service/CsvServiceInterface.php b/src/CustomReport/Service/CsvServiceInterface.php
new file mode 100644
index 000000000..d05ea9eed
--- /dev/null
+++ b/src/CustomReport/Service/CsvServiceInterface.php
@@ -0,0 +1,27 @@
+customReportRepository->loadByName($reportName);
}
- public function getChartData(string $reportName, ChartDataParameter $chartDataParameter): CustomReportChartData
+ public function getChartData(string $reportName, ExportParameter $chartDataParameter): CustomReportChartData
{
$reportConfig = $this->getCustomReportByName($reportName);
$data = $this->adapterService->getData($reportConfig, $chartDataParameter);
@@ -110,4 +110,31 @@ public function getCustomReportDetails(string $reportName): CustomReportDetails
return $reportDetails;
}
+
+ public function getFieldsForExport(Config $reportConfig): array
+ {
+ $columns = $reportConfig->getColumnConfiguration();
+ $fields = [];
+ foreach ($columns as $column) {
+ if ($column['export']) {
+ $fields[] = $column['name'];
+ }
+ }
+
+ return $fields;
+ }
+
+ public function generateCsvData(array $reportData, array $exportFields, bool $includeHeaders): array
+ {
+ $csvData = [];
+ if ($includeHeaders) {
+ $csvData[] = $exportFields;
+ }
+
+ foreach ($reportData['data'] ?? [] as $row) {
+ $csvData[] = array_values($row);
+ }
+
+ return $csvData;
+ }
}
diff --git a/src/CustomReport/Service/CustomReportServiceInterface.php b/src/CustomReport/Service/CustomReportServiceInterface.php
index 5f11c0c38..07db0b4fe 100644
--- a/src/CustomReport/Service/CustomReportServiceInterface.php
+++ b/src/CustomReport/Service/CustomReportServiceInterface.php
@@ -17,7 +17,7 @@
namespace Pimcore\Bundle\StudioBackendBundle\CustomReport\Service;
use Pimcore\Bundle\CustomReportsBundle\Tool\Config;
-use Pimcore\Bundle\StudioBackendBundle\CustomReport\MappedParameter\ChartDataParameter;
+use Pimcore\Bundle\StudioBackendBundle\CustomReport\MappedParameter\ExportParameter;
use Pimcore\Bundle\StudioBackendBundle\CustomReport\Schema\CustomReportChartData;
use Pimcore\Bundle\StudioBackendBundle\CustomReport\Schema\CustomReportDetails;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
@@ -34,15 +34,19 @@ public function getCustomReportConfigTree(): array;
/**
* @throws NotFoundException
*/
- public function getCustomReportByName(string $reportName): ?Config;
+ public function getCustomReportByName(string $reportName): Config;
/**
* @throws NotFoundException
*/
- public function getChartData(string $reportName, ChartDataParameter $chartDataParameter): CustomReportChartData;
+ public function getChartData(string $reportName, ExportParameter $chartDataParameter): CustomReportChartData;
/**
* @throws NotFoundException
*/
public function getCustomReportDetails(string $reportName): CustomReportDetails;
+
+ public function getFieldsForExport(Config $reportConfig): array;
+
+ public function generateCsvData(array $reportData, array $exportFields, bool $includeHeaders): array;
}
diff --git a/src/DependencyInjection/PimcoreStudioBackendExtension.php b/src/DependencyInjection/PimcoreStudioBackendExtension.php
index 4ccf80d02..b7a0bfab4 100644
--- a/src/DependencyInjection/PimcoreStudioBackendExtension.php
+++ b/src/DependencyInjection/PimcoreStudioBackendExtension.php
@@ -19,7 +19,6 @@
use Exception;
use Pimcore\Bundle\CoreBundle\DependencyInjection\ConfigurationHelper;
use Pimcore\Bundle\StudioBackendBundle\Asset\Service\DownloadServiceInterface;
-use Pimcore\Bundle\StudioBackendBundle\Asset\Service\ExecutionEngine\CsvServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Asset\Service\ExecutionEngine\ZipServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\DataObject\Service\DataAdapterServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Element\Service\ElementDeleteServiceInterface;
@@ -27,6 +26,7 @@
use Pimcore\Bundle\StudioBackendBundle\Exception\InvalidHostException;
use Pimcore\Bundle\StudioBackendBundle\Exception\InvalidPathException;
use Pimcore\Bundle\StudioBackendBundle\Exception\InvalidUrlPrefixException;
+use Pimcore\Bundle\StudioBackendBundle\Export\Csv\CsvExportService;
use Pimcore\Bundle\StudioBackendBundle\Grid\Service\ConfigurationServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Mercure\Service\HubServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Note\Service\NoteServiceInterface;
@@ -97,7 +97,7 @@ public function load(array $configs, ContainerBuilder $container): void
$definition = $container->getDefinition(ZipServiceInterface::class);
$definition->setArgument('$downloadLimits', $config['asset_download_settings']);
- $definition = $container->getDefinition(CsvServiceInterface::class);
+ $definition = $container->getDefinition(CsvExportService::class);
$definition->setArgument('$defaultDelimiter', $config['csv_settings']['default_delimiter']);
$definition = $container->getDefinition(ConfigurationServiceInterface::class);
diff --git a/src/ExecutionEngine/Util/StepConfig.php b/src/ExecutionEngine/Util/StepConfig.php
index 526a8255d..c55f4fd08 100644
--- a/src/ExecutionEngine/Util/StepConfig.php
+++ b/src/ExecutionEngine/Util/StepConfig.php
@@ -22,9 +22,12 @@ enum StepConfig: string
{
use EnumToValueArrayTrait;
+ case ID = 'id';
+ case CUSTOM_REPORT_CONFIG = 'custom_report_config';
+ case CUSTOM_REPORT_TO_EXPORT = 'custom_report_to_export';
case ASSET_TO_EXPORT = 'asset_to_export';
case FOLDER_TO_EXPORT = 'folder_to_export';
- case ASSET_EXPORT_DATA = 'asset_export_data';
+ case CSV_EXPORT_DATA = 'csv_export_data';
case CONFIG_CONFIGURATION = 'config';
case CONFIG_COLUMNS = 'columns';
case CONFIG_FILTERS = 'filters';
@@ -35,4 +38,7 @@ enum StepConfig: string
case SETTINGS_HEADER_NAME = 'name';
case NEW_LINE = "\r\n";
case CONFIG_TYPE_ARRAY = 'array';
+ case CONFIG_TYPE_INT = 'int';
+ case CONFIG_TYPE_STRING = 'string';
+ case CONFIG_TYPE_BOOL = 'bool';
}
diff --git a/src/Asset/Controller/Download/DeleteCsvController.php b/src/Export/Controller/Download/DeleteCsvController.php
similarity index 69%
rename from src/Asset/Controller/Download/DeleteCsvController.php
rename to src/Export/Controller/Download/DeleteCsvController.php
index 36712936b..efde25c40 100644
--- a/src/Asset/Controller/Download/DeleteCsvController.php
+++ b/src/Export/Controller/Download/DeleteCsvController.php
@@ -14,24 +14,22 @@
* @license http://www.pimcore.org/license GPLv3 and PCL
*/
-namespace Pimcore\Bundle\StudioBackendBundle\Asset\Controller\Download;
+namespace Pimcore\Bundle\StudioBackendBundle\Export\Controller\Download;
use OpenApi\Attributes\Delete;
-use Pimcore\Bundle\StudioBackendBundle\Asset\Service\DownloadServiceInterface;
-use Pimcore\Bundle\StudioBackendBundle\Asset\Service\ExecutionEngine\CsvServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\EnvironmentException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ForbiddenException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
+use Pimcore\Bundle\StudioBackendBundle\Export\Csv\CsvExportService;
+use Pimcore\Bundle\StudioBackendBundle\Export\Service\DownloadServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Parameter\Path\IdParameter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\DefaultResponses;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\SuccessResponse;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
-use Pimcore\Bundle\StudioBackendBundle\Util\Constant\UserPermissions;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
-use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Serializer\SerializerInterface;
/**
@@ -49,14 +47,13 @@ public function __construct(
/**
* @throws EnvironmentException|ForbiddenException|NotFoundException
*/
- #[Route('/assets/download/csv/{jobRunId}', name: 'pimcore_studio_api_csv_delete', methods: ['DELETE'])]
- #[IsGranted(UserPermissions::ASSETS->value)]
+ #[Route('/export/download/csv/{jobRunId}', name: 'pimcore_studio_api_export_delete_csv', methods: ['DELETE'])]
#[Delete(
- path: self::PREFIX . '/assets/download/csv/{jobRunId}',
- operationId: 'asset_delete_csv',
- description: 'asset_delete_csv_description',
- summary: 'asset_delete_csv_summary',
- tags: [Tags::Assets->name]
+ path: self::PREFIX . '/export/download/csv/{jobRunId}',
+ operationId: 'export_delete_csv',
+ description: 'export_delete_csv_description',
+ summary: 'export_delete_csv_summary',
+ tags: [Tags::Export->value]
)]
#[IdParameter(type: 'JobRun', name: 'jobRunId')]
#[SuccessResponse]
@@ -65,12 +62,12 @@ public function __construct(
HttpResponseCodes::FORBIDDEN,
HttpResponseCodes::NOT_FOUND,
])]
- public function deleteAssetsCsv(int $jobRunId): Response
+ public function deleteCsv(int $jobRunId): Response
{
$this->downloadService->cleanupDataByJobRunId(
$jobRunId,
- CsvServiceInterface::CSV_FOLDER_NAME,
- CsvServiceInterface::CSV_FILE_NAME
+ CsvExportService::CSV_FOLDER_NAME,
+ CsvExportService::CSV_FILE_NAME
);
return new Response();
diff --git a/src/Asset/Controller/Download/DownloadCsvController.php b/src/Export/Controller/Download/DownloadCsvController.php
similarity index 71%
rename from src/Asset/Controller/Download/DownloadCsvController.php
rename to src/Export/Controller/Download/DownloadCsvController.php
index 6fab2ea15..6a2971fc0 100644
--- a/src/Asset/Controller/Download/DownloadCsvController.php
+++ b/src/Export/Controller/Download/DownloadCsvController.php
@@ -14,17 +14,17 @@
* @license http://www.pimcore.org/license GPLv3 and PCL
*/
-namespace Pimcore\Bundle\StudioBackendBundle\Asset\Controller\Download;
+namespace Pimcore\Bundle\StudioBackendBundle\Export\Controller\Download;
use OpenApi\Attributes\Get;
use Pimcore\Bundle\StudioBackendBundle\Asset\Attribute\Response\Header\ContentDisposition;
-use Pimcore\Bundle\StudioBackendBundle\Asset\Service\DownloadServiceInterface;
-use Pimcore\Bundle\StudioBackendBundle\Asset\Service\ExecutionEngine\CsvServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\EnvironmentException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ForbiddenException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\StreamResourceNotFoundException;
+use Pimcore\Bundle\StudioBackendBundle\Export\Csv\CsvExportService;
+use Pimcore\Bundle\StudioBackendBundle\Export\Service\DownloadServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Parameter\Path\IdParameter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\Content\MediaType;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\DefaultResponses;
@@ -32,10 +32,8 @@
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\Asset\MimeTypes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
-use Pimcore\Bundle\StudioBackendBundle\Util\Constant\UserPermissions;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Routing\Attribute\Route;
-use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Serializer\SerializerInterface;
/**
@@ -53,18 +51,17 @@ public function __construct(
/**
* @throws EnvironmentException|ForbiddenException|NotFoundException|StreamResourceNotFoundException
*/
- #[Route('/assets/download/csv/{jobRunId}', name: 'pimcore_studio_api_csv_download_asset', methods: ['GET'])]
- #[IsGranted(UserPermissions::ASSETS->value)]
+ #[Route('/export/download/csv/{jobRunId}', name: 'pimcore_studio_api_export_download_csv', methods: ['GET'])]
#[Get(
- path: self::PREFIX . '/assets/download/csv/{jobRunId}',
- operationId: 'asset_download_csv',
- description: 'asset_download_csv_description',
- summary: 'asset_download_csv_summary',
- tags: [Tags::Assets->name]
+ path: self::PREFIX . '/export/download/csv/{jobRunId}',
+ operationId: 'export_download_csv',
+ description: 'export_download_csv_description',
+ summary: 'export_download_csv_summary',
+ tags: [Tags::Export->value]
)]
#[IdParameter(type: 'JobRun', name: 'jobRunId')]
#[SuccessResponse(
- description: 'asset_download_csv_success_response',
+ description: 'export_download_csv_success_response',
content: [new MediaType('application/csv')],
headers: [new ContentDisposition()]
)]
@@ -73,14 +70,14 @@ public function __construct(
HttpResponseCodes::FORBIDDEN,
HttpResponseCodes::NOT_FOUND,
])]
- public function assetDownloadCsv(int $jobRunId): StreamedResponse
+ public function downloadCsv(int $jobRunId): StreamedResponse
{
return $this->downloadService->downloadResourceByJobRunId(
$jobRunId,
- CsvServiceInterface::CSV_FILE_NAME,
- CsvServiceInterface::CSV_FOLDER_NAME,
+ CsvExportService::CSV_FILE_NAME,
+ CsvExportService::CSV_FOLDER_NAME,
MimeTypes::CSV->value,
- 'assets.csv'
+ 'export.csv'
);
}
}
diff --git a/src/Export/Csv/CsvExportService.php b/src/Export/Csv/CsvExportService.php
new file mode 100644
index 000000000..89b005295
--- /dev/null
+++ b/src/Export/Csv/CsvExportService.php
@@ -0,0 +1,129 @@
+storageService->getTempStorage();
+ if ($withHeaders) {
+ $headers = $this->getHeaders($columns, $withGroup);
+ }
+ if ($delimiter === null) {
+ $delimiter = $this->defaultDelimiter;
+ }
+
+ $data[] = implode($delimiter, $headers) . StepConfig::NEW_LINE->value;
+ foreach ($csvData as $row) {
+ $data[] = implode($delimiter, array_map([$this, 'encodeFunc'], $row)) . StepConfig::NEW_LINE->value;
+ }
+
+ $storage->write(
+ $this->getCsvFilePath($id, $storage),
+ implode($data)
+ );
+ }
+
+ /**
+ * @throws FilesystemException
+ */
+ public function cleanUpFileSystem(int $jobRunId): void
+ {
+ $this->storageService->cleanUpFlysystemFile(
+ $this->getTempFilePath(
+ $jobRunId,
+ self::CSV_FOLDER_NAME . '/' . self::CSV_FILE_NAME
+ )
+ );
+
+ $this->storageService->cleanUpFolder(
+ $this->getTempFilePath($jobRunId, self::CSV_FOLDER_NAME)
+ );
+ }
+
+ private function encodeFunc(?string $value): string
+ {
+ $value = str_replace('"', '""', $value ?? '');
+
+ //force wrap value in quotes and return
+ return '"' . $value . '"';
+ }
+
+ private function getHeaders(array $columns, bool $withGroup): array
+ {
+ if (empty($columns)) {
+ return [];
+ }
+
+ $columnCollection = $this->gridService->getConfigurationFromArray(
+ $columns,
+ true
+ );
+
+ return $this->gridService->getColumnKeys(
+ $columnCollection,
+ $withGroup
+ );
+ }
+
+ /**
+ * @throws FilesystemException
+ */
+ private function getCsvFilePath(int $id, FilesystemOperator $storage): string
+ {
+ $folderName = $this->getTempFileName($id, self::CSV_FOLDER_NAME);
+ $file = $this->getTempFileName($id, self::CSV_FILE_NAME);
+ $storage->createDirectory($folderName);
+
+ return $folderName . '/' . $file;
+ }
+}
diff --git a/src/Asset/EventSubscriber/CsvCreationSubscriber.php b/src/Export/EventSubscriber/Csv/CsvCreationSubscriber.php
similarity index 73%
rename from src/Asset/EventSubscriber/CsvCreationSubscriber.php
rename to src/Export/EventSubscriber/Csv/CsvCreationSubscriber.php
index b825e95c0..bfdf2c7ca 100644
--- a/src/Asset/EventSubscriber/CsvCreationSubscriber.php
+++ b/src/Export/EventSubscriber/Csv/CsvCreationSubscriber.php
@@ -14,16 +14,15 @@
* @license http://www.pimcore.org/license GPLv3 and PCL
*/
-namespace Pimcore\Bundle\StudioBackendBundle\Asset\EventSubscriber;
+namespace Pimcore\Bundle\StudioBackendBundle\Export\EventSubscriber\Csv;
use League\Flysystem\FilesystemException;
use Pimcore\Bundle\GenericExecutionEngineBundle\Event\JobRunStateChangedEvent;
use Pimcore\Bundle\GenericExecutionEngineBundle\Model\JobRunStates;
use Pimcore\Bundle\StudioBackendBundle\Asset\Mercure\Events;
-use Pimcore\Bundle\StudioBackendBundle\Asset\Service\ExecutionEngine\CsvServiceInterface;
-use Pimcore\Bundle\StudioBackendBundle\Element\Service\StorageServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Service\EventSubscriberServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\Jobs;
+use Pimcore\Bundle\StudioBackendBundle\Export\ExportServiceInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
@@ -33,8 +32,7 @@
{
public function __construct(
private EventSubscriberServiceInterface $eventSubscriberService,
- private CsvServiceInterface $csvService,
- private StorageServiceInterface $storageService,
+ private ExportServiceInterface $csvService
) {
}
@@ -70,15 +68,6 @@ public function onStateChanged(JobRunStateChangedEvent $event): void
*/
private function cleanupOnFail(int $jobRunId): void
{
- $this->storageService->cleanUpFlysystemFile(
- $this->csvService->getTempFilePath(
- $jobRunId,
- CsvServiceInterface::CSV_FOLDER_NAME . '/' . CsvServiceInterface::CSV_FILE_NAME
- )
- );
-
- $this->storageService->cleanUpFolder(
- $this->csvService->getTempFilePath($jobRunId, CsvServiceInterface::CSV_FOLDER_NAME)
- );
+ $this->csvService->cleanupFileSystem($jobRunId);
}
}
diff --git a/src/Asset/ExecutionEngine/AutomationAction/Messenger/Handler/CsvCreationHandler.php b/src/Export/ExecutionEngine/AutomationAction/Messenger/Handler/CsvCreationHandler.php
similarity index 69%
rename from src/Asset/ExecutionEngine/AutomationAction/Messenger/Handler/CsvCreationHandler.php
rename to src/Export/ExecutionEngine/AutomationAction/Messenger/Handler/CsvCreationHandler.php
index 2bf8cda3b..51d17909a 100644
--- a/src/Asset/ExecutionEngine/AutomationAction/Messenger/Handler/CsvCreationHandler.php
+++ b/src/Export/ExecutionEngine/AutomationAction/Messenger/Handler/CsvCreationHandler.php
@@ -14,17 +14,16 @@
* @license http://www.pimcore.org/license GPLv3 and PCL
*/
-namespace Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Handler;
+namespace Pimcore\Bundle\StudioBackendBundle\Export\ExecutionEngine\AutomationAction\Messenger\Handler;
use Exception;
use League\Flysystem\FilesystemException;
-use Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages\CsvCreationMessage;
-use Pimcore\Bundle\StudioBackendBundle\Asset\Service\ExecutionEngine\CsvServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\AutomationAction\AbstractHandler;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\Config;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\StepConfig;
use Pimcore\Bundle\StudioBackendBundle\ExecutionEngine\Util\Trait\HandlerProgressTrait;
-use Pimcore\Bundle\StudioBackendBundle\Grid\Service\GridServiceInterface;
+use Pimcore\Bundle\StudioBackendBundle\Export\ExecutionEngine\AutomationAction\Messenger\Messages\CsvCreationMessage;
+use Pimcore\Bundle\StudioBackendBundle\Export\ExportServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Mercure\Service\PublishServiceInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
@@ -38,8 +37,7 @@ final class CsvCreationHandler extends AbstractHandler
public function __construct(
private readonly PublishServiceInterface $publishService,
- private readonly CsvServiceInterface $csvService,
- private readonly GridServiceInterface $gridService
+ private readonly ExportServiceInterface $csvService
) {
parent::__construct();
}
@@ -55,27 +53,26 @@ public function __invoke(CsvCreationMessage $message): void
}
$columns = $this->extractConfigFieldFromJobStepConfig($message, StepConfig::CONFIG_COLUMNS->value);
-
$settings = $this->extractConfigFieldFromJobStepConfig($message, StepConfig::CONFIG_CONFIGURATION->value);
- $columnCollection = $this->gridService->getConfigurationFromArray(
- $columns,
- true
- );
+ $headers = $settings[StepConfig::SETTINGS_HEADER->value] ?? StepConfig::SETTINGS_HEADER_NO_HEADER->value;
+ $delimiter = $settings[StepConfig::SETTINGS_DELIMITER->value] ?? null;
- if (!isset($jobRun->getContext()[StepConfig::ASSET_EXPORT_DATA->value])) {
+ if (!isset($jobRun->getContext()[StepConfig::CSV_EXPORT_DATA->value])) {
$this->abort($this->getAbortData(
Config::CSV_CREATION_FAILED_MESSAGE->value,
- ['message' => 'Asset export data not found in job run context']
+ ['message' => 'Csv export data not found in job run context']
));
}
- $assetData = $jobRun->getContext()[StepConfig::ASSET_EXPORT_DATA->value];
+ $csvData = $jobRun->getContext()[StepConfig::CSV_EXPORT_DATA->value];
try {
- $this->csvService->createCsvFile(
+ $this->csvService->createExportFile(
$jobRun->getId(),
- $columnCollection,
- $settings,
- $assetData,
+ $columns,
+ $csvData,
+ $headers !== StepConfig::SETTINGS_HEADER_NO_HEADER->value,
+ $headers === StepConfig::SETTINGS_HEADER_NAME,
+ $delimiter
);
} catch (Exception|FilesystemException $e) {
$this->abort($this->getAbortData(
@@ -99,5 +96,10 @@ protected function configureStep(): void
StepConfig::CONFIG_COLUMNS->value,
StepConfig::CONFIG_TYPE_ARRAY->value
);
+
+ $this->stepConfiguration->setDefaults([
+ StepConfig::CONFIG_COLUMNS->value => [],
+ StepConfig::CONFIG_CONFIGURATION->value => [],
+ ]);
}
}
diff --git a/src/Asset/ExecutionEngine/AutomationAction/Messenger/Messages/CsvCreationMessage.php b/src/Export/ExecutionEngine/AutomationAction/Messenger/Messages/CsvCreationMessage.php
similarity index 86%
rename from src/Asset/ExecutionEngine/AutomationAction/Messenger/Messages/CsvCreationMessage.php
rename to src/Export/ExecutionEngine/AutomationAction/Messenger/Messages/CsvCreationMessage.php
index 666887b74..3b003f696 100644
--- a/src/Asset/ExecutionEngine/AutomationAction/Messenger/Messages/CsvCreationMessage.php
+++ b/src/Export/ExecutionEngine/AutomationAction/Messenger/Messages/CsvCreationMessage.php
@@ -14,7 +14,7 @@
* @license http://www.pimcore.org/license GPLv3 and PCL
*/
-namespace Pimcore\Bundle\StudioBackendBundle\Asset\ExecutionEngine\AutomationAction\Messenger\Messages;
+namespace Pimcore\Bundle\StudioBackendBundle\Export\ExecutionEngine\AutomationAction\Messenger\Messages;
use Pimcore\Bundle\GenericExecutionEngineBundle\Messenger\Messages\AbstractExecutionEngineMessage;
diff --git a/src/Export/ExecutionEngine/Util/JobSteps.php b/src/Export/ExecutionEngine/Util/JobSteps.php
new file mode 100644
index 000000000..5e27003f4
--- /dev/null
+++ b/src/Export/ExecutionEngine/Util/JobSteps.php
@@ -0,0 +1,21 @@
+executionEngineService->validateJobRun($jobRunId);
+ $fileName = $this->getTempFileName($jobRunId, $tempFileName);
+ $folderName = $this->getTempFileName($jobRunId, $tempFolderName);
+ $filePath = $folderName . '/' . $fileName;
+
+ $streamedResponse = $this->getFileStreamedResponse(
+ $filePath,
+ $mimeType,
+ $downloadName,
+ $this->validateStorage($filePath, $jobRunId)
+ );
+
+ try {
+ $this->storageService->cleanUpFolder($folderName);
+ } catch (FilesystemException) {
+ throw new EnvironmentException(
+ sprintf(
+ 'Failed to clean up temporary folder %s',
+ $folderName
+ )
+ );
+ }
+
+ return $streamedResponse;
+ }
+
+ /**
+ * @throws EnvironmentException|NotFoundException
+ */
+ public function cleanupDataByJobRunId(
+ int $jobRunId,
+ string $folderName,
+ string $fileName
+ ): void {
+ $this->executionEngineService->validateJobRun($jobRunId);
+ $this->validateStorage($this->getTempFilePath($jobRunId, $folderName . '/' . $fileName), $jobRunId);
+
+ try {
+ $this->storageService->cleanUpFolder(
+ $this->getTempFileName(
+ $jobRunId,
+ $folderName
+ ),
+ true
+ );
+ } catch (FilesystemException $e) {
+ throw new EnvironmentException(
+ sprintf(
+ 'Failed to delete file based on jobRunId %d: %s',
+ $jobRunId,
+ $e->getMessage()
+ ),
+ );
+ }
+ }
+
+ /**
+ * @throws EnvironmentException
+ */
+ private function validateStorage(string $filePath, int $jobRunId): FilesystemOperator
+ {
+ $storage = $this->storageService->getTempStorage();
+ if (!$this->storageService->tempFileExists($filePath)) {
+ throw new EnvironmentException(
+ sprintf(
+ 'Resource not found for jobRun with Id %d',
+ $jobRunId
+ )
+ );
+ }
+
+ return $storage;
+ }
+}
diff --git a/src/Export/Service/DownloadServiceInterface.php b/src/Export/Service/DownloadServiceInterface.php
new file mode 100644
index 000000000..4c38fe5cc
--- /dev/null
+++ b/src/Export/Service/DownloadServiceInterface.php
@@ -0,0 +1,49 @@
+value,
description: 'tag_emails_description'
)]
+#[Tag(
+ name: Tags::Export->value,
+ description: 'tag_export_description'
+)]
#[Tag(
name: Tags::Mercure->value,
description: 'tag_mercure_description'
@@ -152,6 +156,7 @@ enum Tags: string
case Elements = 'Elements';
case ExecutionEngine = 'Execution Engine';
case Emails = 'E-Mails';
+ case Export = 'Export';
case Mercure = 'Mercure';
case Metadata = 'Metadata';
case Notes = 'Notes';
diff --git a/translations/studio.en.yaml b/translations/studio.en.yaml
index b6e0e67c4..865d91fa9 100644
--- a/translations/studio.en.yaml
+++ b/translations/studio.en.yaml
@@ -9,7 +9,7 @@ studio_ee_zip_file_copy_failed: 'Zip file could not be copied: %message%'
studio_ee_zip_file_upload_failed: 'Zip file could not be uploaded: %message%'
studio_ee_zip_cleanup_failed: 'Zip directory %directory% could not be removed: %message%'
studio_ee_csv_creation_failed: 'CSV Export failed: %message%'
-studio_ee_csv_data_collection_failed: 'Data for CSV export could not be extracted for asset %id%: %message%'
+studio_ee_csv_data_collection_failed: 'Data for CSV export could not be extracted for %id%: %message%'
studio_ee_element_patch_failed: 'Element with type %type% with ID %id% could not be updated: %message%'
studio_ee_element_rewrite_references_failed: 'Element references with type %type% with ID %id% could not be rewritten: %message%'
studio_ee_element_tag_operation_failed: 'Could not %operation% tags for element type %type% and ID %id%: %message%'
diff --git a/translations/studio_api_docs.en.yaml b/translations/studio_api_docs.en.yaml
index a9f254fb5..74b1cad0c 100644
--- a/translations/studio_api_docs.en.yaml
+++ b/translations/studio_api_docs.en.yaml
@@ -46,9 +46,9 @@ asset_custom_settings_get_by_id_description: |
Retrieves custom settings based on the given {id}.
The {id} must be an ID of existing asset
asset_custom_settings_get_by_id_success_response: Successfully retrieved custom settings as JSON
asset_custom_settings_get_by_id_summary: Get custom settings of an asset by ID
-asset_delete_csv_description: |
+export_delete_csv_description: |
Delete the CSV file with given {jobRunId} returned in the response of the create csv endpoint
-asset_delete_csv_summary: Delete asset CSV file based on jobRunId
+export_delete_csv_summary: Delete asset CSV file based on jobRunId
asset_delete_zip_description: |
Delete the ZIP file with given {jobRunId} returned in the response of the create zip endpoint
asset_delete_zip_summary: Delete asset ZIP file based on jobRunId
@@ -60,10 +60,10 @@ asset_download_by_id_description: |
Download the original asset stream based on the provided {id}
asset_download_by_id_success_response: Original asset binary file
asset_download_by_id_summary: Download asset by ID
-asset_download_csv_description: |
+export_download_csv_description: |
Download the CSV file with given {jobRunId} returned in the response of the create csv endpoint
-asset_download_csv_success_response: CSV File as attachment
-asset_download_csv_summary: Download CSV file for assets
+export_download_csv_success_response: CSV File as attachment
+export_download_csv_summary: Download CSV file for job run id
asset_download_zip_description: |
Download the ZIP archive with assets based on the given {jobRunId} returned in the response of the create zip endpoint
asset_download_zip_success_response: ZIP archive as attachment
@@ -679,8 +679,22 @@ custom_reports_chart_success_response: Chart data as JSON. The actual data depen
custom_reports_chart_sort_by_parameter: Sort by column parameter
custom_reports_chart_report_limit_parameter: Limit of the report data
custom_reports_chart_report_offset_parameter: Offset of the report data
+custom_report_export_csv: CSV export
+custom_report_export_csv_summary: Export report data as CSV
+custom_report_export_csv_created_response: Successfully created jobRun for csv export
+custom_report_export_csv_description: |
+ Creating the CSV file for custom reports.
Parameters are: