aboutsummaryrefslogtreecommitdiffstats
path: root/apps/workflowengine/lib/Manager.php
diff options
context:
space:
mode:
Diffstat (limited to 'apps/workflowengine/lib/Manager.php')
-rw-r--r--apps/workflowengine/lib/Manager.php637
1 files changed, 500 insertions, 137 deletions
diff --git a/apps/workflowengine/lib/Manager.php b/apps/workflowengine/lib/Manager.php
index 48d29cf207e..0f41679789d 100644
--- a/apps/workflowengine/lib/Manager.php
+++ b/apps/workflowengine/lib/Manager.php
@@ -1,150 +1,215 @@
<?php
+
/**
- * @copyright Copyright (c) 2016 Morris Jobke <hey@morrisjobke.de>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace OCA\WorkflowEngine;
-
+use Doctrine\DBAL\Exception;
+use OCA\WorkflowEngine\AppInfo\Application;
+use OCA\WorkflowEngine\Check\FileMimeType;
+use OCA\WorkflowEngine\Check\FileName;
+use OCA\WorkflowEngine\Check\FileSize;
+use OCA\WorkflowEngine\Check\FileSystemTags;
+use OCA\WorkflowEngine\Check\RequestRemoteAddress;
+use OCA\WorkflowEngine\Check\RequestTime;
+use OCA\WorkflowEngine\Check\RequestURL;
+use OCA\WorkflowEngine\Check\RequestUserAgent;
+use OCA\WorkflowEngine\Check\UserGroupMembership;
+use OCA\WorkflowEngine\Entity\File;
+use OCA\WorkflowEngine\Helper\ScopeContext;
+use OCA\WorkflowEngine\Service\Logger;
+use OCA\WorkflowEngine\Service\RuleMatcher;
use OCP\AppFramework\QueryException;
+use OCP\Cache\CappedMemoryCache;
use OCP\DB\QueryBuilder\IQueryBuilder;
-use OCP\Files\Storage\IStorage;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\ICacheFactory;
+use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IL10N;
use OCP\IServerContainer;
+use OCP\IUserSession;
+use OCP\WorkflowEngine\Events\RegisterChecksEvent;
+use OCP\WorkflowEngine\Events\RegisterEntitiesEvent;
+use OCP\WorkflowEngine\Events\RegisterOperationsEvent;
use OCP\WorkflowEngine\ICheck;
+use OCP\WorkflowEngine\IComplexOperation;
+use OCP\WorkflowEngine\IEntity;
+use OCP\WorkflowEngine\IEntityEvent;
use OCP\WorkflowEngine\IManager;
use OCP\WorkflowEngine\IOperation;
+use OCP\WorkflowEngine\IRuleMatcher;
+use Psr\Log\LoggerInterface;
class Manager implements IManager {
-
- /** @var IStorage */
- protected $storage;
-
- /** @var string */
- protected $path;
-
/** @var array[] */
protected $operations = [];
/** @var array[] */
protected $checks = [];
- /** @var IDBConnection */
- protected $connection;
+ /** @var IEntity[] */
+ protected $registeredEntities = [];
+
+ /** @var IOperation[] */
+ protected $registeredOperators = [];
+
+ /** @var ICheck[] */
+ protected $registeredChecks = [];
+
+ /** @var CappedMemoryCache<int[]> */
+ protected CappedMemoryCache $operationsByScope;
+
+ public function __construct(
+ protected IDBConnection $connection,
+ protected IServerContainer $container,
+ protected IL10N $l,
+ protected LoggerInterface $logger,
+ protected IUserSession $session,
+ private IEventDispatcher $dispatcher,
+ private IConfig $config,
+ private ICacheFactory $cacheFactory,
+ ) {
+ $this->operationsByScope = new CappedMemoryCache(64);
+ }
- /** @var IServerContainer|\OC\Server */
- protected $container;
+ public function getRuleMatcher(): IRuleMatcher {
+ return new RuleMatcher(
+ $this->session,
+ $this->container,
+ $this->l,
+ $this,
+ $this->container->query(Logger::class)
+ );
+ }
- /** @var IL10N */
- protected $l;
+ public function getAllConfiguredEvents() {
+ $cache = $this->cacheFactory->createDistributed('flow');
+ $cached = $cache->get('events');
+ if ($cached !== null) {
+ return $cached;
+ }
- /**
- * @param IDBConnection $connection
- * @param IServerContainer $container
- * @param IL10N $l
- */
- public function __construct(IDBConnection $connection, IServerContainer $container, IL10N $l) {
- $this->connection = $connection;
- $this->container = $container;
- $this->l = $l;
- }
+ $query = $this->connection->getQueryBuilder();
- /**
- * @inheritdoc
- */
- public function setFileInfo(IStorage $storage, $path) {
- $this->storage = $storage;
- $this->path = $path;
- }
+ $query->select('class', 'entity')
+ ->selectAlias($query->expr()->castColumn('events', IQueryBuilder::PARAM_STR), 'events')
+ ->from('flow_operations')
+ ->where($query->expr()->neq('events', $query->createNamedParameter('[]'), IQueryBuilder::PARAM_STR))
+ ->groupBy('class', 'entity', $query->expr()->castColumn('events', IQueryBuilder::PARAM_STR));
- /**
- * @inheritdoc
- */
- public function getMatchingOperations($class, $returnFirstMatchingOperationOnly = true) {
- $operations = $this->getOperations($class);
+ $result = $query->executeQuery();
+ $operations = [];
+ while ($row = $result->fetch()) {
+ $eventNames = \json_decode($row['events']);
- $matches = [];
- foreach ($operations as $operation) {
- $checkIds = json_decode($operation['checks'], true);
- $checks = $this->getChecks($checkIds);
+ $operation = $row['class'];
+ $entity = $row['entity'];
- foreach ($checks as $check) {
- if (!$this->check($check)) {
- // Check did not match, continue with the next operation
- continue 2;
- }
- }
+ $operations[$operation] = $operations[$row['class']] ?? [];
+ $operations[$operation][$entity] = $operations[$operation][$entity] ?? [];
- if ($returnFirstMatchingOperationOnly) {
- return $operation;
- }
- $matches[] = $operation;
+ $operations[$operation][$entity] = array_unique(array_merge($operations[$operation][$entity], $eventNames ?? []));
}
+ $result->closeCursor();
+
+ $cache->set('events', $operations, 3600);
- return $matches;
+ return $operations;
}
/**
- * @param array $check
- * @return bool
+ * @param string $operationClass
+ * @return ScopeContext[]
*/
- protected function check(array $check) {
+ public function getAllConfiguredScopesForOperation(string $operationClass): array {
+ static $scopesByOperation = [];
+ if (isset($scopesByOperation[$operationClass])) {
+ return $scopesByOperation[$operationClass];
+ }
+
try {
- $checkInstance = $this->container->query($check['class']);
+ /** @var IOperation $operation */
+ $operation = $this->container->query($operationClass);
} catch (QueryException $e) {
- // Check does not exist, assume it matches.
- return true;
+ return [];
}
- if ($checkInstance instanceof ICheck) {
- $checkInstance->setFileInfo($this->storage, $this->path);
- return $checkInstance->executeCheck($check['operator'], $check['value']);
- } else {
- // Check is invalid
- throw new \UnexpectedValueException($this->l->t('Check %s is invalid or does not exist', $check['class']));
+ $query = $this->connection->getQueryBuilder();
+
+ $query->selectDistinct('s.type')
+ ->addSelect('s.value')
+ ->from('flow_operations', 'o')
+ ->leftJoin('o', 'flow_operations_scope', 's', $query->expr()->eq('o.id', 's.operation_id'))
+ ->where($query->expr()->eq('o.class', $query->createParameter('operationClass')));
+
+ $query->setParameters(['operationClass' => $operationClass]);
+ $result = $query->executeQuery();
+
+ $scopesByOperation[$operationClass] = [];
+ while ($row = $result->fetch()) {
+ $scope = new ScopeContext($row['type'], $row['value']);
+
+ if (!$operation->isAvailableForScope((int)$row['type'])) {
+ continue;
+ }
+
+ $scopesByOperation[$operationClass][$scope->getHash()] = $scope;
}
+
+ return $scopesByOperation[$operationClass];
}
- /**
- * @param string $class
- * @return array[]
- */
- public function getOperations($class) {
- if (isset($this->operations[$class])) {
- return $this->operations[$class];
+ public function getAllOperations(ScopeContext $scopeContext): array {
+ if (isset($this->operations[$scopeContext->getHash()])) {
+ return $this->operations[$scopeContext->getHash()];
}
$query = $this->connection->getQueryBuilder();
- $query->select('*')
- ->from('flow_operations')
- ->where($query->expr()->eq('class', $query->createNamedParameter($class)));
- $result = $query->execute();
+ $query->select('o.*')
+ ->selectAlias('s.type', 'scope_type')
+ ->selectAlias('s.value', 'scope_actor_id')
+ ->from('flow_operations', 'o')
+ ->leftJoin('o', 'flow_operations_scope', 's', $query->expr()->eq('o.id', 's.operation_id'))
+ ->where($query->expr()->eq('s.type', $query->createParameter('scope')));
+
+ if ($scopeContext->getScope() === IManager::SCOPE_USER) {
+ $query->andWhere($query->expr()->eq('s.value', $query->createParameter('scopeId')));
+ }
+
+ $query->setParameters(['scope' => $scopeContext->getScope(), 'scopeId' => $scopeContext->getScopeId()]);
+ $result = $query->executeQuery();
- $this->operations[$class] = [];
+ $this->operations[$scopeContext->getHash()] = [];
while ($row = $result->fetch()) {
- $this->operations[$class][] = $row;
+ try {
+ /** @var IOperation $operation */
+ $operation = $this->container->query($row['class']);
+ } catch (QueryException $e) {
+ continue;
+ }
+
+ if (!$operation->isAvailableForScope((int)$row['scope_type'])) {
+ continue;
+ }
+
+ if (!isset($this->operations[$scopeContext->getHash()][$row['class']])) {
+ $this->operations[$scopeContext->getHash()][$row['class']] = [];
+ }
+ $this->operations[$scopeContext->getHash()][$row['class']][] = $row;
}
- $result->closeCursor();
- return $this->operations[$class];
+ return $this->operations[$scopeContext->getHash()];
+ }
+
+ public function getOperations(string $class, ScopeContext $scopeContext): array {
+ if (!isset($this->operations[$scopeContext->getHash()])) {
+ $this->getAllOperations($scopeContext);
+ }
+ return $this->operations[$scopeContext->getHash()][$class] ?? [];
}
/**
@@ -157,7 +222,7 @@ class Manager implements IManager {
$query->select('*')
->from('flow_operations')
->where($query->expr()->eq('id', $query->createNamedParameter($id)));
- $result = $query->execute();
+ $result = $query->executeQuery();
$row = $result->fetch();
$result->closeCursor();
@@ -168,6 +233,31 @@ class Manager implements IManager {
throw new \UnexpectedValueException($this->l->t('Operation #%s does not exist', [$id]));
}
+ protected function insertOperation(
+ string $class,
+ string $name,
+ array $checkIds,
+ string $operation,
+ string $entity,
+ array $events,
+ ): int {
+ $query = $this->connection->getQueryBuilder();
+ $query->insert('flow_operations')
+ ->values([
+ 'class' => $query->createNamedParameter($class),
+ 'name' => $query->createNamedParameter($name),
+ 'checks' => $query->createNamedParameter(json_encode(array_unique($checkIds))),
+ 'operation' => $query->createNamedParameter($operation),
+ 'entity' => $query->createNamedParameter($entity),
+ 'events' => $query->createNamedParameter(json_encode($events))
+ ]);
+ $query->executeStatement();
+
+ $this->cacheFactory->createDistributed('flow')->remove('events');
+
+ return $query->getLastInsertId();
+ }
+
/**
* @param string $class
* @param string $name
@@ -175,29 +265,67 @@ class Manager implements IManager {
* @param string $operation
* @return array The added operation
* @throws \UnexpectedValueException
+ * @throws Exception
*/
- public function addOperation($class, $name, array $checks, $operation) {
- $this->validateOperation($class, $name, $checks, $operation);
+ public function addOperation(
+ string $class,
+ string $name,
+ array $checks,
+ string $operation,
+ ScopeContext $scope,
+ string $entity,
+ array $events,
+ ) {
+ $this->validateOperation($class, $name, $checks, $operation, $scope, $entity, $events);
+
+ $this->connection->beginTransaction();
- $checkIds = [];
- foreach ($checks as $check) {
- $checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']);
- }
+ try {
+ $checkIds = [];
+ foreach ($checks as $check) {
+ $checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']);
+ }
- $query = $this->connection->getQueryBuilder();
- $query->insert('flow_operations')
- ->values([
- 'class' => $query->createNamedParameter($class),
- 'name' => $query->createNamedParameter($name),
- 'checks' => $query->createNamedParameter(json_encode(array_unique($checkIds))),
- 'operation' => $query->createNamedParameter($operation),
- ]);
- $query->execute();
+ $id = $this->insertOperation($class, $name, $checkIds, $operation, $entity, $events);
+ $this->addScope($id, $scope);
+
+ $this->connection->commit();
+ } catch (Exception $e) {
+ $this->connection->rollBack();
+ throw $e;
+ }
- $id = $query->getLastInsertId();
return $this->getOperation($id);
}
+ protected function canModify(int $id, ScopeContext $scopeContext):bool {
+ if (isset($this->operationsByScope[$scopeContext->getHash()])) {
+ return in_array($id, $this->operationsByScope[$scopeContext->getHash()], true);
+ }
+
+ $qb = $this->connection->getQueryBuilder();
+ $qb = $qb->select('o.id')
+ ->from('flow_operations', 'o')
+ ->leftJoin('o', 'flow_operations_scope', 's', $qb->expr()->eq('o.id', 's.operation_id'))
+ ->where($qb->expr()->eq('s.type', $qb->createParameter('scope')));
+
+ if ($scopeContext->getScope() !== IManager::SCOPE_ADMIN) {
+ $qb->andWhere($qb->expr()->eq('s.value', $qb->createParameter('scopeId')));
+ }
+
+ $qb->setParameters(['scope' => $scopeContext->getScope(), 'scopeId' => $scopeContext->getScopeId()]);
+ $result = $qb->executeQuery();
+
+ $operations = [];
+ while (($opId = $result->fetchOne()) !== false) {
+ $operations[] = (int)$opId;
+ }
+ $this->operationsByScope[$scopeContext->getHash()] = $operations;
+ $result->closeCursor();
+
+ return in_array($id, $this->operationsByScope[$scopeContext->getHash()], true);
+ }
+
/**
* @param int $id
* @param string $name
@@ -205,23 +333,47 @@ class Manager implements IManager {
* @param string $operation
* @return array The updated operation
* @throws \UnexpectedValueException
+ * @throws \DomainException
+ * @throws Exception
*/
- public function updateOperation($id, $name, array $checks, $operation) {
+ public function updateOperation(
+ int $id,
+ string $name,
+ array $checks,
+ string $operation,
+ ScopeContext $scopeContext,
+ string $entity,
+ 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, $scopeContext, $entity, $events);
$checkIds = [];
- foreach ($checks as $check) {
- $checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']);
- }
+ try {
+ $this->connection->beginTransaction();
+ foreach ($checks as $check) {
+ $checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']);
+ }
- $query = $this->connection->getQueryBuilder();
- $query->update('flow_operations')
- ->set('name', $query->createNamedParameter($name))
- ->set('checks', $query->createNamedParameter(json_encode(array_unique($checkIds))))
- ->set('operation', $query->createNamedParameter($operation))
- ->where($query->expr()->eq('id', $query->createNamedParameter($id)));
- $query->execute();
+ $query = $this->connection->getQueryBuilder();
+ $query->update('flow_operations')
+ ->set('name', $query->createNamedParameter($name))
+ ->set('checks', $query->createNamedParameter(json_encode(array_unique($checkIds))))
+ ->set('operation', $query->createNamedParameter($operation))
+ ->set('entity', $query->createNamedParameter($entity))
+ ->set('events', $query->createNamedParameter(json_encode($events)))
+ ->where($query->expr()->eq('id', $query->createNamedParameter($id)));
+ $query->execute();
+ $this->connection->commit();
+ } catch (Exception $e) {
+ $this->connection->rollBack();
+ throw $e;
+ }
+ unset($this->operations[$scopeContext->getHash()]);
+ $this->cacheFactory->createDistributed('flow')->remove('events');
return $this->getOperation($id);
}
@@ -230,12 +382,69 @@ class Manager implements IManager {
* @param int $id
* @return bool
* @throws \UnexpectedValueException
+ * @throws Exception
+ * @throws \DomainException
*/
- public function deleteOperation($id) {
+ public function deleteOperation($id, ScopeContext $scopeContext) {
+ if (!$this->canModify($id, $scopeContext)) {
+ throw new \DomainException('Target operation not within scope');
+ };
$query = $this->connection->getQueryBuilder();
- $query->delete('flow_operations')
- ->where($query->expr()->eq('id', $query->createNamedParameter($id)));
- return (bool) $query->execute();
+ try {
+ $this->connection->beginTransaction();
+ $result = (bool)$query->delete('flow_operations')
+ ->where($query->expr()->eq('id', $query->createNamedParameter($id)))
+ ->executeStatement();
+ if ($result) {
+ $qb = $this->connection->getQueryBuilder();
+ $result &= (bool)$qb->delete('flow_operations_scope')
+ ->where($qb->expr()->eq('operation_id', $qb->createNamedParameter($id)))
+ ->executeStatement();
+ }
+ $this->connection->commit();
+ } catch (Exception $e) {
+ $this->connection->rollBack();
+ throw $e;
+ }
+
+ if (isset($this->operations[$scopeContext->getHash()])) {
+ unset($this->operations[$scopeContext->getHash()]);
+ }
+
+ $this->cacheFactory->createDistributed('flow')->remove('events');
+
+ return $result;
+ }
+
+ protected function validateEvents(string $entity, array $events, IOperation $operation) {
+ 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]));
+ }
+
+ if (empty($events)) {
+ if (!$operation instanceof IComplexOperation) {
+ throw new \UnexpectedValueException($this->l->t('No events are chosen.'));
+ }
+ return;
+ }
+
+ $availableEvents = [];
+ foreach ($instance->getEvents() as $event) {
+ /** @var IEntityEvent $event */
+ $availableEvents[] = $event->getEventName();
+ }
+
+ $diff = array_diff($events, $availableEvents);
+ if (!empty($diff)) {
+ throw new \UnexpectedValueException($this->l->t('Entity %s has no event %s', [$entity, array_shift($diff)]));
+ }
}
/**
@@ -243,9 +452,12 @@ class Manager implements IManager {
* @param string $name
* @param array[] $checks
* @param string $operation
+ * @param ScopeContext $scope
+ * @param string $entity
+ * @param array $events
* @throws \UnexpectedValueException
*/
- protected function validateOperation($class, $name, array $checks, $operation) {
+ public function validateOperation($class, $name, array $checks, $operation, ScopeContext $scope, string $entity, array $events) {
try {
/** @var IOperation $instance */
$instance = $this->container->query($class);
@@ -257,9 +469,27 @@ class Manager implements IManager {
throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]));
}
+ if (!$instance->isAvailableForScope($scope->getScope())) {
+ throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]));
+ }
+
+ $this->validateEvents($entity, $events, $instance);
+
+ if (count($checks) === 0) {
+ throw new \UnexpectedValueException($this->l->t('At least one check needs to be provided'));
+ }
+
+ if (strlen((string)$operation) > IManager::MAX_OPERATION_VALUE_BYTES) {
+ throw new \UnexpectedValueException($this->l->t('The provided operation data is too long'));
+ }
+
$instance->validateOperation($name, $checks, $operation);
foreach ($checks as $check) {
+ if (!is_string($check['class'])) {
+ throw new \UnexpectedValueException($this->l->t('Invalid check provided'));
+ }
+
try {
/** @var ICheck $instance */
$instance = $this->container->query($check['class']);
@@ -271,6 +501,16 @@ class Manager implements IManager {
throw new \UnexpectedValueException($this->l->t('Check %s is invalid', [$class]));
}
+ if (!empty($instance->supportedEntities())
+ && !in_array($entity, $instance->supportedEntities())
+ ) {
+ throw new \UnexpectedValueException($this->l->t('Check %s is not allowed with this entity', [$class]));
+ }
+
+ if (strlen((string)$check['value']) > IManager::MAX_CHECK_VALUE_BYTES) {
+ throw new \UnexpectedValueException($this->l->t('The provided check value is too long'));
+ }
+
$instance->validateCheck($check['operator'], $check['value']);
}
}
@@ -298,11 +538,11 @@ class Manager implements IManager {
$query->select('*')
->from('flow_checks')
->where($query->expr()->in('id', $query->createNamedParameter($checkIds, IQueryBuilder::PARAM_INT_ARRAY)));
- $result = $query->execute();
+ $result = $query->executeQuery();
while ($row = $result->fetch()) {
- $this->checks[(int) $row['id']] = $row;
- $checks[(int) $row['id']] = $row;
+ $this->checks[(int)$row['id']] = $row;
+ $checks[(int)$row['id']] = $row;
}
$result->closeCursor();
@@ -329,11 +569,11 @@ class Manager implements IManager {
$query->select('id')
->from('flow_checks')
->where($query->expr()->eq('hash', $query->createNamedParameter($hash)));
- $result = $query->execute();
+ $result = $query->executeQuery();
if ($row = $result->fetch()) {
$result->closeCursor();
- return (int) $row['id'];
+ return (int)$row['id'];
}
$query = $this->connection->getQueryBuilder();
@@ -344,8 +584,131 @@ class Manager implements IManager {
'value' => $query->createNamedParameter($value),
'hash' => $query->createNamedParameter($hash),
]);
- $query->execute();
+ $query->executeStatement();
return $query->getLastInsertId();
}
+
+ protected function addScope(int $operationId, ScopeContext $scope): void {
+ $query = $this->connection->getQueryBuilder();
+
+ $insertQuery = $query->insert('flow_operations_scope');
+ $insertQuery->values([
+ 'operation_id' => $query->createNamedParameter($operationId),
+ 'type' => $query->createNamedParameter($scope->getScope()),
+ 'value' => $query->createNamedParameter($scope->getScopeId()),
+ ]);
+ $insertQuery->executeStatement();
+ }
+
+ public function formatOperation(array $operation): array {
+ $checkIds = json_decode($operation['checks'], true);
+ $checks = $this->getChecks($checkIds);
+
+ $operation['checks'] = [];
+ foreach ($checks as $check) {
+ // Remove internal values
+ unset($check['id']);
+ unset($check['hash']);
+
+ $operation['checks'][] = $check;
+ }
+ $operation['events'] = json_decode($operation['events'], true) ?? [];
+
+
+ return $operation;
+ }
+
+ /**
+ * @return IEntity[]
+ */
+ public function getEntitiesList(): array {
+ $this->dispatcher->dispatchTyped(new RegisterEntitiesEvent($this));
+
+ return array_values(array_merge($this->getBuildInEntities(), $this->registeredEntities));
+ }
+
+ /**
+ * @return IOperation[]
+ */
+ public function getOperatorList(): array {
+ $this->dispatcher->dispatchTyped(new RegisterOperationsEvent($this));
+
+ return array_merge($this->getBuildInOperators(), $this->registeredOperators);
+ }
+
+ /**
+ * @return ICheck[]
+ */
+ public function getCheckList(): array {
+ $this->dispatcher->dispatchTyped(new RegisterChecksEvent($this));
+
+ return array_merge($this->getBuildInChecks(), $this->registeredChecks);
+ }
+
+ public function registerEntity(IEntity $entity): void {
+ $this->registeredEntities[get_class($entity)] = $entity;
+ }
+
+ public function registerOperation(IOperation $operator): void {
+ $this->registeredOperators[get_class($operator)] = $operator;
+ }
+
+ public function registerCheck(ICheck $check): void {
+ $this->registeredChecks[get_class($check)] = $check;
+ }
+
+ /**
+ * @return IEntity[]
+ */
+ protected function getBuildInEntities(): array {
+ try {
+ return [
+ File::class => $this->container->query(File::class),
+ ];
+ } catch (QueryException $e) {
+ $this->logger->error($e->getMessage(), ['exception' => $e]);
+ return [];
+ }
+ }
+
+ /**
+ * @return IOperation[]
+ */
+ protected function getBuildInOperators(): array {
+ try {
+ return [
+ // None yet
+ ];
+ } catch (QueryException $e) {
+ $this->logger->error($e->getMessage(), ['exception' => $e]);
+ return [];
+ }
+ }
+
+ /**
+ * @return ICheck[]
+ */
+ protected function getBuildInChecks(): array {
+ try {
+ return [
+ $this->container->query(FileMimeType::class),
+ $this->container->query(FileName::class),
+ $this->container->query(FileSize::class),
+ $this->container->query(FileSystemTags::class),
+ $this->container->query(RequestRemoteAddress::class),
+ $this->container->query(RequestTime::class),
+ $this->container->query(RequestURL::class),
+ $this->container->query(RequestUserAgent::class),
+ $this->container->query(UserGroupMembership::class),
+ ];
+ } catch (QueryException $e) {
+ $this->logger->error($e->getMessage(), ['exception' => $e]);
+ return [];
+ }
+ }
+
+ public function isUserScopeEnabled(): bool {
+ return $this->config->getAppValue(Application::APP_ID, 'user_scope_disabled', 'no') === 'no';
+ }
}