diff --git a/apps/workflowengine/lib/Controller/AWorkflowController.php b/apps/workflowengine/lib/Controller/AWorkflowController.php index 2e54e417a3..24f5732183 100644 --- a/apps/workflowengine/lib/Controller/AWorkflowController.php +++ b/apps/workflowengine/lib/Controller/AWorkflowController.php @@ -94,10 +94,16 @@ abstract class AWorkflowController extends OCSController { * @throws OCSForbiddenException * @throws OCSException */ - public function create(string $class, string $name, array $checks, string $operation): DataResponse { + public function create( + string $class, + string $name, + array $checks, + string $operation, + array $events + ): DataResponse { $context = $this->getScopeContext(); try { - $operation = $this->manager->addOperation($class, $name, $checks, $operation, $context); + $operation = $this->manager->addOperation($class, $name, $checks, $operation, $context, $events); $operation = $this->manager->formatOperation($operation); return new DataResponse($operation); } catch (\UnexpectedValueException $e) { @@ -114,9 +120,15 @@ abstract class AWorkflowController extends OCSController { * @throws OCSForbiddenException * @throws OCSException */ - public function update(int $id, string $name, array $checks, string $operation): DataResponse { + public function update( + int $id, + string $name, + array $checks, + string $operation, + array $events + ): DataResponse { try { - $operation = $this->manager->updateOperation($id, $name, $checks, $operation, $this->getScopeContext()); + $operation = $this->manager->updateOperation($id, $name, $checks, $operation, $this->getScopeContext(), $events); $operation = $this->manager->formatOperation($operation); return new DataResponse($operation); } catch (\UnexpectedValueException $e) { diff --git a/apps/workflowengine/lib/Manager.php b/apps/workflowengine/lib/Manager.php index adde530919..d0376e703e 100644 --- a/apps/workflowengine/lib/Manager.php +++ b/apps/workflowengine/lib/Manager.php @@ -38,6 +38,7 @@ use OCP\IUserSession; use OCP\WorkflowEngine\ICheck; use OCP\WorkflowEngine\IEntity; use OCP\WorkflowEngine\IEntityAware; +use OCP\WorkflowEngine\IEntityEvent; use OCP\WorkflowEngine\IManager; use OCP\WorkflowEngine\IOperation; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -238,7 +239,13 @@ class Manager implements IManager, IEntityAware { throw new \UnexpectedValueException($this->l->t('Operation #%s does not exist', [$id])); } - protected function insertOperation(string $class, string $name, array $checkIds, string $operation): int { + protected function insertOperation( + string $class, + string $name, + array $checkIds, + string $operation, + array $events + ): int { $query = $this->connection->getQueryBuilder(); $query->insert('flow_operations') ->values([ @@ -246,6 +253,7 @@ class Manager implements IManager, IEntityAware { 'name' => $query->createNamedParameter($name), 'checks' => $query->createNamedParameter(json_encode(array_unique($checkIds))), 'operation' => $query->createNamedParameter($operation), + 'events' => $query->createNamedParameter(json_encode($events)) ]); $query->execute(); @@ -261,8 +269,15 @@ class Manager implements IManager, IEntityAware { * @throws \UnexpectedValueException * @throws DBALException */ - public function addOperation($class, $name, array $checks, $operation, ScopeContext $scope) { - $this->validateOperation($class, $name, $checks, $operation); + public function addOperation( + string $class, + string $name, + array $checks, + string $operation, + ScopeContext $scope, + array $events + ) { + $this->validateOperation($class, $name, $checks, $operation, $events); $this->connection->beginTransaction(); @@ -272,7 +287,7 @@ class Manager implements IManager, IEntityAware { $checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']); } - $id = $this->insertOperation($class, $name, $checkIds, $operation); + $id = $this->insertOperation($class, $name, $checkIds, $operation, $events); $this->addScope($id, $scope); $this->connection->commit(); @@ -321,12 +336,19 @@ class Manager implements IManager, IEntityAware { * @throws \DomainException * @throws DBALException */ - public function updateOperation($id, $name, array $checks, $operation, ScopeContext $scopeContext): array { + public function updateOperation( + int $id, + string $name, + array $checks, + string $operation, + ScopeContext $scopeContext, + array $events + ): array { if(!$this->canModify($id, $scopeContext)) { throw new \DomainException('Target operation not within scope'); }; $row = $this->getOperation($id); - $this->validateOperation($row['class'], $name, $checks, $operation); + $this->validateOperation($row['class'], $name, $checks, $operation, $events); $checkIds = []; try { @@ -340,6 +362,7 @@ class Manager implements IManager, IEntityAware { ->set('name', $query->createNamedParameter($name)) ->set('checks', $query->createNamedParameter(json_encode(array_unique($checkIds)))) ->set('operation', $query->createNamedParameter($operation)) + ->set('events', $query->createNamedParameter(json_encode($events))) ->where($query->expr()->eq('id', $query->createNamedParameter($id))); $query->execute(); $this->connection->commit(); @@ -388,6 +411,30 @@ class Manager implements IManager, IEntityAware { return $result; } + protected function validateEvents($events) { + foreach ($events as $entity => $eventNames) { + try { + /** @var IEntity $instance */ + $instance = $this->container->query($entity); + } catch (QueryException $e) { + throw new \UnexpectedValueException($this->l->t('Entity %s does not exist', [$entity])); + } + + if(!$instance instanceof IEntity) { + throw new \UnexpectedValueException($this->l->t('Entity %s is invalid', [$entity])); + } + + $availableEvents = array_reduce($instance->getEvents(), function(array $carry, IEntityEvent $event) { + $carry[] = $event->getEventName(); + }, []); + foreach($eventNames as $event) { + if(!in_array($event, $availableEvents, true)) { + throw new \UnexpectedValueException($this->l->t('Entity %s has no event %s', [$entity, $event])); + } + } + } + } + /** * @param string $class * @param string $name @@ -395,7 +442,7 @@ class Manager implements IManager, IEntityAware { * @param string $operation * @throws \UnexpectedValueException */ - protected function validateOperation($class, $name, array $checks, $operation) { + protected function validateOperation($class, $name, array $checks, $operation, array $events) { try { /** @var IOperation $instance */ $instance = $this->container->query($class); @@ -407,6 +454,8 @@ class Manager implements IManager, IEntityAware { throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class])); } + $this->validateEvents($events); + $instance->validateOperation($name, $checks, $operation); foreach ($checks as $check) { diff --git a/apps/workflowengine/lib/Migration/Version2019Date20190808074233.php b/apps/workflowengine/lib/Migration/Version2019Date20190808074233.php index cedee43a9e..2b9a8aa17c 100644 --- a/apps/workflowengine/lib/Migration/Version2019Date20190808074233.php +++ b/apps/workflowengine/lib/Migration/Version2019Date20190808074233.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace OCA\WorkflowEngine\Migration; use Closure; +use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\Type; use OCP\DB\ISchemaWrapper; use OCP\Migration\SimpleMigrationStep; @@ -69,7 +70,13 @@ class Version2019Date20190808074233 extends SimpleMigrationStep { $table->addColumn('operation', Type::TEXT, [ 'notnull' => false, ]); + $this->addEventsColumn($table); $table->setPrimaryKey(['id']); + } else { + $table = $schema->getTable('flow_operations'); + if(!$table->hasColumn('events')) { + $this->addEventsColumn($table); + } } if (!$schema->hasTable('flow_operations_scope')) { @@ -97,4 +104,11 @@ class Version2019Date20190808074233 extends SimpleMigrationStep { return $schema; } + + protected function addEventsColumn(Table $table) { + $table->addColumn('events', Type::TEXT, [ + 'notnull' => true, + 'default' => '[]', + ]); + } } diff --git a/apps/workflowengine/tests/ManagerTest.php b/apps/workflowengine/tests/ManagerTest.php index a497cd85a8..a2d30944f7 100644 --- a/apps/workflowengine/tests/ManagerTest.php +++ b/apps/workflowengine/tests/ManagerTest.php @@ -290,19 +290,19 @@ class ManagerTest extends TestCase { $check2 = ['class' => 'OCA\WFE\C33', 'operator' => 'eq', 'value' => 23456]; /** @noinspection PhpUnhandledExceptionInspection */ - $op = $this->manager->updateOperation($opId1, 'Test01a', [$check1, $check2], 'foohur', $adminScope); + $op = $this->manager->updateOperation($opId1, 'Test01a', [$check1, $check2], 'foohur', $adminScope, []); $this->assertSame('Test01a', $op['name']); $this->assertSame('foohur', $op['operation']); /** @noinspection PhpUnhandledExceptionInspection */ - $op = $this->manager->updateOperation($opId2, 'Test02a', [$check1], 'barfoo', $userScope); + $op = $this->manager->updateOperation($opId2, 'Test02a', [$check1], 'barfoo', $userScope, []); $this->assertSame('Test02a', $op['name']); $this->assertSame('barfoo', $op['operation']); foreach([[$adminScope, $opId2], [$userScope, $opId1]] as $run) { try { /** @noinspection PhpUnhandledExceptionInspection */ - $this->manager->updateOperation($run[1], 'Evil', [$check2], 'hackx0r', $run[0]); + $this->manager->updateOperation($run[1], 'Evil', [$check2], 'hackx0r', $run[0], []); $this->assertTrue(false, 'DomainException not thrown'); } catch (\DomainException $e) { $this->assertTrue(true); @@ -398,4 +398,5 @@ class ManagerTest extends TestCase { $this->assertSame(1, $entityTypeCounts[0]); $this->assertSame(1, $entityTypeCounts[1]); } + }