extend DB table, manager, controller with support for entity events

Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
This commit is contained in:
Arthur Schiwon 2019-08-27 17:51:10 +02:00
parent fe2a78609a
commit 827dd896fa
No known key found for this signature in database
GPG Key ID: 7424F1874854DF23
4 changed files with 90 additions and 14 deletions

View File

@ -94,10 +94,16 @@ abstract class AWorkflowController extends OCSController {
* @throws OCSForbiddenException * @throws OCSForbiddenException
* @throws OCSException * @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(); $context = $this->getScopeContext();
try { 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); $operation = $this->manager->formatOperation($operation);
return new DataResponse($operation); return new DataResponse($operation);
} catch (\UnexpectedValueException $e) { } catch (\UnexpectedValueException $e) {
@ -114,9 +120,15 @@ abstract class AWorkflowController extends OCSController {
* @throws OCSForbiddenException * @throws OCSForbiddenException
* @throws OCSException * @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 { 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); $operation = $this->manager->formatOperation($operation);
return new DataResponse($operation); return new DataResponse($operation);
} catch (\UnexpectedValueException $e) { } catch (\UnexpectedValueException $e) {

View File

@ -38,6 +38,7 @@ use OCP\IUserSession;
use OCP\WorkflowEngine\ICheck; use OCP\WorkflowEngine\ICheck;
use OCP\WorkflowEngine\IEntity; use OCP\WorkflowEngine\IEntity;
use OCP\WorkflowEngine\IEntityAware; use OCP\WorkflowEngine\IEntityAware;
use OCP\WorkflowEngine\IEntityEvent;
use OCP\WorkflowEngine\IManager; use OCP\WorkflowEngine\IManager;
use OCP\WorkflowEngine\IOperation; use OCP\WorkflowEngine\IOperation;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; 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])); 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 = $this->connection->getQueryBuilder();
$query->insert('flow_operations') $query->insert('flow_operations')
->values([ ->values([
@ -246,6 +253,7 @@ class Manager implements IManager, IEntityAware {
'name' => $query->createNamedParameter($name), 'name' => $query->createNamedParameter($name),
'checks' => $query->createNamedParameter(json_encode(array_unique($checkIds))), 'checks' => $query->createNamedParameter(json_encode(array_unique($checkIds))),
'operation' => $query->createNamedParameter($operation), 'operation' => $query->createNamedParameter($operation),
'events' => $query->createNamedParameter(json_encode($events))
]); ]);
$query->execute(); $query->execute();
@ -261,8 +269,15 @@ class Manager implements IManager, IEntityAware {
* @throws \UnexpectedValueException * @throws \UnexpectedValueException
* @throws DBALException * @throws DBALException
*/ */
public function addOperation($class, $name, array $checks, $operation, ScopeContext $scope) { public function addOperation(
$this->validateOperation($class, $name, $checks, $operation); string $class,
string $name,
array $checks,
string $operation,
ScopeContext $scope,
array $events
) {
$this->validateOperation($class, $name, $checks, $operation, $events);
$this->connection->beginTransaction(); $this->connection->beginTransaction();
@ -272,7 +287,7 @@ class Manager implements IManager, IEntityAware {
$checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']); $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->addScope($id, $scope);
$this->connection->commit(); $this->connection->commit();
@ -321,12 +336,19 @@ class Manager implements IManager, IEntityAware {
* @throws \DomainException * @throws \DomainException
* @throws DBALException * @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)) { if(!$this->canModify($id, $scopeContext)) {
throw new \DomainException('Target operation not within scope'); throw new \DomainException('Target operation not within scope');
}; };
$row = $this->getOperation($id); $row = $this->getOperation($id);
$this->validateOperation($row['class'], $name, $checks, $operation); $this->validateOperation($row['class'], $name, $checks, $operation, $events);
$checkIds = []; $checkIds = [];
try { try {
@ -340,6 +362,7 @@ class Manager implements IManager, IEntityAware {
->set('name', $query->createNamedParameter($name)) ->set('name', $query->createNamedParameter($name))
->set('checks', $query->createNamedParameter(json_encode(array_unique($checkIds)))) ->set('checks', $query->createNamedParameter(json_encode(array_unique($checkIds))))
->set('operation', $query->createNamedParameter($operation)) ->set('operation', $query->createNamedParameter($operation))
->set('events', $query->createNamedParameter(json_encode($events)))
->where($query->expr()->eq('id', $query->createNamedParameter($id))); ->where($query->expr()->eq('id', $query->createNamedParameter($id)));
$query->execute(); $query->execute();
$this->connection->commit(); $this->connection->commit();
@ -388,6 +411,30 @@ class Manager implements IManager, IEntityAware {
return $result; 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 $class
* @param string $name * @param string $name
@ -395,7 +442,7 @@ class Manager implements IManager, IEntityAware {
* @param string $operation * @param string $operation
* @throws \UnexpectedValueException * @throws \UnexpectedValueException
*/ */
protected function validateOperation($class, $name, array $checks, $operation) { protected function validateOperation($class, $name, array $checks, $operation, array $events) {
try { try {
/** @var IOperation $instance */ /** @var IOperation $instance */
$instance = $this->container->query($class); $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])); throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]));
} }
$this->validateEvents($events);
$instance->validateOperation($name, $checks, $operation); $instance->validateOperation($name, $checks, $operation);
foreach ($checks as $check) { foreach ($checks as $check) {

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace OCA\WorkflowEngine\Migration; namespace OCA\WorkflowEngine\Migration;
use Closure; use Closure;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Type;
use OCP\DB\ISchemaWrapper; use OCP\DB\ISchemaWrapper;
use OCP\Migration\SimpleMigrationStep; use OCP\Migration\SimpleMigrationStep;
@ -69,7 +70,13 @@ class Version2019Date20190808074233 extends SimpleMigrationStep {
$table->addColumn('operation', Type::TEXT, [ $table->addColumn('operation', Type::TEXT, [
'notnull' => false, 'notnull' => false,
]); ]);
$this->addEventsColumn($table);
$table->setPrimaryKey(['id']); $table->setPrimaryKey(['id']);
} else {
$table = $schema->getTable('flow_operations');
if(!$table->hasColumn('events')) {
$this->addEventsColumn($table);
}
} }
if (!$schema->hasTable('flow_operations_scope')) { if (!$schema->hasTable('flow_operations_scope')) {
@ -97,4 +104,11 @@ class Version2019Date20190808074233 extends SimpleMigrationStep {
return $schema; return $schema;
} }
protected function addEventsColumn(Table $table) {
$table->addColumn('events', Type::TEXT, [
'notnull' => true,
'default' => '[]',
]);
}
} }

View File

@ -290,19 +290,19 @@ class ManagerTest extends TestCase {
$check2 = ['class' => 'OCA\WFE\C33', 'operator' => 'eq', 'value' => 23456]; $check2 = ['class' => 'OCA\WFE\C33', 'operator' => 'eq', 'value' => 23456];
/** @noinspection PhpUnhandledExceptionInspection */ /** @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('Test01a', $op['name']);
$this->assertSame('foohur', $op['operation']); $this->assertSame('foohur', $op['operation']);
/** @noinspection PhpUnhandledExceptionInspection */ /** @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('Test02a', $op['name']);
$this->assertSame('barfoo', $op['operation']); $this->assertSame('barfoo', $op['operation']);
foreach([[$adminScope, $opId2], [$userScope, $opId1]] as $run) { foreach([[$adminScope, $opId2], [$userScope, $opId1]] as $run) {
try { try {
/** @noinspection PhpUnhandledExceptionInspection */ /** @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'); $this->assertTrue(false, 'DomainException not thrown');
} catch (\DomainException $e) { } catch (\DomainException $e) {
$this->assertTrue(true); $this->assertTrue(true);
@ -398,4 +398,5 @@ class ManagerTest extends TestCase {
$this->assertSame(1, $entityTypeCounts[0]); $this->assertSame(1, $entityTypeCounts[0]);
$this->assertSame(1, $entityTypeCounts[1]); $this->assertSame(1, $entityTypeCounts[1]);
} }
} }