Add ability to permanently delete workflow
[MAILPOET-4540]
This commit is contained in:
committed by
David Remer
parent
a4c8caa664
commit
4e82c5334b
@@ -0,0 +1,42 @@
|
|||||||
|
<?php declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace MailPoet\Automation\Engine\Endpoints\Workflows;
|
||||||
|
|
||||||
|
use MailPoet\API\REST\Request;
|
||||||
|
use MailPoet\API\REST\Response;
|
||||||
|
use MailPoet\Automation\Engine\API\Endpoint;
|
||||||
|
use MailPoet\Automation\Engine\Data\Workflow;
|
||||||
|
use MailPoet\Automation\Engine\Exceptions\InvalidStateException;
|
||||||
|
use MailPoet\Automation\Engine\Storage\WorkflowStorage;
|
||||||
|
use MailPoet\Validator\Builder;
|
||||||
|
|
||||||
|
class WorkflowsDeleteEndpoint extends Endpoint {
|
||||||
|
/** @var WorkflowStorage */
|
||||||
|
private $workflowStorage;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
WorkflowStorage $workflowStorage
|
||||||
|
) {
|
||||||
|
$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();
|
||||||
|
}
|
||||||
|
$this->workflowStorage->deleteWorkflow($existingWorkflow);
|
||||||
|
|
||||||
|
return new Response(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getRequestSchema(): array {
|
||||||
|
return [
|
||||||
|
'id' => Builder::integer()->required(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -8,6 +8,7 @@ use MailPoet\Automation\Engine\Control\TriggerHandler;
|
|||||||
use MailPoet\Automation\Engine\Endpoints\System\DatabaseDeleteEndpoint;
|
use MailPoet\Automation\Engine\Endpoints\System\DatabaseDeleteEndpoint;
|
||||||
use MailPoet\Automation\Engine\Endpoints\System\DatabasePostEndpoint;
|
use MailPoet\Automation\Engine\Endpoints\System\DatabasePostEndpoint;
|
||||||
use MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsCreateFromTemplateEndpoint;
|
use MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsCreateFromTemplateEndpoint;
|
||||||
|
use MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsDeleteEndpoint;
|
||||||
use MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsDuplicateEndpoint;
|
use MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsDuplicateEndpoint;
|
||||||
use MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsGetEndpoint;
|
use MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsGetEndpoint;
|
||||||
use MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsPutEndpoint;
|
use MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsPutEndpoint;
|
||||||
@@ -73,8 +74,9 @@ class Engine {
|
|||||||
$this->wordPress->addAction(Hooks::API_INITIALIZE, function (API $api) {
|
$this->wordPress->addAction(Hooks::API_INITIALIZE, function (API $api) {
|
||||||
$api->registerGetRoute('workflows', WorkflowsGetEndpoint::class);
|
$api->registerGetRoute('workflows', WorkflowsGetEndpoint::class);
|
||||||
$api->registerPutRoute('workflows/(?P<id>\d+)', WorkflowsPutEndpoint::class);
|
$api->registerPutRoute('workflows/(?P<id>\d+)', WorkflowsPutEndpoint::class);
|
||||||
$api->registerPostRoute('workflows/create-from-template', WorkflowsCreateFromTemplateEndpoint::class);
|
$api->registerDeleteRoute('workflows/(?P<id>\d+)', WorkflowsDeleteEndpoint::class);
|
||||||
$api->registerPostRoute('workflows/(?P<id>\d+)/duplicate', WorkflowsDuplicateEndpoint::class);
|
$api->registerPostRoute('workflows/(?P<id>\d+)/duplicate', WorkflowsDuplicateEndpoint::class);
|
||||||
|
$api->registerPostRoute('workflows/create-from-template', WorkflowsCreateFromTemplateEndpoint::class);
|
||||||
$api->registerPostRoute('system/database', DatabasePostEndpoint::class);
|
$api->registerPostRoute('system/database', DatabasePostEndpoint::class);
|
||||||
$api->registerDeleteRoute('system/database', DatabaseDeleteEndpoint::class);
|
$api->registerDeleteRoute('system/database', DatabaseDeleteEndpoint::class);
|
||||||
$api->registerGetRoute('workflow-templates', WorkflowTemplatesGetEndpoint::class);
|
$api->registerGetRoute('workflow-templates', WorkflowTemplatesGetEndpoint::class);
|
||||||
|
@@ -59,6 +59,7 @@ class Migrator {
|
|||||||
updated_at timestamp NOT NULL,
|
updated_at timestamp NOT NULL,
|
||||||
subjects longtext,
|
subjects longtext,
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
|
INDEX (workflow_id),
|
||||||
INDEX (status)
|
INDEX (status)
|
||||||
);
|
);
|
||||||
");
|
");
|
||||||
|
@@ -142,6 +142,44 @@ class WorkflowStorage {
|
|||||||
}, (array)$data);
|
}, (array)$data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function deleteWorkflow(Workflow $workflow): void {
|
||||||
|
$workflowTable = esc_sql($this->workflowTable);
|
||||||
|
$versionTable = esc_sql($this->versionsTable);
|
||||||
|
$workflowRunTable = esc_sql($this->wpdb->prefix . 'mailpoet_workflow_runs');
|
||||||
|
$workflowRunLogTable = esc_sql($this->wpdb->prefix . 'mailpoet_workflow_run_logs');
|
||||||
|
$workflowId = $workflow->getId();
|
||||||
|
$runLogsQuery = $this->wpdb->prepare(
|
||||||
|
"
|
||||||
|
DELETE FROM $workflowRunLogTable
|
||||||
|
WHERE workflow_run_id IN (
|
||||||
|
SELECT id FROM $workflowRunTable
|
||||||
|
WHERE workflow_id = %d
|
||||||
|
)
|
||||||
|
",
|
||||||
|
$workflowId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!is_string($runLogsQuery)) {
|
||||||
|
throw Exceptions\InvalidStateException::create();
|
||||||
|
}
|
||||||
|
$logsDeleted = $this->wpdb->query($runLogsQuery);
|
||||||
|
if (!is_int($logsDeleted)) {
|
||||||
|
throw Exceptions::databaseError($this->wpdb->last_error);
|
||||||
|
}
|
||||||
|
$runsDeleted = $this->wpdb->delete($this->wpdb->prefix . 'mailpoet_workflow_runs', ['workflow_id' => $workflowId]);
|
||||||
|
if (!is_int($runsDeleted)) {
|
||||||
|
throw Exceptions::databaseError($this->wpdb->last_error);
|
||||||
|
}
|
||||||
|
$versionsDeleted = $this->wpdb->delete($versionTable, ['workflow_id' => $workflowId]);
|
||||||
|
if (!is_int($versionsDeleted)) {
|
||||||
|
throw Exceptions::databaseError($this->wpdb->last_error);
|
||||||
|
}
|
||||||
|
$workflowDeleted = $this->wpdb->delete($workflowTable, ['id' => $workflowId]);
|
||||||
|
if (!is_int($workflowDeleted)) {
|
||||||
|
throw Exceptions::databaseError($this->wpdb->last_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function truncate(): bool {
|
public function truncate(): bool {
|
||||||
$workflowTable = esc_sql($this->workflowTable);
|
$workflowTable = esc_sql($this->workflowTable);
|
||||||
$versionTable = esc_sql($this->versionsTable);
|
$versionTable = esc_sql($this->versionsTable);
|
||||||
|
@@ -143,6 +143,7 @@ class ContainerConfigurator implements IContainerConfigurator {
|
|||||||
$container->autowire(\MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsPutEndpoint::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\WorkflowsCreateFromTemplateEndpoint::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsDuplicateEndpoint::class)->setPublic(true);
|
$container->autowire(\MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsDuplicateEndpoint::class)->setPublic(true);
|
||||||
|
$container->autowire(\MailPoet\Automation\Engine\Endpoints\Workflows\WorkflowsDeleteEndpoint::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\Automation\Engine\Endpoints\System\DatabasePostEndpoint::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);
|
$container->autowire(\MailPoet\Automation\Engine\Endpoints\System\DatabaseDeleteEndpoint::class)->setPublic(true);
|
||||||
// Automation - core integration
|
// Automation - core integration
|
||||||
|
@@ -4,6 +4,10 @@ namespace MailPoet\Test\Automation\Engine\Storage;
|
|||||||
|
|
||||||
use MailPoet\Automation\Engine\Data\Step;
|
use MailPoet\Automation\Engine\Data\Step;
|
||||||
use MailPoet\Automation\Engine\Data\Workflow;
|
use MailPoet\Automation\Engine\Data\Workflow;
|
||||||
|
use MailPoet\Automation\Engine\Data\WorkflowRun;
|
||||||
|
use MailPoet\Automation\Engine\Data\WorkflowRunLog;
|
||||||
|
use MailPoet\Automation\Engine\Storage\WorkflowRunLogStorage;
|
||||||
|
use MailPoet\Automation\Engine\Storage\WorkflowRunStorage;
|
||||||
use MailPoet\Automation\Engine\Storage\WorkflowStorage;
|
use MailPoet\Automation\Engine\Storage\WorkflowStorage;
|
||||||
use MailPoet\Automation\Integrations\MailPoet\Triggers\SomeoneSubscribesTrigger;
|
use MailPoet\Automation\Integrations\MailPoet\Triggers\SomeoneSubscribesTrigger;
|
||||||
|
|
||||||
@@ -73,6 +77,60 @@ class WorkflowStorageTest extends \MailPoetTest
|
|||||||
$this->assertEmpty($this->testee->getActiveWorkflowsByTrigger($subscriberTrigger));
|
$this->assertEmpty($this->testee->getActiveWorkflowsByTrigger($subscriberTrigger));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testItCanDeleteAWorkflow() {
|
||||||
|
$workflowToDelete = $this->createEmptyWorkflow();
|
||||||
|
$workflowToKeep = $this->createEmptyWorkflow();
|
||||||
|
expect($this->testee->getWorkflows())->count(2);
|
||||||
|
$this->testee->deleteWorkflow($workflowToDelete);
|
||||||
|
expect($this->testee->getWorkflows())->count(1);
|
||||||
|
expect($this->testee->getWorkflow($workflowToDelete->getId()))->null();
|
||||||
|
$workflowToKeepFromDatabase = $this->testee->getWorkflow($workflowToKeep->getId());
|
||||||
|
$this->assertInstanceOf(Workflow::class, $workflowToKeepFromDatabase);
|
||||||
|
expect($workflowToKeepFromDatabase->getVersionId())->notNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItCanDeleteWorkflowsRelatedData() {
|
||||||
|
$workflowRunStorage = $this->diContainer->get(WorkflowRunStorage::class);
|
||||||
|
$workflowRunLogStorage = $this->diContainer->get(WorkflowRunLogStorage::class);
|
||||||
|
$workflows = [
|
||||||
|
'toDelete' => $this->createEmptyWorkflow(),
|
||||||
|
'toKeep' => $this->createEmptyWorkflow()
|
||||||
|
];
|
||||||
|
$runs = [
|
||||||
|
'toDelete' => [],
|
||||||
|
'toKeep' => []
|
||||||
|
];
|
||||||
|
$runLogs = [
|
||||||
|
'toDelete' => [],
|
||||||
|
'toKeep' => []
|
||||||
|
];
|
||||||
|
foreach ($workflows as $type => $workflow) {
|
||||||
|
for ($i = 0; $i < 2; $i++) {
|
||||||
|
$workflowRun = new WorkflowRun($workflow->getId(), $workflow->getVersionId(), 'trigger-key', []);
|
||||||
|
$runId = $workflowRunStorage->createWorkflowRun($workflowRun);
|
||||||
|
$runs[$type][] = $runId;
|
||||||
|
for ($i = 0; $i < 2; $i++) {
|
||||||
|
$log = new WorkflowRunLog($runId, "step-{$i}");
|
||||||
|
$logId = $workflowRunLogStorage->createWorkflowRunLog($log);
|
||||||
|
$runLogs[$type][] = $logId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->testee->deleteWorkflow($workflows['toDelete']);
|
||||||
|
foreach ($runs['toDelete'] as $runId) {
|
||||||
|
expect($workflowRunStorage->getWorkflowRun($runId))->null();
|
||||||
|
}
|
||||||
|
foreach ($runs['toKeep'] as $runId) {
|
||||||
|
expect($workflowRunStorage->getWorkflowRun($runId))->notNull();
|
||||||
|
}
|
||||||
|
foreach ($runLogs['toDelete'] as $runLogId) {
|
||||||
|
expect($workflowRunLogStorage->getWorkflowRunLog($runLogId))->null();
|
||||||
|
}
|
||||||
|
foreach ($runLogs['toKeep'] as $runLogId) {
|
||||||
|
expect($workflowRunLogStorage->getWorkflowRunLog($runLogId))->notNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function createEmptyWorkflow(string $name="test"): Workflow {
|
private function createEmptyWorkflow(string $name="test"): Workflow {
|
||||||
$workflow = new Workflow($name, [], new \WP_User());
|
$workflow = new Workflow($name, [], new \WP_User());
|
||||||
$workflowId = $this->testee->createWorkflow($workflow);
|
$workflowId = $this->testee->createWorkflow($workflow);
|
||||||
|
Reference in New Issue
Block a user