diff --git a/mailpoet/lib/Automation/Engine/Data/Workflow.php b/mailpoet/lib/Automation/Engine/Data/Workflow.php index 2e7d166110..232f0dc8cf 100644 --- a/mailpoet/lib/Automation/Engine/Data/Workflow.php +++ b/mailpoet/lib/Automation/Engine/Data/Workflow.php @@ -191,8 +191,8 @@ class Workflow { }, Json::decode($data['steps'])), new \WP_User((int)$data['author']) ); - $workflow->id = (int)$data['id']; - $workflow->versionId = (int)$data['version_id']; + $workflow->id = (int)($data['id'] ?? 0); + $workflow->versionId = (int)($data['version_id'] ?? 0); $workflow->status = $data['status']; $workflow->createdAt = new DateTimeImmutable($data['created_at']); $workflow->updatedAt = new DateTimeImmutable($data['updated_at']); diff --git a/mailpoet/lib/Automation/Engine/Endpoints/Workflows/WorkflowsDuplicateEndpoint.php b/mailpoet/lib/Automation/Engine/Endpoints/Workflows/WorkflowsDuplicateEndpoint.php new file mode 100644 index 0000000000..8d970d64cf --- /dev/null +++ b/mailpoet/lib/Automation/Engine/Endpoints/Workflows/WorkflowsDuplicateEndpoint.php @@ -0,0 +1,51 @@ +workflowMapper = $workflowMapper; + $this->workflowStorage = $workflowStorage; + } + + public function handle(Request $request): Response { + $workflowId = $request->getParam('id'); + if (!is_int($workflowId)) { + throw InvalidStateException::create(); + } + $existingWorkflow = $this->workflowStorage->getWorkflow($workflowId); + if (!$existingWorkflow instanceof Workflow) { + throw InvalidStateException::create(); + } + $duplicateId = $this->workflowStorage->duplicateWorkflow($existingWorkflow); + $duplicate = $this->workflowStorage->getWorkflow($duplicateId); + if (!$duplicate instanceof Workflow) { + throw InvalidStateException::create(); + } + return new Response($this->workflowMapper->buildWorkflow($duplicate)); + } + + public static function getRequestSchema(): array { + return [ + 'id' => Builder::integer()->required(), + ]; + } +} diff --git a/mailpoet/lib/Automation/Engine/Endpoints/Workflows/WorkflowsPutEndpoint.php b/mailpoet/lib/Automation/Engine/Endpoints/Workflows/WorkflowsPutEndpoint.php index 1171dde883..7a5d90b039 100644 --- a/mailpoet/lib/Automation/Engine/Endpoints/Workflows/WorkflowsPutEndpoint.php +++ b/mailpoet/lib/Automation/Engine/Endpoints/Workflows/WorkflowsPutEndpoint.php @@ -2,15 +2,11 @@ namespace MailPoet\Automation\Engine\Endpoints\Workflows; -use DateTimeImmutable; use MailPoet\API\REST\Request; use MailPoet\API\REST\Response; use MailPoet\Automation\Engine\API\Endpoint; use MailPoet\Automation\Engine\Builder\UpdateWorkflowController; -use MailPoet\Automation\Engine\Data\NextStep; -use MailPoet\Automation\Engine\Data\Step; -use MailPoet\Automation\Engine\Data\Workflow; -use MailPoet\Automation\Engine\Storage\WorkflowStatisticsStorage; +use MailPoet\Automation\Engine\Mappers\WorkflowMapper; use MailPoet\Automation\Engine\Validation\WorkflowSchema; use MailPoet\Validator\Builder; @@ -18,21 +14,21 @@ class WorkflowsPutEndpoint extends Endpoint { /** @var UpdateWorkflowController */ private $updateController; - /** @var WorkflowStatisticsStorage */ - private $statisticsStorage; + /** @var WorkflowMapper */ + private $workflowMapper; public function __construct( UpdateWorkflowController $updateController, - WorkflowStatisticsStorage $statisticsStorage + WorkflowMapper $workflowMapper ) { $this->updateController = $updateController; - $this->statisticsStorage = $statisticsStorage; + $this->workflowMapper = $workflowMapper; } public function handle(Request $request): Response { $data = $request->getParams(); $workflow = $this->updateController->updateWorkflow(intval($request->getParam('id')), $data); - return new Response($this->buildWorkflow($workflow)); + return new Response($this->workflowMapper->buildWorkflow($workflow)); } public static function getRequestSchema(): array { @@ -43,31 +39,4 @@ class WorkflowsPutEndpoint extends Endpoint { 'steps' => WorkflowSchema::getStepsSchema(), ]; } - - protected function buildWorkflow(Workflow $workflow): array { - return [ - 'id' => $workflow->getId(), - 'name' => $workflow->getName(), - 'status' => $workflow->getStatus(), - 'created_at' => $workflow->getCreatedAt()->format(DateTimeImmutable::W3C), - 'updated_at' => $workflow->getUpdatedAt()->format(DateTimeImmutable::W3C), - 'activated_at' => $workflow->getActivatedAt() ? $workflow->getActivatedAt()->format(DateTimeImmutable::W3C) : null, - 'author' => [ - 'id' => $workflow->getAuthor()->ID, - 'name' => $workflow->getAuthor()->display_name, - ], - 'stats' => $this->statisticsStorage->getWorkflowStats($workflow->getId())->toArray(), - 'steps' => array_map(function (Step $step) { - return [ - 'id' => $step->getId(), - 'type' => $step->getType(), - 'key' => $step->getKey(), - 'args' => $step->getArgs(), - 'next_steps' => array_map(function (NextStep $nextStep) { - return $nextStep->toArray(); - }, $step->getNextSteps()), - ]; - }, $workflow->getSteps()), - ]; - } } diff --git a/mailpoet/lib/Automation/Engine/Engine.php b/mailpoet/lib/Automation/Engine/Engine.php index 9701fae282..689db83d21 100644 --- a/mailpoet/lib/Automation/Engine/Engine.php +++ b/mailpoet/lib/Automation/Engine/Engine.php @@ -8,6 +8,7 @@ use MailPoet\Automation\Engine\Control\TriggerHandler; use MailPoet\Automation\Engine\Endpoints\System\DatabaseDeleteEndpoint; use MailPoet\Automation\Engine\Endpoints\System\DatabasePostEndpoint; use MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsCreateFromTemplateEndpoint; +use MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsDuplicateEndpoint; use MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsGetEndpoint; use MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsPutEndpoint; use MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowTemplatesGetEndpoint; @@ -73,6 +74,7 @@ class Engine { $api->registerGetRoute('workflows', WorkflowsGetEndpoint::class); $api->registerPutRoute('workflows/(?P\d+)', WorkflowsPutEndpoint::class); $api->registerPostRoute('workflows/create-from-template', WorkflowsCreateFromTemplateEndpoint::class); + $api->registerPostRoute('workflows/(?P\d+)/duplicate', WorkflowsDuplicateEndpoint::class); $api->registerPostRoute('system/database', DatabasePostEndpoint::class); $api->registerDeleteRoute('system/database', DatabaseDeleteEndpoint::class); $api->registerGetRoute('workflow-templates', WorkflowTemplatesGetEndpoint::class); diff --git a/mailpoet/lib/Automation/Engine/Mappers/WorkflowMapper.php b/mailpoet/lib/Automation/Engine/Mappers/WorkflowMapper.php new file mode 100644 index 0000000000..da666e4198 --- /dev/null +++ b/mailpoet/lib/Automation/Engine/Mappers/WorkflowMapper.php @@ -0,0 +1,47 @@ +statisticsStorage = $statisticsStorage; + } + + public function buildWorkflow(Workflow $workflow): array { + return [ + 'id' => $workflow->getId(), + 'name' => $workflow->getName(), + 'status' => $workflow->getStatus(), + 'created_at' => $workflow->getCreatedAt()->format(DateTimeImmutable::W3C), + 'updated_at' => $workflow->getUpdatedAt()->format(DateTimeImmutable::W3C), + 'activated_at' => $workflow->getActivatedAt() ? $workflow->getActivatedAt()->format(DateTimeImmutable::W3C) : null, + 'author' => [ + 'id' => $workflow->getAuthor()->ID, + 'name' => $workflow->getAuthor()->display_name, + ], + 'stats' => $this->statisticsStorage->getWorkflowStats($workflow->getId())->toArray(), + 'steps' => array_map(function (Step $step) { + return [ + 'id' => $step->getId(), + 'type' => $step->getType(), + 'key' => $step->getKey(), + 'args' => $step->getArgs(), + 'next_steps' => array_map(function (NextStep $nextStep) { + return $nextStep->toArray(); + }, $step->getNextSteps()), + ]; + }, $workflow->getSteps()), + ]; + } +} diff --git a/mailpoet/lib/Automation/Engine/Storage/WorkflowStorage.php b/mailpoet/lib/Automation/Engine/Storage/WorkflowStorage.php index 32cb6765d4..334f004e1d 100644 --- a/mailpoet/lib/Automation/Engine/Storage/WorkflowStorage.php +++ b/mailpoet/lib/Automation/Engine/Storage/WorkflowStorage.php @@ -30,11 +30,22 @@ class WorkflowStorage { if (!$result) { throw Exceptions::databaseError($this->wpdb->last_error); } - $id = (int)$this->wpdb->insert_id; + $id = $this->wpdb->insert_id; $this->insertWorkflowVersion($id, $workflow); return $id; } + public function duplicateWorkflow(Workflow $workflow): int { + $data = $workflow->toArray(); + $now = (new DateTimeImmutable())->format(DateTimeImmutable::W3C); + $data['created_at'] = $now; + $data['updated_at'] = $now; + $data['status'] = Workflow::STATUS_DRAFT; + $data['name'] = 'Copy of ' . $workflow->getName(); + $duplicate = Workflow::fromArray($data); + return $this->createWorkflow($duplicate); + } + public function updateWorkflow(Workflow $workflow): void { $oldRecord = $this->getWorkflow($workflow->getId()); if ($oldRecord && $oldRecord->equals($workflow)) { @@ -146,7 +157,6 @@ class WorkflowStorage { } private function insertWorkflowVersion(int $workflowId, Workflow $workflow): void { - $dateString = (new DateTimeImmutable())->format(DateTimeImmutable::W3C); $data = [ 'workflow_id' => $workflowId, diff --git a/mailpoet/lib/DI/ContainerConfigurator.php b/mailpoet/lib/DI/ContainerConfigurator.php index 8a35252fe3..6372f92f7f 100644 --- a/mailpoet/lib/DI/ContainerConfigurator.php +++ b/mailpoet/lib/DI/ContainerConfigurator.php @@ -122,6 +122,7 @@ class ContainerConfigurator implements IContainerConfigurator { $container->autowire(\MailPoet\Automation\Engine\Control\TriggerHandler::class)->setPublic(true); $container->autowire(\MailPoet\Automation\Engine\Engine::class)->setPublic(true); $container->autowire(\MailPoet\Automation\Engine\Hooks::class)->setPublic(true); + $container->autowire(\MailPoet\Automation\Engine\Mappers\WorkflowMapper::class)->setPublic(true); $container->autowire(\MailPoet\Automation\Engine\Migrations\Migrator::class)->setPublic(true); $container->autowire(\MailPoet\Automation\Engine\Registry::class)->setPublic(true); $container->autowire(\MailPoet\Automation\Engine\Storage\WorkflowRunStorage::class)->setPublic(true); @@ -141,6 +142,7 @@ class ContainerConfigurator implements IContainerConfigurator { $container->autowire(\MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowTemplatesGetEndpoint::class)->setPublic(true); $container->autowire(\MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsPutEndpoint::class)->setPublic(true); $container->autowire(\MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsCreateFromTemplateEndpoint::class)->setPublic(true); + $container->autowire(\MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsDuplicateEndpoint::class)->setPublic(true); $container->autowire(\MailPoet\Automation\Engine\Endpoints\System\DatabasePostEndpoint::class)->setPublic(true); $container->autowire(\MailPoet\Automation\Engine\Endpoints\System\DatabaseDeleteEndpoint::class)->setPublic(true); // Automation - core integration