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