You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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