From c2a52813e2cfadc43b096927ee9d9db3d9ac5c84 Mon Sep 17 00:00:00 2001
From: Arthur Schiwon <blizzz@arthur-schiwon.de>
Date: Thu, 5 Sep 2019 15:52:11 +0200
Subject: [PATCH] extends ICheck with scope and entity support, provide them as
 initialState

Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
---
 .../lib/Check/AbstractStringCheck.php         | 11 ++++
 .../workflowengine/lib/Check/FileMimeType.php |  5 ++
 apps/workflowengine/lib/Check/FileName.php    |  9 +++
 apps/workflowengine/lib/Check/FileSize.php    |  9 +++
 .../lib/Check/FileSystemTags.php              |  9 +++
 apps/workflowengine/lib/Check/RequestTime.php |  4 ++
 .../lib/Check/RequestUserAgent.php            |  4 ++
 apps/workflowengine/lib/Manager.php           | 56 +++++++++++++++++--
 .../workflowengine/lib/Settings/ASettings.php | 21 +++++++
 lib/public/WorkflowEngine/ICheck.php          | 24 ++++++++
 lib/public/WorkflowEngine/IManager.php        | 17 ++++--
 11 files changed, 160 insertions(+), 9 deletions(-)

diff --git a/apps/workflowengine/lib/Check/AbstractStringCheck.php b/apps/workflowengine/lib/Check/AbstractStringCheck.php
index 0fd728e3496..7a385729e09 100644
--- a/apps/workflowengine/lib/Check/AbstractStringCheck.php
+++ b/apps/workflowengine/lib/Check/AbstractStringCheck.php
@@ -25,6 +25,7 @@ namespace OCA\WorkflowEngine\Check;
 use OCP\Files\Storage\IStorage;
 use OCP\IL10N;
 use OCP\WorkflowEngine\ICheck;
+use OCP\WorkflowEngine\IManager;
 
 abstract class AbstractStringCheck implements ICheck {
 
@@ -101,6 +102,16 @@ abstract class AbstractStringCheck implements ICheck {
 		}
 	}
 
+	public function supportedEntities(): array {
+		// universal by default
+		return [];
+	}
+
+	public function isAvailableForScope(int $scope): bool {
+		// admin only by default
+		return $scope === IManager::SCOPE_ADMIN;
+	}
+
 	/**
 	 * @param string $pattern
 	 * @param string $subject
diff --git a/apps/workflowengine/lib/Check/FileMimeType.php b/apps/workflowengine/lib/Check/FileMimeType.php
index 5f572f5aa9d..6d51992fdd0 100644
--- a/apps/workflowengine/lib/Check/FileMimeType.php
+++ b/apps/workflowengine/lib/Check/FileMimeType.php
@@ -22,6 +22,7 @@
 namespace OCA\WorkflowEngine\Check;
 
 
+use OCA\WorkflowEngine\Entity\File;
 use OCP\Files\IMimeTypeDetector;
 use OCP\Files\Storage\IStorage;
 use OCP\IL10N;
@@ -195,4 +196,8 @@ class FileMimeType extends AbstractStringCheck {
 			strpos($this->request->getPathInfo(), '/webdav/') === 0
 		);
 	}
+
+	public function supportedEntities(): array {
+		return [ File::class ];
+	}
 }
diff --git a/apps/workflowengine/lib/Check/FileName.php b/apps/workflowengine/lib/Check/FileName.php
index c6afbf7afad..d9b63ebfed1 100644
--- a/apps/workflowengine/lib/Check/FileName.php
+++ b/apps/workflowengine/lib/Check/FileName.php
@@ -22,6 +22,7 @@ declare(strict_types=1);
 
 namespace OCA\WorkflowEngine\Check;
 
+use OCA\WorkflowEngine\Entity\File;
 use OCP\Files\Storage\IStorage;
 use OCP\IL10N;
 use OCP\IRequest;
@@ -75,4 +76,12 @@ class FileName extends AbstractStringCheck {
 		}
 		return parent::executeStringCheck($operator, $checkValue, $actualValue);
 	}
+
+	public function supportedEntities(): array {
+		return [ File::class ];
+	}
+
+	public function isAvailableForScope(int $scope): bool {
+		return true;
+	}
 }
diff --git a/apps/workflowengine/lib/Check/FileSize.php b/apps/workflowengine/lib/Check/FileSize.php
index 7e48f0f6038..06a45bdcd41 100644
--- a/apps/workflowengine/lib/Check/FileSize.php
+++ b/apps/workflowengine/lib/Check/FileSize.php
@@ -22,6 +22,7 @@
 namespace OCA\WorkflowEngine\Check;
 
 
+use OCA\WorkflowEngine\Entity\File;
 use OCP\Files\Storage\IStorage;
 use OCP\IL10N;
 use OCP\IRequest;
@@ -116,4 +117,12 @@ class FileSize implements ICheck {
 		$this->size = $size;
 		return $this->size;
 	}
+
+	public function supportedEntities(): array {
+		return [ File::class ];
+	}
+
+	public function isAvailableForScope(int $scope): bool {
+		return true;
+	}
 }
diff --git a/apps/workflowengine/lib/Check/FileSystemTags.php b/apps/workflowengine/lib/Check/FileSystemTags.php
index 4a2b87fd53e..12285c9b33e 100644
--- a/apps/workflowengine/lib/Check/FileSystemTags.php
+++ b/apps/workflowengine/lib/Check/FileSystemTags.php
@@ -22,6 +22,7 @@
 namespace OCA\WorkflowEngine\Check;
 
 
+use OCA\WorkflowEngine\Entity\File;
 use OCP\Files\Cache\ICache;
 use OCP\Files\IHomeStorage;
 use OCP\Files\Storage\IStorage;
@@ -166,4 +167,12 @@ class FileSystemTags implements ICheck {
 		$dir = dirname($path);
 		return $dir === '.' ? '' : $dir;
 	}
+
+	public function supportedEntities(): array {
+		return [ File::class ];
+	}
+
+	public function isAvailableForScope(int $scope): bool {
+		return true;
+	}
 }
diff --git a/apps/workflowengine/lib/Check/RequestTime.php b/apps/workflowengine/lib/Check/RequestTime.php
index 2aa79e77673..0f5322b4759 100644
--- a/apps/workflowengine/lib/Check/RequestTime.php
+++ b/apps/workflowengine/lib/Check/RequestTime.php
@@ -126,4 +126,8 @@ class RequestTime implements ICheck {
 			throw new \UnexpectedValueException($this->l->t('The given end time is invalid'), 4);
 		}
 	}
+
+	public function isAvailableForScope(int $scope): bool {
+		return true;
+	}
 }
diff --git a/apps/workflowengine/lib/Check/RequestUserAgent.php b/apps/workflowengine/lib/Check/RequestUserAgent.php
index 4191a2f3412..2b2e3015557 100644
--- a/apps/workflowengine/lib/Check/RequestUserAgent.php
+++ b/apps/workflowengine/lib/Check/RequestUserAgent.php
@@ -79,4 +79,8 @@ class RequestUserAgent extends AbstractStringCheck {
 	protected function getActualValue() {
 		return (string) $this->request->getHeader('User-Agent');
 	}
+
+	public function isAvailableForScope(int $scope): bool {
+		return true;
+	}
 }
diff --git a/apps/workflowengine/lib/Manager.php b/apps/workflowengine/lib/Manager.php
index 8782fd3efef..3f01b890a52 100644
--- a/apps/workflowengine/lib/Manager.php
+++ b/apps/workflowengine/lib/Manager.php
@@ -21,10 +21,18 @@
 
 namespace OCA\WorkflowEngine;
 
-
 use OC\Files\Storage\Wrapper\Jail;
 use Doctrine\DBAL\DBALException;
 use OC\Cache\CappedMemoryCache;
+use OCA\WorkflowEngine\Check\FileMimeType;
+use OCA\WorkflowEngine\Check\FileName;
+use OCA\WorkflowEngine\Check\FileSize;
+use OCA\WorkflowEngine\Check\FileSystemTags;
+use OCA\WorkflowEngine\Check\RequestRemoteAddress;
+use OCA\WorkflowEngine\Check\RequestTime;
+use OCA\WorkflowEngine\Check\RequestURL;
+use OCA\WorkflowEngine\Check\RequestUserAgent;
+use OCA\WorkflowEngine\Check\UserGroupMembership;
 use OCA\WorkflowEngine\Entity\File;
 use OCA\WorkflowEngine\Helper\ScopeContext;
 use OCP\AppFramework\QueryException;
@@ -80,6 +88,9 @@ class Manager implements IManager, IEntityAware {
 	/** @var IOperation[] */
 	protected $registeredOperators = [];
 
+	/** @var ICheck[] */
+	protected $registeredChecks = [];
+
 	/** @var ILogger */
 	protected $logger;
 
@@ -510,6 +521,12 @@ class Manager implements IManager, IEntityAware {
 				throw new \UnexpectedValueException($this->l->t('Check %s is invalid', [$class]));
 			}
 
+			if (!empty($instance->supportedEntities())
+				&& !in_array(get_class($entity), $instance->supportedEntities())
+			) {
+				throw new \UnexpectedValueException($this->l->t('Check %s is not allowed with this entity', [$class]));
+			}
+
 			$instance->validateCheck($check['operator'], $check['value']);
 		}
 	}
@@ -653,11 +670,14 @@ class Manager implements IManager, IEntityAware {
 	}
 
 	/**
-	 * Listen to 'OCP/WorkflowEngine::registerEntities' at the EventDispatcher
-	 * for registering your entities
-	 *
-	 * @since 18.0.0
+	 * @return ICheck[]
 	 */
+	public function getCheckList(): array {
+		$this->eventDispatcher->dispatch(IManager::EVENT_NAME_REG_CHECK, new GenericEvent($this));
+
+		return array_merge($this->getBuildInChecks(), $this->registeredChecks);
+	}
+
 	public function registerEntity(IEntity $entity): void {
 		$this->registeredEntities[get_class($entity)] = $entity;
 	}
@@ -666,6 +686,10 @@ class Manager implements IManager, IEntityAware {
 		$this->registeredOperators[get_class($operator)] = $operator;
 	}
 
+	public function registerCheck(ICheck $check): void {
+		$this->registeredChecks[get_class($check)] = $check;
+	}
+
 	/**
 	 * @return IEntity[]
 	 */
@@ -693,4 +717,26 @@ class Manager implements IManager, IEntityAware {
 			return [];
 		}
 	}
+
+	/**
+	 * @return IEntity[]
+	 */
+	protected function getBuildInChecks(): array {
+		try {
+			return [
+				$this->container->query(FileMimeType::class),
+				$this->container->query(FileName::class),
+				$this->container->query(FileSize::class),
+				$this->container->query(FileSystemTags::class),
+				$this->container->query(RequestRemoteAddress::class),
+				$this->container->query(RequestTime::class),
+				$this->container->query(RequestURL::class),
+				$this->container->query(RequestUserAgent::class),
+				$this->container->query(UserGroupMembership::class),
+			];
+		} catch (QueryException $e) {
+			$this->logger->logException($e);
+			return [];
+		}
+	}
 }
diff --git a/apps/workflowengine/lib/Settings/ASettings.php b/apps/workflowengine/lib/Settings/ASettings.php
index 1781aaa2f55..ac2ebdb8cac 100644
--- a/apps/workflowengine/lib/Settings/ASettings.php
+++ b/apps/workflowengine/lib/Settings/ASettings.php
@@ -30,6 +30,7 @@ use OCP\AppFramework\Http\TemplateResponse;
 use OCP\IInitialStateService;
 use OCP\IL10N;
 use OCP\Settings\ISettings;
+use OCP\WorkflowEngine\ICheck;
 use OCP\WorkflowEngine\IComplexOperation;
 use OCP\WorkflowEngine\IEntity;
 use OCP\WorkflowEngine\IEntityEvent;
@@ -94,6 +95,13 @@ abstract class ASettings implements ISettings {
 			$this->operatorsToArray($operators)
 		);
 
+		$checks = $this->manager->getCheckList();
+		$this->initialStateService->provideInitialState(
+			Application::APP_ID,
+			'checks',
+			$this->checksToArray($checks)
+		);
+
 		$this->initialStateService->provideInitialState(
 			Application::APP_ID,
 			'scope',
@@ -156,4 +164,17 @@ abstract class ASettings implements ISettings {
 			];
 		}, $operators);
 	}
+
+	private function checksToArray(array $checks) {
+		$checks = array_filter($checks, function(ICheck $check) {
+			return $check->isAvailableForScope($this->getScope());
+		});
+
+		return array_map(function (ICheck $check) {
+			return [
+				'id' => get_class($check),
+				'supportedEntities' => $check->supportedEntities(),
+			];
+		}, $checks);
+	}
 }
diff --git a/lib/public/WorkflowEngine/ICheck.php b/lib/public/WorkflowEngine/ICheck.php
index 1d4fc966460..92ec6f83893 100644
--- a/lib/public/WorkflowEngine/ICheck.php
+++ b/lib/public/WorkflowEngine/ICheck.php
@@ -55,4 +55,28 @@ interface ICheck {
 	 * @since 9.1
 	 */
 	public function validateCheck($operator, $value);
+
+	/**
+	 * returns a list of Entities the checker supports. The values must match
+	 * the class name of the entity.
+	 *
+	 * An empty result means the check is universally available.
+	 *
+	 * @since 18.0.0
+	 */
+	public function supportedEntities(): array;
+
+	/**
+	 * returns whether the operation can be used in the requested scope.
+	 *
+	 * Scope IDs are defined as constants in OCP\WorkflowEngine\IManager. At
+	 * time of writing these are SCOPE_ADMIN and SCOPE_USER.
+	 *
+	 * For possibly unknown future scopes the recommended behaviour is: if
+	 * user scope is permitted, the default behaviour should return `true`,
+	 * otherwise `false`.
+	 *
+	 * @since 18.0.0
+	 */
+	public function isAvailableForScope(int $scope): bool;
 }
diff --git a/lib/public/WorkflowEngine/IManager.php b/lib/public/WorkflowEngine/IManager.php
index 8ef7a3a03e8..8be47d961e7 100644
--- a/lib/public/WorkflowEngine/IManager.php
+++ b/lib/public/WorkflowEngine/IManager.php
@@ -39,6 +39,7 @@ interface IManager {
 
 	const EVENT_NAME_REG_OPERATION = 'OCP\WorkflowEngine::registerOperations';
 	const EVENT_NAME_REG_ENTITY = 'OCP\WorkflowEngine::registerEntities';
+	const EVENT_NAME_REG_CHECK = 'OCP\WorkflowEngine::registerChecks';
 
 	/**
 	 * @param IStorage $storage
@@ -56,18 +57,26 @@ interface IManager {
 	public function getMatchingOperations($class, $returnFirstMatchingOperationOnly = true);
 
 	/**
-	 * Listen to 'OCP/WorkflowEngine::registerEntities' at the EventDispatcher
-	 * for registering your entities
+	 * Listen to `\OCP\WorkflowEngine::EVENT_NAME_REG_ENTITY` at the
+	 * EventDispatcher for registering your entities.
 	 *
 	 * @since 18.0.0
 	 */
 	public function registerEntity(IEntity $entity): void;
 
 	/**
-	 * Listen to 'OCP/WorkflowEngine::registerOperators' at the EventDispatcher
-	 * for registering your operators
+	 * Listen to `\OCP\WorkflowEngine::EVENT_NAME_REG_OPERATION` at the
+	 * EventDispatcher for registering your operators.
 	 *
 	 * @since 18.0.0
 	 */
 	public function registerOperation(IOperation $operator): void;
+
+	/**
+	 * Listen to `\OCP\WorkflowEngine::EVENT_NAME_REG_CHECK` at the
+	 * EventDispatcher for registering your operators.
+	 *
+	 * @since 18.0.0
+	 */
+	public function registerCheck(ICheck $check): void;
 }
-- 
GitLab