Passed
Push — master ( c3d000...8f0849 )
by Julius
14:01 queued 13s
created
apps/workflowengine/lib/Manager.php 1 patch
Indentation   +684 added lines, -684 removed lines patch added patch discarded remove patch
@@ -70,688 +70,688 @@
 block discarded – undo
70 70
 use Symfony\Component\EventDispatcher\GenericEvent;
71 71
 
72 72
 class Manager implements IManager {
73
-	/** @var IStorage */
74
-	protected $storage;
75
-
76
-	/** @var string */
77
-	protected $path;
78
-
79
-	/** @var object */
80
-	protected $entity;
81
-
82
-	/** @var array[] */
83
-	protected $operations = [];
84
-
85
-	/** @var array[] */
86
-	protected $checks = [];
87
-
88
-	/** @var IDBConnection */
89
-	protected $connection;
90
-
91
-	/** @var IServerContainer|\OC\Server */
92
-	protected $container;
93
-
94
-	/** @var IL10N */
95
-	protected $l;
96
-
97
-	/** @var LegacyDispatcher */
98
-	protected $legacyEventDispatcher;
99
-
100
-	/** @var IEntity[] */
101
-	protected $registeredEntities = [];
102
-
103
-	/** @var IOperation[] */
104
-	protected $registeredOperators = [];
105
-
106
-	/** @var ICheck[] */
107
-	protected $registeredChecks = [];
108
-
109
-	/** @var ILogger */
110
-	protected $logger;
111
-
112
-	/** @var CappedMemoryCache<int[]> */
113
-	protected CappedMemoryCache $operationsByScope;
114
-
115
-	/** @var IUserSession */
116
-	protected $session;
117
-
118
-	/** @var IEventDispatcher */
119
-	private $dispatcher;
120
-
121
-	/** @var IConfig */
122
-	private $config;
123
-	private ICacheFactory $cacheFactory;
124
-
125
-	public function __construct(
126
-		IDBConnection $connection,
127
-		IServerContainer $container,
128
-		IL10N $l,
129
-		LegacyDispatcher $eventDispatcher,
130
-		ILogger $logger,
131
-		IUserSession $session,
132
-		IEventDispatcher $dispatcher,
133
-		IConfig $config,
134
-		ICacheFactory $cacheFactory,
135
-	) {
136
-		$this->connection = $connection;
137
-		$this->container = $container;
138
-		$this->l = $l;
139
-		$this->legacyEventDispatcher = $eventDispatcher;
140
-		$this->logger = $logger;
141
-		$this->operationsByScope = new CappedMemoryCache(64);
142
-		$this->session = $session;
143
-		$this->dispatcher = $dispatcher;
144
-		$this->config = $config;
145
-		$this->cacheFactory = $cacheFactory;
146
-	}
147
-
148
-	public function getRuleMatcher(): IRuleMatcher {
149
-		return new RuleMatcher(
150
-			$this->session,
151
-			$this->container,
152
-			$this->l,
153
-			$this,
154
-			$this->container->query(Logger::class)
155
-		);
156
-	}
157
-
158
-	public function getAllConfiguredEvents() {
159
-		$cache = $this->cacheFactory->createDistributed('flow');
160
-		$cached = $cache->get('events');
161
-		if ($cached !== null) {
162
-			return $cached;
163
-		}
164
-
165
-		$query = $this->connection->getQueryBuilder();
166
-
167
-		$query->select('class', 'entity')
168
-			->selectAlias($query->expr()->castColumn('events', IQueryBuilder::PARAM_STR), 'events')
169
-			->from('flow_operations')
170
-			->where($query->expr()->neq('events', $query->createNamedParameter('[]'), IQueryBuilder::PARAM_STR))
171
-			->groupBy('class', 'entity', $query->expr()->castColumn('events', IQueryBuilder::PARAM_STR));
172
-
173
-		$result = $query->execute();
174
-		$operations = [];
175
-		while ($row = $result->fetch()) {
176
-			$eventNames = \json_decode($row['events']);
177
-
178
-			$operation = $row['class'];
179
-			$entity = $row['entity'];
180
-
181
-			$operations[$operation] = $operations[$row['class']] ?? [];
182
-			$operations[$operation][$entity] = $operations[$operation][$entity] ?? [];
183
-
184
-			$operations[$operation][$entity] = array_unique(array_merge($operations[$operation][$entity], $eventNames ?? []));
185
-		}
186
-		$result->closeCursor();
187
-
188
-		$cache->set('events', $operations, 3600);
189
-
190
-		return $operations;
191
-	}
192
-
193
-	/**
194
-	 * @param string $operationClass
195
-	 * @return ScopeContext[]
196
-	 */
197
-	public function getAllConfiguredScopesForOperation(string $operationClass): array {
198
-		static $scopesByOperation = [];
199
-		if (isset($scopesByOperation[$operationClass])) {
200
-			return $scopesByOperation[$operationClass];
201
-		}
202
-
203
-		$query = $this->connection->getQueryBuilder();
204
-
205
-		$query->selectDistinct('s.type')
206
-			->addSelect('s.value')
207
-			->from('flow_operations', 'o')
208
-			->leftJoin('o', 'flow_operations_scope', 's', $query->expr()->eq('o.id', 's.operation_id'))
209
-			->where($query->expr()->eq('o.class', $query->createParameter('operationClass')));
210
-
211
-		$query->setParameters(['operationClass' => $operationClass]);
212
-		$result = $query->execute();
213
-
214
-		$scopesByOperation[$operationClass] = [];
215
-		while ($row = $result->fetch()) {
216
-			$scope = new ScopeContext($row['type'], $row['value']);
217
-			$scopesByOperation[$operationClass][$scope->getHash()] = $scope;
218
-		}
219
-
220
-		return $scopesByOperation[$operationClass];
221
-	}
222
-
223
-	public function getAllOperations(ScopeContext $scopeContext): array {
224
-		if (isset($this->operations[$scopeContext->getHash()])) {
225
-			return $this->operations[$scopeContext->getHash()];
226
-		}
227
-
228
-		$query = $this->connection->getQueryBuilder();
229
-
230
-		$query->select('o.*')
231
-			->selectAlias('s.type', 'scope_type')
232
-			->selectAlias('s.value', 'scope_actor_id')
233
-			->from('flow_operations', 'o')
234
-			->leftJoin('o', 'flow_operations_scope', 's', $query->expr()->eq('o.id', 's.operation_id'))
235
-			->where($query->expr()->eq('s.type', $query->createParameter('scope')));
236
-
237
-		if ($scopeContext->getScope() === IManager::SCOPE_USER) {
238
-			$query->andWhere($query->expr()->eq('s.value', $query->createParameter('scopeId')));
239
-		}
240
-
241
-		$query->setParameters(['scope' => $scopeContext->getScope(), 'scopeId' => $scopeContext->getScopeId()]);
242
-		$result = $query->execute();
243
-
244
-		$this->operations[$scopeContext->getHash()] = [];
245
-		while ($row = $result->fetch()) {
246
-			if (!isset($this->operations[$scopeContext->getHash()][$row['class']])) {
247
-				$this->operations[$scopeContext->getHash()][$row['class']] = [];
248
-			}
249
-			$this->operations[$scopeContext->getHash()][$row['class']][] = $row;
250
-		}
251
-
252
-		return $this->operations[$scopeContext->getHash()];
253
-	}
254
-
255
-	public function getOperations(string $class, ScopeContext $scopeContext): array {
256
-		if (!isset($this->operations[$scopeContext->getHash()])) {
257
-			$this->getAllOperations($scopeContext);
258
-		}
259
-		return $this->operations[$scopeContext->getHash()][$class] ?? [];
260
-	}
261
-
262
-	/**
263
-	 * @param int $id
264
-	 * @return array
265
-	 * @throws \UnexpectedValueException
266
-	 */
267
-	protected function getOperation($id) {
268
-		$query = $this->connection->getQueryBuilder();
269
-		$query->select('*')
270
-			->from('flow_operations')
271
-			->where($query->expr()->eq('id', $query->createNamedParameter($id)));
272
-		$result = $query->execute();
273
-		$row = $result->fetch();
274
-		$result->closeCursor();
275
-
276
-		if ($row) {
277
-			return $row;
278
-		}
279
-
280
-		throw new \UnexpectedValueException($this->l->t('Operation #%s does not exist', [$id]));
281
-	}
282
-
283
-	protected function insertOperation(
284
-		string $class,
285
-		string $name,
286
-		array $checkIds,
287
-		string $operation,
288
-		string $entity,
289
-		array $events
290
-	): int {
291
-		$query = $this->connection->getQueryBuilder();
292
-		$query->insert('flow_operations')
293
-			->values([
294
-				'class' => $query->createNamedParameter($class),
295
-				'name' => $query->createNamedParameter($name),
296
-				'checks' => $query->createNamedParameter(json_encode(array_unique($checkIds))),
297
-				'operation' => $query->createNamedParameter($operation),
298
-				'entity' => $query->createNamedParameter($entity),
299
-				'events' => $query->createNamedParameter(json_encode($events))
300
-			]);
301
-		$query->execute();
302
-
303
-		$this->cacheFactory->createDistributed('flow')->remove('events');
304
-
305
-		return $query->getLastInsertId();
306
-	}
307
-
308
-	/**
309
-	 * @param string $class
310
-	 * @param string $name
311
-	 * @param array[] $checks
312
-	 * @param string $operation
313
-	 * @return array The added operation
314
-	 * @throws \UnexpectedValueException
315
-	 * @throw Exception
316
-	 */
317
-	public function addOperation(
318
-		string $class,
319
-		string $name,
320
-		array $checks,
321
-		string $operation,
322
-		ScopeContext $scope,
323
-		string $entity,
324
-		array $events
325
-	) {
326
-		$this->validateOperation($class, $name, $checks, $operation, $entity, $events);
327
-
328
-		$this->connection->beginTransaction();
329
-
330
-		try {
331
-			$checkIds = [];
332
-			foreach ($checks as $check) {
333
-				$checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']);
334
-			}
335
-
336
-			$id = $this->insertOperation($class, $name, $checkIds, $operation, $entity, $events);
337
-			$this->addScope($id, $scope);
338
-
339
-			$this->connection->commit();
340
-		} catch (Exception $e) {
341
-			$this->connection->rollBack();
342
-			throw $e;
343
-		}
344
-
345
-		return $this->getOperation($id);
346
-	}
347
-
348
-	protected function canModify(int $id, ScopeContext $scopeContext):bool {
349
-		if (isset($this->operationsByScope[$scopeContext->getHash()])) {
350
-			return in_array($id, $this->operationsByScope[$scopeContext->getHash()], true);
351
-		}
352
-
353
-		$qb = $this->connection->getQueryBuilder();
354
-		$qb = $qb->select('o.id')
355
-			->from('flow_operations', 'o')
356
-			->leftJoin('o', 'flow_operations_scope', 's', $qb->expr()->eq('o.id', 's.operation_id'))
357
-			->where($qb->expr()->eq('s.type', $qb->createParameter('scope')));
358
-
359
-		if ($scopeContext->getScope() !== IManager::SCOPE_ADMIN) {
360
-			$qb->where($qb->expr()->eq('s.value', $qb->createParameter('scopeId')));
361
-		}
362
-
363
-		$qb->setParameters(['scope' => $scopeContext->getScope(), 'scopeId' => $scopeContext->getScopeId()]);
364
-		$result = $qb->execute();
365
-
366
-		$operations = [];
367
-		while (($opId = $result->fetchOne()) !== false) {
368
-			$operations[] = (int)$opId;
369
-		}
370
-		$this->operationsByScope[$scopeContext->getHash()] = $operations;
371
-		$result->closeCursor();
372
-
373
-		return in_array($id, $this->operationsByScope[$scopeContext->getHash()], true);
374
-	}
375
-
376
-	/**
377
-	 * @param int $id
378
-	 * @param string $name
379
-	 * @param array[] $checks
380
-	 * @param string $operation
381
-	 * @return array The updated operation
382
-	 * @throws \UnexpectedValueException
383
-	 * @throws \DomainException
384
-	 * @throws Exception
385
-	 */
386
-	public function updateOperation(
387
-		int $id,
388
-		string $name,
389
-		array $checks,
390
-		string $operation,
391
-		ScopeContext $scopeContext,
392
-		string $entity,
393
-		array $events
394
-	): array {
395
-		if (!$this->canModify($id, $scopeContext)) {
396
-			throw new \DomainException('Target operation not within scope');
397
-		};
398
-		$row = $this->getOperation($id);
399
-		$this->validateOperation($row['class'], $name, $checks, $operation, $entity, $events);
400
-
401
-		$checkIds = [];
402
-		try {
403
-			$this->connection->beginTransaction();
404
-			foreach ($checks as $check) {
405
-				$checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']);
406
-			}
407
-
408
-			$query = $this->connection->getQueryBuilder();
409
-			$query->update('flow_operations')
410
-				->set('name', $query->createNamedParameter($name))
411
-				->set('checks', $query->createNamedParameter(json_encode(array_unique($checkIds))))
412
-				->set('operation', $query->createNamedParameter($operation))
413
-				->set('entity', $query->createNamedParameter($entity))
414
-				->set('events', $query->createNamedParameter(json_encode($events)))
415
-				->where($query->expr()->eq('id', $query->createNamedParameter($id)));
416
-			$query->execute();
417
-			$this->connection->commit();
418
-		} catch (Exception $e) {
419
-			$this->connection->rollBack();
420
-			throw $e;
421
-		}
422
-		unset($this->operations[$scopeContext->getHash()]);
423
-		$this->cacheFactory->createDistributed('flow')->remove('events');
424
-
425
-		return $this->getOperation($id);
426
-	}
427
-
428
-	/**
429
-	 * @param int $id
430
-	 * @return bool
431
-	 * @throws \UnexpectedValueException
432
-	 * @throws Exception
433
-	 * @throws \DomainException
434
-	 */
435
-	public function deleteOperation($id, ScopeContext $scopeContext) {
436
-		if (!$this->canModify($id, $scopeContext)) {
437
-			throw new \DomainException('Target operation not within scope');
438
-		};
439
-		$query = $this->connection->getQueryBuilder();
440
-		try {
441
-			$this->connection->beginTransaction();
442
-			$result = (bool)$query->delete('flow_operations')
443
-				->where($query->expr()->eq('id', $query->createNamedParameter($id)))
444
-				->execute();
445
-			if ($result) {
446
-				$qb = $this->connection->getQueryBuilder();
447
-				$result &= (bool)$qb->delete('flow_operations_scope')
448
-					->where($qb->expr()->eq('operation_id', $qb->createNamedParameter($id)))
449
-					->execute();
450
-			}
451
-			$this->connection->commit();
452
-		} catch (Exception $e) {
453
-			$this->connection->rollBack();
454
-			throw $e;
455
-		}
456
-
457
-		if (isset($this->operations[$scopeContext->getHash()])) {
458
-			unset($this->operations[$scopeContext->getHash()]);
459
-		}
460
-
461
-		$this->cacheFactory->createDistributed('flow')->remove('events');
462
-
463
-		return $result;
464
-	}
465
-
466
-	protected function validateEvents(string $entity, array $events, IOperation $operation) {
467
-		try {
468
-			/** @var IEntity $instance */
469
-			$instance = $this->container->query($entity);
470
-		} catch (QueryException $e) {
471
-			throw new \UnexpectedValueException($this->l->t('Entity %s does not exist', [$entity]));
472
-		}
473
-
474
-		if (!$instance instanceof IEntity) {
475
-			throw new \UnexpectedValueException($this->l->t('Entity %s is invalid', [$entity]));
476
-		}
477
-
478
-		if (empty($events)) {
479
-			if (!$operation instanceof IComplexOperation) {
480
-				throw new \UnexpectedValueException($this->l->t('No events are chosen.'));
481
-			}
482
-			return;
483
-		}
484
-
485
-		$availableEvents = [];
486
-		foreach ($instance->getEvents() as $event) {
487
-			/** @var IEntityEvent $event */
488
-			$availableEvents[] = $event->getEventName();
489
-		}
490
-
491
-		$diff = array_diff($events, $availableEvents);
492
-		if (!empty($diff)) {
493
-			throw new \UnexpectedValueException($this->l->t('Entity %s has no event %s', [$entity, array_shift($diff)]));
494
-		}
495
-	}
496
-
497
-	/**
498
-	 * @param string $class
499
-	 * @param string $name
500
-	 * @param array[] $checks
501
-	 * @param string $operation
502
-	 * @throws \UnexpectedValueException
503
-	 */
504
-	public function validateOperation($class, $name, array $checks, $operation, string $entity, array $events) {
505
-		try {
506
-			/** @var IOperation $instance */
507
-			$instance = $this->container->query($class);
508
-		} catch (QueryException $e) {
509
-			throw new \UnexpectedValueException($this->l->t('Operation %s does not exist', [$class]));
510
-		}
511
-
512
-		if (!($instance instanceof IOperation)) {
513
-			throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]));
514
-		}
515
-
516
-		$this->validateEvents($entity, $events, $instance);
517
-
518
-		if (count($checks) === 0) {
519
-			throw new \UnexpectedValueException($this->l->t('At least one check needs to be provided'));
520
-		}
521
-
522
-		if (strlen((string)$operation) > IManager::MAX_OPERATION_VALUE_BYTES) {
523
-			throw new \UnexpectedValueException($this->l->t('The provided operation data is too long'));
524
-		}
525
-
526
-		$instance->validateOperation($name, $checks, $operation);
527
-
528
-		foreach ($checks as $check) {
529
-			if (!is_string($check['class'])) {
530
-				throw new \UnexpectedValueException($this->l->t('Invalid check provided'));
531
-			}
532
-
533
-			try {
534
-				/** @var ICheck $instance */
535
-				$instance = $this->container->query($check['class']);
536
-			} catch (QueryException $e) {
537
-				throw new \UnexpectedValueException($this->l->t('Check %s does not exist', [$class]));
538
-			}
539
-
540
-			if (!($instance instanceof ICheck)) {
541
-				throw new \UnexpectedValueException($this->l->t('Check %s is invalid', [$class]));
542
-			}
543
-
544
-			if (!empty($instance->supportedEntities())
545
-				&& !in_array($entity, $instance->supportedEntities())
546
-			) {
547
-				throw new \UnexpectedValueException($this->l->t('Check %s is not allowed with this entity', [$class]));
548
-			}
549
-
550
-			if (strlen((string)$check['value']) > IManager::MAX_CHECK_VALUE_BYTES) {
551
-				throw new \UnexpectedValueException($this->l->t('The provided check value is too long'));
552
-			}
553
-
554
-			$instance->validateCheck($check['operator'], $check['value']);
555
-		}
556
-	}
557
-
558
-	/**
559
-	 * @param int[] $checkIds
560
-	 * @return array[]
561
-	 */
562
-	public function getChecks(array $checkIds) {
563
-		$checkIds = array_map('intval', $checkIds);
564
-
565
-		$checks = [];
566
-		foreach ($checkIds as $i => $checkId) {
567
-			if (isset($this->checks[$checkId])) {
568
-				$checks[$checkId] = $this->checks[$checkId];
569
-				unset($checkIds[$i]);
570
-			}
571
-		}
572
-
573
-		if (empty($checkIds)) {
574
-			return $checks;
575
-		}
576
-
577
-		$query = $this->connection->getQueryBuilder();
578
-		$query->select('*')
579
-			->from('flow_checks')
580
-			->where($query->expr()->in('id', $query->createNamedParameter($checkIds, IQueryBuilder::PARAM_INT_ARRAY)));
581
-		$result = $query->execute();
582
-
583
-		while ($row = $result->fetch()) {
584
-			$this->checks[(int) $row['id']] = $row;
585
-			$checks[(int) $row['id']] = $row;
586
-		}
587
-		$result->closeCursor();
588
-
589
-		$checkIds = array_diff($checkIds, array_keys($checks));
590
-
591
-		if (!empty($checkIds)) {
592
-			$missingCheck = array_pop($checkIds);
593
-			throw new \UnexpectedValueException($this->l->t('Check #%s does not exist', $missingCheck));
594
-		}
595
-
596
-		return $checks;
597
-	}
598
-
599
-	/**
600
-	 * @param string $class
601
-	 * @param string $operator
602
-	 * @param string $value
603
-	 * @return int Check unique ID
604
-	 */
605
-	protected function addCheck($class, $operator, $value) {
606
-		$hash = md5($class . '::' . $operator . '::' . $value);
607
-
608
-		$query = $this->connection->getQueryBuilder();
609
-		$query->select('id')
610
-			->from('flow_checks')
611
-			->where($query->expr()->eq('hash', $query->createNamedParameter($hash)));
612
-		$result = $query->execute();
613
-
614
-		if ($row = $result->fetch()) {
615
-			$result->closeCursor();
616
-			return (int) $row['id'];
617
-		}
618
-
619
-		$query = $this->connection->getQueryBuilder();
620
-		$query->insert('flow_checks')
621
-			->values([
622
-				'class' => $query->createNamedParameter($class),
623
-				'operator' => $query->createNamedParameter($operator),
624
-				'value' => $query->createNamedParameter($value),
625
-				'hash' => $query->createNamedParameter($hash),
626
-			]);
627
-		$query->execute();
628
-
629
-		return $query->getLastInsertId();
630
-	}
631
-
632
-	protected function addScope(int $operationId, ScopeContext $scope): void {
633
-		$query = $this->connection->getQueryBuilder();
634
-
635
-		$insertQuery = $query->insert('flow_operations_scope');
636
-		$insertQuery->values([
637
-			'operation_id' => $query->createNamedParameter($operationId),
638
-			'type' => $query->createNamedParameter($scope->getScope()),
639
-			'value' => $query->createNamedParameter($scope->getScopeId()),
640
-		]);
641
-		$insertQuery->execute();
642
-	}
643
-
644
-	public function formatOperation(array $operation): array {
645
-		$checkIds = json_decode($operation['checks'], true);
646
-		$checks = $this->getChecks($checkIds);
647
-
648
-		$operation['checks'] = [];
649
-		foreach ($checks as $check) {
650
-			// Remove internal values
651
-			unset($check['id']);
652
-			unset($check['hash']);
653
-
654
-			$operation['checks'][] = $check;
655
-		}
656
-		$operation['events'] = json_decode($operation['events'], true) ?? [];
657
-
658
-
659
-		return $operation;
660
-	}
661
-
662
-	/**
663
-	 * @return IEntity[]
664
-	 */
665
-	public function getEntitiesList(): array {
666
-		$this->dispatcher->dispatchTyped(new RegisterEntitiesEvent($this));
667
-		$this->legacyEventDispatcher->dispatch(IManager::EVENT_NAME_REG_ENTITY, new GenericEvent($this));
668
-
669
-		return array_values(array_merge($this->getBuildInEntities(), $this->registeredEntities));
670
-	}
671
-
672
-	/**
673
-	 * @return IOperation[]
674
-	 */
675
-	public function getOperatorList(): array {
676
-		$this->dispatcher->dispatchTyped(new RegisterOperationsEvent($this));
677
-		$this->legacyEventDispatcher->dispatch(IManager::EVENT_NAME_REG_OPERATION, new GenericEvent($this));
678
-
679
-		return array_merge($this->getBuildInOperators(), $this->registeredOperators);
680
-	}
681
-
682
-	/**
683
-	 * @return ICheck[]
684
-	 */
685
-	public function getCheckList(): array {
686
-		$this->dispatcher->dispatchTyped(new RegisterChecksEvent($this));
687
-		$this->legacyEventDispatcher->dispatch(IManager::EVENT_NAME_REG_CHECK, new GenericEvent($this));
688
-
689
-		return array_merge($this->getBuildInChecks(), $this->registeredChecks);
690
-	}
691
-
692
-	public function registerEntity(IEntity $entity): void {
693
-		$this->registeredEntities[get_class($entity)] = $entity;
694
-	}
695
-
696
-	public function registerOperation(IOperation $operator): void {
697
-		$this->registeredOperators[get_class($operator)] = $operator;
698
-	}
699
-
700
-	public function registerCheck(ICheck $check): void {
701
-		$this->registeredChecks[get_class($check)] = $check;
702
-	}
703
-
704
-	/**
705
-	 * @return IEntity[]
706
-	 */
707
-	protected function getBuildInEntities(): array {
708
-		try {
709
-			return [
710
-				File::class => $this->container->query(File::class),
711
-			];
712
-		} catch (QueryException $e) {
713
-			$this->logger->logException($e);
714
-			return [];
715
-		}
716
-	}
717
-
718
-	/**
719
-	 * @return IOperation[]
720
-	 */
721
-	protected function getBuildInOperators(): array {
722
-		try {
723
-			return [
724
-				// None yet
725
-			];
726
-		} catch (QueryException $e) {
727
-			$this->logger->logException($e);
728
-			return [];
729
-		}
730
-	}
731
-
732
-	/**
733
-	 * @return ICheck[]
734
-	 */
735
-	protected function getBuildInChecks(): array {
736
-		try {
737
-			return [
738
-				$this->container->query(FileMimeType::class),
739
-				$this->container->query(FileName::class),
740
-				$this->container->query(FileSize::class),
741
-				$this->container->query(FileSystemTags::class),
742
-				$this->container->query(RequestRemoteAddress::class),
743
-				$this->container->query(RequestTime::class),
744
-				$this->container->query(RequestURL::class),
745
-				$this->container->query(RequestUserAgent::class),
746
-				$this->container->query(UserGroupMembership::class),
747
-			];
748
-		} catch (QueryException $e) {
749
-			$this->logger->logException($e);
750
-			return [];
751
-		}
752
-	}
753
-
754
-	public function isUserScopeEnabled(): bool {
755
-		return $this->config->getAppValue(Application::APP_ID, 'user_scope_disabled', 'no') === 'no';
756
-	}
73
+    /** @var IStorage */
74
+    protected $storage;
75
+
76
+    /** @var string */
77
+    protected $path;
78
+
79
+    /** @var object */
80
+    protected $entity;
81
+
82
+    /** @var array[] */
83
+    protected $operations = [];
84
+
85
+    /** @var array[] */
86
+    protected $checks = [];
87
+
88
+    /** @var IDBConnection */
89
+    protected $connection;
90
+
91
+    /** @var IServerContainer|\OC\Server */
92
+    protected $container;
93
+
94
+    /** @var IL10N */
95
+    protected $l;
96
+
97
+    /** @var LegacyDispatcher */
98
+    protected $legacyEventDispatcher;
99
+
100
+    /** @var IEntity[] */
101
+    protected $registeredEntities = [];
102
+
103
+    /** @var IOperation[] */
104
+    protected $registeredOperators = [];
105
+
106
+    /** @var ICheck[] */
107
+    protected $registeredChecks = [];
108
+
109
+    /** @var ILogger */
110
+    protected $logger;
111
+
112
+    /** @var CappedMemoryCache<int[]> */
113
+    protected CappedMemoryCache $operationsByScope;
114
+
115
+    /** @var IUserSession */
116
+    protected $session;
117
+
118
+    /** @var IEventDispatcher */
119
+    private $dispatcher;
120
+
121
+    /** @var IConfig */
122
+    private $config;
123
+    private ICacheFactory $cacheFactory;
124
+
125
+    public function __construct(
126
+        IDBConnection $connection,
127
+        IServerContainer $container,
128
+        IL10N $l,
129
+        LegacyDispatcher $eventDispatcher,
130
+        ILogger $logger,
131
+        IUserSession $session,
132
+        IEventDispatcher $dispatcher,
133
+        IConfig $config,
134
+        ICacheFactory $cacheFactory,
135
+    ) {
136
+        $this->connection = $connection;
137
+        $this->container = $container;
138
+        $this->l = $l;
139
+        $this->legacyEventDispatcher = $eventDispatcher;
140
+        $this->logger = $logger;
141
+        $this->operationsByScope = new CappedMemoryCache(64);
142
+        $this->session = $session;
143
+        $this->dispatcher = $dispatcher;
144
+        $this->config = $config;
145
+        $this->cacheFactory = $cacheFactory;
146
+    }
147
+
148
+    public function getRuleMatcher(): IRuleMatcher {
149
+        return new RuleMatcher(
150
+            $this->session,
151
+            $this->container,
152
+            $this->l,
153
+            $this,
154
+            $this->container->query(Logger::class)
155
+        );
156
+    }
157
+
158
+    public function getAllConfiguredEvents() {
159
+        $cache = $this->cacheFactory->createDistributed('flow');
160
+        $cached = $cache->get('events');
161
+        if ($cached !== null) {
162
+            return $cached;
163
+        }
164
+
165
+        $query = $this->connection->getQueryBuilder();
166
+
167
+        $query->select('class', 'entity')
168
+            ->selectAlias($query->expr()->castColumn('events', IQueryBuilder::PARAM_STR), 'events')
169
+            ->from('flow_operations')
170
+            ->where($query->expr()->neq('events', $query->createNamedParameter('[]'), IQueryBuilder::PARAM_STR))
171
+            ->groupBy('class', 'entity', $query->expr()->castColumn('events', IQueryBuilder::PARAM_STR));
172
+
173
+        $result = $query->execute();
174
+        $operations = [];
175
+        while ($row = $result->fetch()) {
176
+            $eventNames = \json_decode($row['events']);
177
+
178
+            $operation = $row['class'];
179
+            $entity = $row['entity'];
180
+
181
+            $operations[$operation] = $operations[$row['class']] ?? [];
182
+            $operations[$operation][$entity] = $operations[$operation][$entity] ?? [];
183
+
184
+            $operations[$operation][$entity] = array_unique(array_merge($operations[$operation][$entity], $eventNames ?? []));
185
+        }
186
+        $result->closeCursor();
187
+
188
+        $cache->set('events', $operations, 3600);
189
+
190
+        return $operations;
191
+    }
192
+
193
+    /**
194
+     * @param string $operationClass
195
+     * @return ScopeContext[]
196
+     */
197
+    public function getAllConfiguredScopesForOperation(string $operationClass): array {
198
+        static $scopesByOperation = [];
199
+        if (isset($scopesByOperation[$operationClass])) {
200
+            return $scopesByOperation[$operationClass];
201
+        }
202
+
203
+        $query = $this->connection->getQueryBuilder();
204
+
205
+        $query->selectDistinct('s.type')
206
+            ->addSelect('s.value')
207
+            ->from('flow_operations', 'o')
208
+            ->leftJoin('o', 'flow_operations_scope', 's', $query->expr()->eq('o.id', 's.operation_id'))
209
+            ->where($query->expr()->eq('o.class', $query->createParameter('operationClass')));
210
+
211
+        $query->setParameters(['operationClass' => $operationClass]);
212
+        $result = $query->execute();
213
+
214
+        $scopesByOperation[$operationClass] = [];
215
+        while ($row = $result->fetch()) {
216
+            $scope = new ScopeContext($row['type'], $row['value']);
217
+            $scopesByOperation[$operationClass][$scope->getHash()] = $scope;
218
+        }
219
+
220
+        return $scopesByOperation[$operationClass];
221
+    }
222
+
223
+    public function getAllOperations(ScopeContext $scopeContext): array {
224
+        if (isset($this->operations[$scopeContext->getHash()])) {
225
+            return $this->operations[$scopeContext->getHash()];
226
+        }
227
+
228
+        $query = $this->connection->getQueryBuilder();
229
+
230
+        $query->select('o.*')
231
+            ->selectAlias('s.type', 'scope_type')
232
+            ->selectAlias('s.value', 'scope_actor_id')
233
+            ->from('flow_operations', 'o')
234
+            ->leftJoin('o', 'flow_operations_scope', 's', $query->expr()->eq('o.id', 's.operation_id'))
235
+            ->where($query->expr()->eq('s.type', $query->createParameter('scope')));
236
+
237
+        if ($scopeContext->getScope() === IManager::SCOPE_USER) {
238
+            $query->andWhere($query->expr()->eq('s.value', $query->createParameter('scopeId')));
239
+        }
240
+
241
+        $query->setParameters(['scope' => $scopeContext->getScope(), 'scopeId' => $scopeContext->getScopeId()]);
242
+        $result = $query->execute();
243
+
244
+        $this->operations[$scopeContext->getHash()] = [];
245
+        while ($row = $result->fetch()) {
246
+            if (!isset($this->operations[$scopeContext->getHash()][$row['class']])) {
247
+                $this->operations[$scopeContext->getHash()][$row['class']] = [];
248
+            }
249
+            $this->operations[$scopeContext->getHash()][$row['class']][] = $row;
250
+        }
251
+
252
+        return $this->operations[$scopeContext->getHash()];
253
+    }
254
+
255
+    public function getOperations(string $class, ScopeContext $scopeContext): array {
256
+        if (!isset($this->operations[$scopeContext->getHash()])) {
257
+            $this->getAllOperations($scopeContext);
258
+        }
259
+        return $this->operations[$scopeContext->getHash()][$class] ?? [];
260
+    }
261
+
262
+    /**
263
+     * @param int $id
264
+     * @return array
265
+     * @throws \UnexpectedValueException
266
+     */
267
+    protected function getOperation($id) {
268
+        $query = $this->connection->getQueryBuilder();
269
+        $query->select('*')
270
+            ->from('flow_operations')
271
+            ->where($query->expr()->eq('id', $query->createNamedParameter($id)));
272
+        $result = $query->execute();
273
+        $row = $result->fetch();
274
+        $result->closeCursor();
275
+
276
+        if ($row) {
277
+            return $row;
278
+        }
279
+
280
+        throw new \UnexpectedValueException($this->l->t('Operation #%s does not exist', [$id]));
281
+    }
282
+
283
+    protected function insertOperation(
284
+        string $class,
285
+        string $name,
286
+        array $checkIds,
287
+        string $operation,
288
+        string $entity,
289
+        array $events
290
+    ): int {
291
+        $query = $this->connection->getQueryBuilder();
292
+        $query->insert('flow_operations')
293
+            ->values([
294
+                'class' => $query->createNamedParameter($class),
295
+                'name' => $query->createNamedParameter($name),
296
+                'checks' => $query->createNamedParameter(json_encode(array_unique($checkIds))),
297
+                'operation' => $query->createNamedParameter($operation),
298
+                'entity' => $query->createNamedParameter($entity),
299
+                'events' => $query->createNamedParameter(json_encode($events))
300
+            ]);
301
+        $query->execute();
302
+
303
+        $this->cacheFactory->createDistributed('flow')->remove('events');
304
+
305
+        return $query->getLastInsertId();
306
+    }
307
+
308
+    /**
309
+     * @param string $class
310
+     * @param string $name
311
+     * @param array[] $checks
312
+     * @param string $operation
313
+     * @return array The added operation
314
+     * @throws \UnexpectedValueException
315
+     * @throw Exception
316
+     */
317
+    public function addOperation(
318
+        string $class,
319
+        string $name,
320
+        array $checks,
321
+        string $operation,
322
+        ScopeContext $scope,
323
+        string $entity,
324
+        array $events
325
+    ) {
326
+        $this->validateOperation($class, $name, $checks, $operation, $entity, $events);
327
+
328
+        $this->connection->beginTransaction();
329
+
330
+        try {
331
+            $checkIds = [];
332
+            foreach ($checks as $check) {
333
+                $checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']);
334
+            }
335
+
336
+            $id = $this->insertOperation($class, $name, $checkIds, $operation, $entity, $events);
337
+            $this->addScope($id, $scope);
338
+
339
+            $this->connection->commit();
340
+        } catch (Exception $e) {
341
+            $this->connection->rollBack();
342
+            throw $e;
343
+        }
344
+
345
+        return $this->getOperation($id);
346
+    }
347
+
348
+    protected function canModify(int $id, ScopeContext $scopeContext):bool {
349
+        if (isset($this->operationsByScope[$scopeContext->getHash()])) {
350
+            return in_array($id, $this->operationsByScope[$scopeContext->getHash()], true);
351
+        }
352
+
353
+        $qb = $this->connection->getQueryBuilder();
354
+        $qb = $qb->select('o.id')
355
+            ->from('flow_operations', 'o')
356
+            ->leftJoin('o', 'flow_operations_scope', 's', $qb->expr()->eq('o.id', 's.operation_id'))
357
+            ->where($qb->expr()->eq('s.type', $qb->createParameter('scope')));
358
+
359
+        if ($scopeContext->getScope() !== IManager::SCOPE_ADMIN) {
360
+            $qb->where($qb->expr()->eq('s.value', $qb->createParameter('scopeId')));
361
+        }
362
+
363
+        $qb->setParameters(['scope' => $scopeContext->getScope(), 'scopeId' => $scopeContext->getScopeId()]);
364
+        $result = $qb->execute();
365
+
366
+        $operations = [];
367
+        while (($opId = $result->fetchOne()) !== false) {
368
+            $operations[] = (int)$opId;
369
+        }
370
+        $this->operationsByScope[$scopeContext->getHash()] = $operations;
371
+        $result->closeCursor();
372
+
373
+        return in_array($id, $this->operationsByScope[$scopeContext->getHash()], true);
374
+    }
375
+
376
+    /**
377
+     * @param int $id
378
+     * @param string $name
379
+     * @param array[] $checks
380
+     * @param string $operation
381
+     * @return array The updated operation
382
+     * @throws \UnexpectedValueException
383
+     * @throws \DomainException
384
+     * @throws Exception
385
+     */
386
+    public function updateOperation(
387
+        int $id,
388
+        string $name,
389
+        array $checks,
390
+        string $operation,
391
+        ScopeContext $scopeContext,
392
+        string $entity,
393
+        array $events
394
+    ): array {
395
+        if (!$this->canModify($id, $scopeContext)) {
396
+            throw new \DomainException('Target operation not within scope');
397
+        };
398
+        $row = $this->getOperation($id);
399
+        $this->validateOperation($row['class'], $name, $checks, $operation, $entity, $events);
400
+
401
+        $checkIds = [];
402
+        try {
403
+            $this->connection->beginTransaction();
404
+            foreach ($checks as $check) {
405
+                $checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']);
406
+            }
407
+
408
+            $query = $this->connection->getQueryBuilder();
409
+            $query->update('flow_operations')
410
+                ->set('name', $query->createNamedParameter($name))
411
+                ->set('checks', $query->createNamedParameter(json_encode(array_unique($checkIds))))
412
+                ->set('operation', $query->createNamedParameter($operation))
413
+                ->set('entity', $query->createNamedParameter($entity))
414
+                ->set('events', $query->createNamedParameter(json_encode($events)))
415
+                ->where($query->expr()->eq('id', $query->createNamedParameter($id)));
416
+            $query->execute();
417
+            $this->connection->commit();
418
+        } catch (Exception $e) {
419
+            $this->connection->rollBack();
420
+            throw $e;
421
+        }
422
+        unset($this->operations[$scopeContext->getHash()]);
423
+        $this->cacheFactory->createDistributed('flow')->remove('events');
424
+
425
+        return $this->getOperation($id);
426
+    }
427
+
428
+    /**
429
+     * @param int $id
430
+     * @return bool
431
+     * @throws \UnexpectedValueException
432
+     * @throws Exception
433
+     * @throws \DomainException
434
+     */
435
+    public function deleteOperation($id, ScopeContext $scopeContext) {
436
+        if (!$this->canModify($id, $scopeContext)) {
437
+            throw new \DomainException('Target operation not within scope');
438
+        };
439
+        $query = $this->connection->getQueryBuilder();
440
+        try {
441
+            $this->connection->beginTransaction();
442
+            $result = (bool)$query->delete('flow_operations')
443
+                ->where($query->expr()->eq('id', $query->createNamedParameter($id)))
444
+                ->execute();
445
+            if ($result) {
446
+                $qb = $this->connection->getQueryBuilder();
447
+                $result &= (bool)$qb->delete('flow_operations_scope')
448
+                    ->where($qb->expr()->eq('operation_id', $qb->createNamedParameter($id)))
449
+                    ->execute();
450
+            }
451
+            $this->connection->commit();
452
+        } catch (Exception $e) {
453
+            $this->connection->rollBack();
454
+            throw $e;
455
+        }
456
+
457
+        if (isset($this->operations[$scopeContext->getHash()])) {
458
+            unset($this->operations[$scopeContext->getHash()]);
459
+        }
460
+
461
+        $this->cacheFactory->createDistributed('flow')->remove('events');
462
+
463
+        return $result;
464
+    }
465
+
466
+    protected function validateEvents(string $entity, array $events, IOperation $operation) {
467
+        try {
468
+            /** @var IEntity $instance */
469
+            $instance = $this->container->query($entity);
470
+        } catch (QueryException $e) {
471
+            throw new \UnexpectedValueException($this->l->t('Entity %s does not exist', [$entity]));
472
+        }
473
+
474
+        if (!$instance instanceof IEntity) {
475
+            throw new \UnexpectedValueException($this->l->t('Entity %s is invalid', [$entity]));
476
+        }
477
+
478
+        if (empty($events)) {
479
+            if (!$operation instanceof IComplexOperation) {
480
+                throw new \UnexpectedValueException($this->l->t('No events are chosen.'));
481
+            }
482
+            return;
483
+        }
484
+
485
+        $availableEvents = [];
486
+        foreach ($instance->getEvents() as $event) {
487
+            /** @var IEntityEvent $event */
488
+            $availableEvents[] = $event->getEventName();
489
+        }
490
+
491
+        $diff = array_diff($events, $availableEvents);
492
+        if (!empty($diff)) {
493
+            throw new \UnexpectedValueException($this->l->t('Entity %s has no event %s', [$entity, array_shift($diff)]));
494
+        }
495
+    }
496
+
497
+    /**
498
+     * @param string $class
499
+     * @param string $name
500
+     * @param array[] $checks
501
+     * @param string $operation
502
+     * @throws \UnexpectedValueException
503
+     */
504
+    public function validateOperation($class, $name, array $checks, $operation, string $entity, array $events) {
505
+        try {
506
+            /** @var IOperation $instance */
507
+            $instance = $this->container->query($class);
508
+        } catch (QueryException $e) {
509
+            throw new \UnexpectedValueException($this->l->t('Operation %s does not exist', [$class]));
510
+        }
511
+
512
+        if (!($instance instanceof IOperation)) {
513
+            throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]));
514
+        }
515
+
516
+        $this->validateEvents($entity, $events, $instance);
517
+
518
+        if (count($checks) === 0) {
519
+            throw new \UnexpectedValueException($this->l->t('At least one check needs to be provided'));
520
+        }
521
+
522
+        if (strlen((string)$operation) > IManager::MAX_OPERATION_VALUE_BYTES) {
523
+            throw new \UnexpectedValueException($this->l->t('The provided operation data is too long'));
524
+        }
525
+
526
+        $instance->validateOperation($name, $checks, $operation);
527
+
528
+        foreach ($checks as $check) {
529
+            if (!is_string($check['class'])) {
530
+                throw new \UnexpectedValueException($this->l->t('Invalid check provided'));
531
+            }
532
+
533
+            try {
534
+                /** @var ICheck $instance */
535
+                $instance = $this->container->query($check['class']);
536
+            } catch (QueryException $e) {
537
+                throw new \UnexpectedValueException($this->l->t('Check %s does not exist', [$class]));
538
+            }
539
+
540
+            if (!($instance instanceof ICheck)) {
541
+                throw new \UnexpectedValueException($this->l->t('Check %s is invalid', [$class]));
542
+            }
543
+
544
+            if (!empty($instance->supportedEntities())
545
+                && !in_array($entity, $instance->supportedEntities())
546
+            ) {
547
+                throw new \UnexpectedValueException($this->l->t('Check %s is not allowed with this entity', [$class]));
548
+            }
549
+
550
+            if (strlen((string)$check['value']) > IManager::MAX_CHECK_VALUE_BYTES) {
551
+                throw new \UnexpectedValueException($this->l->t('The provided check value is too long'));
552
+            }
553
+
554
+            $instance->validateCheck($check['operator'], $check['value']);
555
+        }
556
+    }
557
+
558
+    /**
559
+     * @param int[] $checkIds
560
+     * @return array[]
561
+     */
562
+    public function getChecks(array $checkIds) {
563
+        $checkIds = array_map('intval', $checkIds);
564
+
565
+        $checks = [];
566
+        foreach ($checkIds as $i => $checkId) {
567
+            if (isset($this->checks[$checkId])) {
568
+                $checks[$checkId] = $this->checks[$checkId];
569
+                unset($checkIds[$i]);
570
+            }
571
+        }
572
+
573
+        if (empty($checkIds)) {
574
+            return $checks;
575
+        }
576
+
577
+        $query = $this->connection->getQueryBuilder();
578
+        $query->select('*')
579
+            ->from('flow_checks')
580
+            ->where($query->expr()->in('id', $query->createNamedParameter($checkIds, IQueryBuilder::PARAM_INT_ARRAY)));
581
+        $result = $query->execute();
582
+
583
+        while ($row = $result->fetch()) {
584
+            $this->checks[(int) $row['id']] = $row;
585
+            $checks[(int) $row['id']] = $row;
586
+        }
587
+        $result->closeCursor();
588
+
589
+        $checkIds = array_diff($checkIds, array_keys($checks));
590
+
591
+        if (!empty($checkIds)) {
592
+            $missingCheck = array_pop($checkIds);
593
+            throw new \UnexpectedValueException($this->l->t('Check #%s does not exist', $missingCheck));
594
+        }
595
+
596
+        return $checks;
597
+    }
598
+
599
+    /**
600
+     * @param string $class
601
+     * @param string $operator
602
+     * @param string $value
603
+     * @return int Check unique ID
604
+     */
605
+    protected function addCheck($class, $operator, $value) {
606
+        $hash = md5($class . '::' . $operator . '::' . $value);
607
+
608
+        $query = $this->connection->getQueryBuilder();
609
+        $query->select('id')
610
+            ->from('flow_checks')
611
+            ->where($query->expr()->eq('hash', $query->createNamedParameter($hash)));
612
+        $result = $query->execute();
613
+
614
+        if ($row = $result->fetch()) {
615
+            $result->closeCursor();
616
+            return (int) $row['id'];
617
+        }
618
+
619
+        $query = $this->connection->getQueryBuilder();
620
+        $query->insert('flow_checks')
621
+            ->values([
622
+                'class' => $query->createNamedParameter($class),
623
+                'operator' => $query->createNamedParameter($operator),
624
+                'value' => $query->createNamedParameter($value),
625
+                'hash' => $query->createNamedParameter($hash),
626
+            ]);
627
+        $query->execute();
628
+
629
+        return $query->getLastInsertId();
630
+    }
631
+
632
+    protected function addScope(int $operationId, ScopeContext $scope): void {
633
+        $query = $this->connection->getQueryBuilder();
634
+
635
+        $insertQuery = $query->insert('flow_operations_scope');
636
+        $insertQuery->values([
637
+            'operation_id' => $query->createNamedParameter($operationId),
638
+            'type' => $query->createNamedParameter($scope->getScope()),
639
+            'value' => $query->createNamedParameter($scope->getScopeId()),
640
+        ]);
641
+        $insertQuery->execute();
642
+    }
643
+
644
+    public function formatOperation(array $operation): array {
645
+        $checkIds = json_decode($operation['checks'], true);
646
+        $checks = $this->getChecks($checkIds);
647
+
648
+        $operation['checks'] = [];
649
+        foreach ($checks as $check) {
650
+            // Remove internal values
651
+            unset($check['id']);
652
+            unset($check['hash']);
653
+
654
+            $operation['checks'][] = $check;
655
+        }
656
+        $operation['events'] = json_decode($operation['events'], true) ?? [];
657
+
658
+
659
+        return $operation;
660
+    }
661
+
662
+    /**
663
+     * @return IEntity[]
664
+     */
665
+    public function getEntitiesList(): array {
666
+        $this->dispatcher->dispatchTyped(new RegisterEntitiesEvent($this));
667
+        $this->legacyEventDispatcher->dispatch(IManager::EVENT_NAME_REG_ENTITY, new GenericEvent($this));
668
+
669
+        return array_values(array_merge($this->getBuildInEntities(), $this->registeredEntities));
670
+    }
671
+
672
+    /**
673
+     * @return IOperation[]
674
+     */
675
+    public function getOperatorList(): array {
676
+        $this->dispatcher->dispatchTyped(new RegisterOperationsEvent($this));
677
+        $this->legacyEventDispatcher->dispatch(IManager::EVENT_NAME_REG_OPERATION, new GenericEvent($this));
678
+
679
+        return array_merge($this->getBuildInOperators(), $this->registeredOperators);
680
+    }
681
+
682
+    /**
683
+     * @return ICheck[]
684
+     */
685
+    public function getCheckList(): array {
686
+        $this->dispatcher->dispatchTyped(new RegisterChecksEvent($this));
687
+        $this->legacyEventDispatcher->dispatch(IManager::EVENT_NAME_REG_CHECK, new GenericEvent($this));
688
+
689
+        return array_merge($this->getBuildInChecks(), $this->registeredChecks);
690
+    }
691
+
692
+    public function registerEntity(IEntity $entity): void {
693
+        $this->registeredEntities[get_class($entity)] = $entity;
694
+    }
695
+
696
+    public function registerOperation(IOperation $operator): void {
697
+        $this->registeredOperators[get_class($operator)] = $operator;
698
+    }
699
+
700
+    public function registerCheck(ICheck $check): void {
701
+        $this->registeredChecks[get_class($check)] = $check;
702
+    }
703
+
704
+    /**
705
+     * @return IEntity[]
706
+     */
707
+    protected function getBuildInEntities(): array {
708
+        try {
709
+            return [
710
+                File::class => $this->container->query(File::class),
711
+            ];
712
+        } catch (QueryException $e) {
713
+            $this->logger->logException($e);
714
+            return [];
715
+        }
716
+    }
717
+
718
+    /**
719
+     * @return IOperation[]
720
+     */
721
+    protected function getBuildInOperators(): array {
722
+        try {
723
+            return [
724
+                // None yet
725
+            ];
726
+        } catch (QueryException $e) {
727
+            $this->logger->logException($e);
728
+            return [];
729
+        }
730
+    }
731
+
732
+    /**
733
+     * @return ICheck[]
734
+     */
735
+    protected function getBuildInChecks(): array {
736
+        try {
737
+            return [
738
+                $this->container->query(FileMimeType::class),
739
+                $this->container->query(FileName::class),
740
+                $this->container->query(FileSize::class),
741
+                $this->container->query(FileSystemTags::class),
742
+                $this->container->query(RequestRemoteAddress::class),
743
+                $this->container->query(RequestTime::class),
744
+                $this->container->query(RequestURL::class),
745
+                $this->container->query(RequestUserAgent::class),
746
+                $this->container->query(UserGroupMembership::class),
747
+            ];
748
+        } catch (QueryException $e) {
749
+            $this->logger->logException($e);
750
+            return [];
751
+        }
752
+    }
753
+
754
+    public function isUserScopeEnabled(): bool {
755
+        return $this->config->getAppValue(Application::APP_ID, 'user_scope_disabled', 'no') === 'no';
756
+    }
757 757
 }
Please login to merge, or discard this patch.