Manager.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-License-Identifier: AGPL-3.0-or-later
  5. */
  6. namespace OCA\WorkflowEngine;
  7. use Doctrine\DBAL\Exception;
  8. use OCA\WorkflowEngine\AppInfo\Application;
  9. use OCA\WorkflowEngine\Check\FileMimeType;
  10. use OCA\WorkflowEngine\Check\FileName;
  11. use OCA\WorkflowEngine\Check\FileSize;
  12. use OCA\WorkflowEngine\Check\FileSystemTags;
  13. use OCA\WorkflowEngine\Check\RequestRemoteAddress;
  14. use OCA\WorkflowEngine\Check\RequestTime;
  15. use OCA\WorkflowEngine\Check\RequestURL;
  16. use OCA\WorkflowEngine\Check\RequestUserAgent;
  17. use OCA\WorkflowEngine\Check\UserGroupMembership;
  18. use OCA\WorkflowEngine\Entity\File;
  19. use OCA\WorkflowEngine\Helper\ScopeContext;
  20. use OCA\WorkflowEngine\Service\Logger;
  21. use OCA\WorkflowEngine\Service\RuleMatcher;
  22. use OCP\AppFramework\QueryException;
  23. use OCP\Cache\CappedMemoryCache;
  24. use OCP\DB\QueryBuilder\IQueryBuilder;
  25. use OCP\EventDispatcher\IEventDispatcher;
  26. use OCP\ICacheFactory;
  27. use OCP\IConfig;
  28. use OCP\IDBConnection;
  29. use OCP\IL10N;
  30. use OCP\IServerContainer;
  31. use OCP\IUserSession;
  32. use OCP\WorkflowEngine\Events\RegisterChecksEvent;
  33. use OCP\WorkflowEngine\Events\RegisterEntitiesEvent;
  34. use OCP\WorkflowEngine\Events\RegisterOperationsEvent;
  35. use OCP\WorkflowEngine\ICheck;
  36. use OCP\WorkflowEngine\IComplexOperation;
  37. use OCP\WorkflowEngine\IEntity;
  38. use OCP\WorkflowEngine\IEntityEvent;
  39. use OCP\WorkflowEngine\IManager;
  40. use OCP\WorkflowEngine\IOperation;
  41. use OCP\WorkflowEngine\IRuleMatcher;
  42. use Psr\Log\LoggerInterface;
  43. class Manager implements IManager {
  44. /** @var array[] */
  45. protected $operations = [];
  46. /** @var array[] */
  47. protected $checks = [];
  48. /** @var IEntity[] */
  49. protected $registeredEntities = [];
  50. /** @var IOperation[] */
  51. protected $registeredOperators = [];
  52. /** @var ICheck[] */
  53. protected $registeredChecks = [];
  54. /** @var CappedMemoryCache<int[]> */
  55. protected CappedMemoryCache $operationsByScope;
  56. public function __construct(
  57. protected IDBConnection $connection,
  58. protected IServerContainer $container,
  59. protected IL10N $l,
  60. protected LoggerInterface $logger,
  61. protected IUserSession $session,
  62. private IEventDispatcher $dispatcher,
  63. private IConfig $config,
  64. private ICacheFactory $cacheFactory,
  65. ) {
  66. $this->operationsByScope = new CappedMemoryCache(64);
  67. }
  68. public function getRuleMatcher(): IRuleMatcher {
  69. return new RuleMatcher(
  70. $this->session,
  71. $this->container,
  72. $this->l,
  73. $this,
  74. $this->container->query(Logger::class)
  75. );
  76. }
  77. public function getAllConfiguredEvents() {
  78. $cache = $this->cacheFactory->createDistributed('flow');
  79. $cached = $cache->get('events');
  80. if ($cached !== null) {
  81. return $cached;
  82. }
  83. $query = $this->connection->getQueryBuilder();
  84. $query->select('class', 'entity')
  85. ->selectAlias($query->expr()->castColumn('events', IQueryBuilder::PARAM_STR), 'events')
  86. ->from('flow_operations')
  87. ->where($query->expr()->neq('events', $query->createNamedParameter('[]'), IQueryBuilder::PARAM_STR))
  88. ->groupBy('class', 'entity', $query->expr()->castColumn('events', IQueryBuilder::PARAM_STR));
  89. $result = $query->executeQuery();
  90. $operations = [];
  91. while ($row = $result->fetch()) {
  92. $eventNames = \json_decode($row['events']);
  93. $operation = $row['class'];
  94. $entity = $row['entity'];
  95. $operations[$operation] = $operations[$row['class']] ?? [];
  96. $operations[$operation][$entity] = $operations[$operation][$entity] ?? [];
  97. $operations[$operation][$entity] = array_unique(array_merge($operations[$operation][$entity], $eventNames ?? []));
  98. }
  99. $result->closeCursor();
  100. $cache->set('events', $operations, 3600);
  101. return $operations;
  102. }
  103. /**
  104. * @param string $operationClass
  105. * @return ScopeContext[]
  106. */
  107. public function getAllConfiguredScopesForOperation(string $operationClass): array {
  108. static $scopesByOperation = [];
  109. if (isset($scopesByOperation[$operationClass])) {
  110. return $scopesByOperation[$operationClass];
  111. }
  112. try {
  113. /** @var IOperation $operation */
  114. $operation = $this->container->query($operationClass);
  115. } catch (QueryException $e) {
  116. return [];
  117. }
  118. $query = $this->connection->getQueryBuilder();
  119. $query->selectDistinct('s.type')
  120. ->addSelect('s.value')
  121. ->from('flow_operations', 'o')
  122. ->leftJoin('o', 'flow_operations_scope', 's', $query->expr()->eq('o.id', 's.operation_id'))
  123. ->where($query->expr()->eq('o.class', $query->createParameter('operationClass')));
  124. $query->setParameters(['operationClass' => $operationClass]);
  125. $result = $query->executeQuery();
  126. $scopesByOperation[$operationClass] = [];
  127. while ($row = $result->fetch()) {
  128. $scope = new ScopeContext($row['type'], $row['value']);
  129. if (!$operation->isAvailableForScope((int)$row['type'])) {
  130. continue;
  131. }
  132. $scopesByOperation[$operationClass][$scope->getHash()] = $scope;
  133. }
  134. return $scopesByOperation[$operationClass];
  135. }
  136. public function getAllOperations(ScopeContext $scopeContext): array {
  137. if (isset($this->operations[$scopeContext->getHash()])) {
  138. return $this->operations[$scopeContext->getHash()];
  139. }
  140. $query = $this->connection->getQueryBuilder();
  141. $query->select('o.*')
  142. ->selectAlias('s.type', 'scope_type')
  143. ->selectAlias('s.value', 'scope_actor_id')
  144. ->from('flow_operations', 'o')
  145. ->leftJoin('o', 'flow_operations_scope', 's', $query->expr()->eq('o.id', 's.operation_id'))
  146. ->where($query->expr()->eq('s.type', $query->createParameter('scope')));
  147. if ($scopeContext->getScope() === IManager::SCOPE_USER) {
  148. $query->andWhere($query->expr()->eq('s.value', $query->createParameter('scopeId')));
  149. }
  150. $query->setParameters(['scope' => $scopeContext->getScope(), 'scopeId' => $scopeContext->getScopeId()]);
  151. $result = $query->executeQuery();
  152. $this->operations[$scopeContext->getHash()] = [];
  153. while ($row = $result->fetch()) {
  154. try {
  155. /** @var IOperation $operation */
  156. $operation = $this->container->query($row['class']);
  157. } catch (QueryException $e) {
  158. continue;
  159. }
  160. if (!$operation->isAvailableForScope((int)$row['scope_type'])) {
  161. continue;
  162. }
  163. if (!isset($this->operations[$scopeContext->getHash()][$row['class']])) {
  164. $this->operations[$scopeContext->getHash()][$row['class']] = [];
  165. }
  166. $this->operations[$scopeContext->getHash()][$row['class']][] = $row;
  167. }
  168. return $this->operations[$scopeContext->getHash()];
  169. }
  170. public function getOperations(string $class, ScopeContext $scopeContext): array {
  171. if (!isset($this->operations[$scopeContext->getHash()])) {
  172. $this->getAllOperations($scopeContext);
  173. }
  174. return $this->operations[$scopeContext->getHash()][$class] ?? [];
  175. }
  176. /**
  177. * @param int $id
  178. * @return array
  179. * @throws \UnexpectedValueException
  180. */
  181. protected function getOperation($id) {
  182. $query = $this->connection->getQueryBuilder();
  183. $query->select('*')
  184. ->from('flow_operations')
  185. ->where($query->expr()->eq('id', $query->createNamedParameter($id)));
  186. $result = $query->executeQuery();
  187. $row = $result->fetch();
  188. $result->closeCursor();
  189. if ($row) {
  190. return $row;
  191. }
  192. throw new \UnexpectedValueException($this->l->t('Operation #%s does not exist', [$id]));
  193. }
  194. protected function insertOperation(
  195. string $class,
  196. string $name,
  197. array $checkIds,
  198. string $operation,
  199. string $entity,
  200. array $events,
  201. ): int {
  202. $query = $this->connection->getQueryBuilder();
  203. $query->insert('flow_operations')
  204. ->values([
  205. 'class' => $query->createNamedParameter($class),
  206. 'name' => $query->createNamedParameter($name),
  207. 'checks' => $query->createNamedParameter(json_encode(array_unique($checkIds))),
  208. 'operation' => $query->createNamedParameter($operation),
  209. 'entity' => $query->createNamedParameter($entity),
  210. 'events' => $query->createNamedParameter(json_encode($events))
  211. ]);
  212. $query->executeStatement();
  213. $this->cacheFactory->createDistributed('flow')->remove('events');
  214. return $query->getLastInsertId();
  215. }
  216. /**
  217. * @param string $class
  218. * @param string $name
  219. * @param array[] $checks
  220. * @param string $operation
  221. * @return array The added operation
  222. * @throws \UnexpectedValueException
  223. * @throws Exception
  224. */
  225. public function addOperation(
  226. string $class,
  227. string $name,
  228. array $checks,
  229. string $operation,
  230. ScopeContext $scope,
  231. string $entity,
  232. array $events,
  233. ) {
  234. $this->validateOperation($class, $name, $checks, $operation, $scope, $entity, $events);
  235. $this->connection->beginTransaction();
  236. try {
  237. $checkIds = [];
  238. foreach ($checks as $check) {
  239. $checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']);
  240. }
  241. $id = $this->insertOperation($class, $name, $checkIds, $operation, $entity, $events);
  242. $this->addScope($id, $scope);
  243. $this->connection->commit();
  244. } catch (Exception $e) {
  245. $this->connection->rollBack();
  246. throw $e;
  247. }
  248. return $this->getOperation($id);
  249. }
  250. protected function canModify(int $id, ScopeContext $scopeContext):bool {
  251. if (isset($this->operationsByScope[$scopeContext->getHash()])) {
  252. return in_array($id, $this->operationsByScope[$scopeContext->getHash()], true);
  253. }
  254. $qb = $this->connection->getQueryBuilder();
  255. $qb = $qb->select('o.id')
  256. ->from('flow_operations', 'o')
  257. ->leftJoin('o', 'flow_operations_scope', 's', $qb->expr()->eq('o.id', 's.operation_id'))
  258. ->where($qb->expr()->eq('s.type', $qb->createParameter('scope')));
  259. if ($scopeContext->getScope() !== IManager::SCOPE_ADMIN) {
  260. $qb->andWhere($qb->expr()->eq('s.value', $qb->createParameter('scopeId')));
  261. }
  262. $qb->setParameters(['scope' => $scopeContext->getScope(), 'scopeId' => $scopeContext->getScopeId()]);
  263. $result = $qb->executeQuery();
  264. $operations = [];
  265. while (($opId = $result->fetchOne()) !== false) {
  266. $operations[] = (int)$opId;
  267. }
  268. $this->operationsByScope[$scopeContext->getHash()] = $operations;
  269. $result->closeCursor();
  270. return in_array($id, $this->operationsByScope[$scopeContext->getHash()], true);
  271. }
  272. /**
  273. * @param int $id
  274. * @param string $name
  275. * @param array[] $checks
  276. * @param string $operation
  277. * @return array The updated operation
  278. * @throws \UnexpectedValueException
  279. * @throws \DomainException
  280. * @throws Exception
  281. */
  282. public function updateOperation(
  283. int $id,
  284. string $name,
  285. array $checks,
  286. string $operation,
  287. ScopeContext $scopeContext,
  288. string $entity,
  289. array $events,
  290. ): array {
  291. if (!$this->canModify($id, $scopeContext)) {
  292. throw new \DomainException('Target operation not within scope');
  293. };
  294. $row = $this->getOperation($id);
  295. $this->validateOperation($row['class'], $name, $checks, $operation, $scopeContext, $entity, $events);
  296. $checkIds = [];
  297. try {
  298. $this->connection->beginTransaction();
  299. foreach ($checks as $check) {
  300. $checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']);
  301. }
  302. $query = $this->connection->getQueryBuilder();
  303. $query->update('flow_operations')
  304. ->set('name', $query->createNamedParameter($name))
  305. ->set('checks', $query->createNamedParameter(json_encode(array_unique($checkIds))))
  306. ->set('operation', $query->createNamedParameter($operation))
  307. ->set('entity', $query->createNamedParameter($entity))
  308. ->set('events', $query->createNamedParameter(json_encode($events)))
  309. ->where($query->expr()->eq('id', $query->createNamedParameter($id)));
  310. $query->execute();
  311. $this->connection->commit();
  312. } catch (Exception $e) {
  313. $this->connection->rollBack();
  314. throw $e;
  315. }
  316. unset($this->operations[$scopeContext->getHash()]);
  317. $this->cacheFactory->createDistributed('flow')->remove('events');
  318. return $this->getOperation($id);
  319. }
  320. /**
  321. * @param int $id
  322. * @return bool
  323. * @throws \UnexpectedValueException
  324. * @throws Exception
  325. * @throws \DomainException
  326. */
  327. public function deleteOperation($id, ScopeContext $scopeContext) {
  328. if (!$this->canModify($id, $scopeContext)) {
  329. throw new \DomainException('Target operation not within scope');
  330. };
  331. $query = $this->connection->getQueryBuilder();
  332. try {
  333. $this->connection->beginTransaction();
  334. $result = (bool)$query->delete('flow_operations')
  335. ->where($query->expr()->eq('id', $query->createNamedParameter($id)))
  336. ->executeStatement();
  337. if ($result) {
  338. $qb = $this->connection->getQueryBuilder();
  339. $result &= (bool)$qb->delete('flow_operations_scope')
  340. ->where($qb->expr()->eq('operation_id', $qb->createNamedParameter($id)))
  341. ->executeStatement();
  342. }
  343. $this->connection->commit();
  344. } catch (Exception $e) {
  345. $this->connection->rollBack();
  346. throw $e;
  347. }
  348. if (isset($this->operations[$scopeContext->getHash()])) {
  349. unset($this->operations[$scopeContext->getHash()]);
  350. }
  351. $this->cacheFactory->createDistributed('flow')->remove('events');
  352. return $result;
  353. }
  354. protected function validateEvents(string $entity, array $events, IOperation $operation) {
  355. try {
  356. /** @var IEntity $instance */
  357. $instance = $this->container->query($entity);
  358. } catch (QueryException $e) {
  359. throw new \UnexpectedValueException($this->l->t('Entity %s does not exist', [$entity]));
  360. }
  361. if (!$instance instanceof IEntity) {
  362. throw new \UnexpectedValueException($this->l->t('Entity %s is invalid', [$entity]));
  363. }
  364. if (empty($events)) {
  365. if (!$operation instanceof IComplexOperation) {
  366. throw new \UnexpectedValueException($this->l->t('No events are chosen.'));
  367. }
  368. return;
  369. }
  370. $availableEvents = [];
  371. foreach ($instance->getEvents() as $event) {
  372. /** @var IEntityEvent $event */
  373. $availableEvents[] = $event->getEventName();
  374. }
  375. $diff = array_diff($events, $availableEvents);
  376. if (!empty($diff)) {
  377. throw new \UnexpectedValueException($this->l->t('Entity %s has no event %s', [$entity, array_shift($diff)]));
  378. }
  379. }
  380. /**
  381. * @param string $class
  382. * @param string $name
  383. * @param array[] $checks
  384. * @param string $operation
  385. * @param ScopeContext $scope
  386. * @param string $entity
  387. * @param array $events
  388. * @throws \UnexpectedValueException
  389. */
  390. public function validateOperation($class, $name, array $checks, $operation, ScopeContext $scope, string $entity, array $events) {
  391. try {
  392. /** @var IOperation $instance */
  393. $instance = $this->container->query($class);
  394. } catch (QueryException $e) {
  395. throw new \UnexpectedValueException($this->l->t('Operation %s does not exist', [$class]));
  396. }
  397. if (!($instance instanceof IOperation)) {
  398. throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]));
  399. }
  400. if (!$instance->isAvailableForScope($scope->getScope())) {
  401. throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]));
  402. }
  403. $this->validateEvents($entity, $events, $instance);
  404. if (count($checks) === 0) {
  405. throw new \UnexpectedValueException($this->l->t('At least one check needs to be provided'));
  406. }
  407. if (strlen((string)$operation) > IManager::MAX_OPERATION_VALUE_BYTES) {
  408. throw new \UnexpectedValueException($this->l->t('The provided operation data is too long'));
  409. }
  410. $instance->validateOperation($name, $checks, $operation);
  411. foreach ($checks as $check) {
  412. if (!is_string($check['class'])) {
  413. throw new \UnexpectedValueException($this->l->t('Invalid check provided'));
  414. }
  415. try {
  416. /** @var ICheck $instance */
  417. $instance = $this->container->query($check['class']);
  418. } catch (QueryException $e) {
  419. throw new \UnexpectedValueException($this->l->t('Check %s does not exist', [$class]));
  420. }
  421. if (!($instance instanceof ICheck)) {
  422. throw new \UnexpectedValueException($this->l->t('Check %s is invalid', [$class]));
  423. }
  424. if (!empty($instance->supportedEntities())
  425. && !in_array($entity, $instance->supportedEntities())
  426. ) {
  427. throw new \UnexpectedValueException($this->l->t('Check %s is not allowed with this entity', [$class]));
  428. }
  429. if (strlen((string)$check['value']) > IManager::MAX_CHECK_VALUE_BYTES) {
  430. throw new \UnexpectedValueException($this->l->t('The provided check value is too long'));
  431. }
  432. $instance->validateCheck($check['operator'], $check['value']);
  433. }
  434. }
  435. /**
  436. * @param int[] $checkIds
  437. * @return array[]
  438. */
  439. public function getChecks(array $checkIds) {
  440. $checkIds = array_map('intval', $checkIds);
  441. $checks = [];
  442. foreach ($checkIds as $i => $checkId) {
  443. if (isset($this->checks[$checkId])) {
  444. $checks[$checkId] = $this->checks[$checkId];
  445. unset($checkIds[$i]);
  446. }
  447. }
  448. if (empty($checkIds)) {
  449. return $checks;
  450. }
  451. $query = $this->connection->getQueryBuilder();
  452. $query->select('*')
  453. ->from('flow_checks')
  454. ->where($query->expr()->in('id', $query->createNamedParameter($checkIds, IQueryBuilder::PARAM_INT_ARRAY)));
  455. $result = $query->executeQuery();
  456. while ($row = $result->fetch()) {
  457. $this->checks[(int)$row['id']] = $row;
  458. $checks[(int)$row['id']] = $row;
  459. }
  460. $result->closeCursor();
  461. $checkIds = array_diff($checkIds, array_keys($checks));
  462. if (!empty($checkIds)) {
  463. $missingCheck = array_pop($checkIds);
  464. throw new \UnexpectedValueException($this->l->t('Check #%s does not exist', $missingCheck));
  465. }
  466. return $checks;
  467. }
  468. /**
  469. * @param string $class
  470. * @param string $operator
  471. * @param string $value
  472. * @return int Check unique ID
  473. */
  474. protected function addCheck($class, $operator, $value) {
  475. $hash = md5($class . '::' . $operator . '::' . $value);
  476. $query = $this->connection->getQueryBuilder();
  477. $query->select('id')
  478. ->from('flow_checks')
  479. ->where($query->expr()->eq('hash', $query->createNamedParameter($hash)));
  480. $result = $query->executeQuery();
  481. if ($row = $result->fetch()) {
  482. $result->closeCursor();
  483. return (int)$row['id'];
  484. }
  485. $query = $this->connection->getQueryBuilder();
  486. $query->insert('flow_checks')
  487. ->values([
  488. 'class' => $query->createNamedParameter($class),
  489. 'operator' => $query->createNamedParameter($operator),
  490. 'value' => $query->createNamedParameter($value),
  491. 'hash' => $query->createNamedParameter($hash),
  492. ]);
  493. $query->executeStatement();
  494. return $query->getLastInsertId();
  495. }
  496. protected function addScope(int $operationId, ScopeContext $scope): void {
  497. $query = $this->connection->getQueryBuilder();
  498. $insertQuery = $query->insert('flow_operations_scope');
  499. $insertQuery->values([
  500. 'operation_id' => $query->createNamedParameter($operationId),
  501. 'type' => $query->createNamedParameter($scope->getScope()),
  502. 'value' => $query->createNamedParameter($scope->getScopeId()),
  503. ]);
  504. $insertQuery->executeStatement();
  505. }
  506. public function formatOperation(array $operation): array {
  507. $checkIds = json_decode($operation['checks'], true);
  508. $checks = $this->getChecks($checkIds);
  509. $operation['checks'] = [];
  510. foreach ($checks as $check) {
  511. // Remove internal values
  512. unset($check['id']);
  513. unset($check['hash']);
  514. $operation['checks'][] = $check;
  515. }
  516. $operation['events'] = json_decode($operation['events'], true) ?? [];
  517. return $operation;
  518. }
  519. /**
  520. * @return IEntity[]
  521. */
  522. public function getEntitiesList(): array {
  523. $this->dispatcher->dispatchTyped(new RegisterEntitiesEvent($this));
  524. return array_values(array_merge($this->getBuildInEntities(), $this->registeredEntities));
  525. }
  526. /**
  527. * @return IOperation[]
  528. */
  529. public function getOperatorList(): array {
  530. $this->dispatcher->dispatchTyped(new RegisterOperationsEvent($this));
  531. return array_merge($this->getBuildInOperators(), $this->registeredOperators);
  532. }
  533. /**
  534. * @return ICheck[]
  535. */
  536. public function getCheckList(): array {
  537. $this->dispatcher->dispatchTyped(new RegisterChecksEvent($this));
  538. return array_merge($this->getBuildInChecks(), $this->registeredChecks);
  539. }
  540. public function registerEntity(IEntity $entity): void {
  541. $this->registeredEntities[get_class($entity)] = $entity;
  542. }
  543. public function registerOperation(IOperation $operator): void {
  544. $this->registeredOperators[get_class($operator)] = $operator;
  545. }
  546. public function registerCheck(ICheck $check): void {
  547. $this->registeredChecks[get_class($check)] = $check;
  548. }
  549. /**
  550. * @return IEntity[]
  551. */
  552. protected function getBuildInEntities(): array {
  553. try {
  554. return [
  555. File::class => $this->container->query(File::class),
  556. ];
  557. } catch (QueryException $e) {
  558. $this->logger->error($e->getMessage(), ['exception' => $e]);
  559. return [];
  560. }
  561. }
  562. /**
  563. * @return IOperation[]
  564. */
  565. protected function getBuildInOperators(): array {
  566. try {
  567. return [
  568. // None yet
  569. ];
  570. } catch (QueryException $e) {
  571. $this->logger->error($e->getMessage(), ['exception' => $e]);
  572. return [];
  573. }
  574. }
  575. /**
  576. * @return ICheck[]
  577. */
  578. protected function getBuildInChecks(): array {
  579. try {
  580. return [
  581. $this->container->query(FileMimeType::class),
  582. $this->container->query(FileName::class),
  583. $this->container->query(FileSize::class),
  584. $this->container->query(FileSystemTags::class),
  585. $this->container->query(RequestRemoteAddress::class),
  586. $this->container->query(RequestTime::class),
  587. $this->container->query(RequestURL::class),
  588. $this->container->query(RequestUserAgent::class),
  589. $this->container->query(UserGroupMembership::class),
  590. ];
  591. } catch (QueryException $e) {
  592. $this->logger->error($e->getMessage(), ['exception' => $e]);
  593. return [];
  594. }
  595. }
  596. public function isUserScopeEnabled(): bool {
  597. return $this->config->getAppValue(Application::APP_ID, 'user_scope_disabled', 'no') === 'no';
  598. }
  599. }