From 86317bbf4dfd5302a1db286f0972ad2263907f3c Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Thu, 2 May 2024 11:15:51 +0200 Subject: [PATCH] refactor: Move validation to EShapeType Signed-off-by: Marcel Klehr --- lib/private/TaskProcessing/Manager.php | 86 ++++------------------ lib/public/TaskProcessing/EShapeType.php | 91 ++++++++++++++++++++++++ lib/public/TaskProcessing/IManager.php | 2 +- 3 files changed, 104 insertions(+), 75 deletions(-) diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index 4cc2119f299..65307d4e435 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -465,43 +465,12 @@ class Manager implements IManager { if ($optional) { continue; } - throw new \OCP\TaskProcessing\Exception\ValidationException('Missing key: "' . $key . '"'); + throw new ValidationException('Missing key: "' . $key . '"'); } - if ($type === EShapeType::Text && !is_string($io[$key])) { - throw new \OCP\TaskProcessing\Exception\ValidationException('Non-text item provided for Text key: "' . $key . '"'); - } - if ($type === EShapeType::ListOfTexts && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_string($item))) > 0)) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-text list item provided for ListOfTexts key: "' . $key . '"'); - } - if ($type === EShapeType::Number && !is_numeric($io[$key])) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-numeric item provided for Number key: "' . $key . '"'); - } - if ($type === EShapeType::ListOfNumbers && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_numeric($item))) > 0)) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-numeric list item provided for ListOfNumbers key: "' . $key . '"'); - } - if ($type === EShapeType::Image && !is_numeric($io[$key])) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-image item provided for Image key: "' . $key . '"'); - } - if ($type === EShapeType::ListOfImages && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_numeric($item))) > 0)) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-image list item provided for ListOfImages key: "' . $key . '"'); - } - if ($type === EShapeType::Audio && !is_numeric($io[$key])) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-audio item provided for Audio key: "' . $key . '"'); - } - if ($type === EShapeType::ListOfAudio && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_numeric($item))) > 0)) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-audio list item provided for ListOfAudio key: "' . $key . '"'); - } - if ($type === EShapeType::Video && !is_numeric($io[$key])) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-video item provided for Video key: "' . $key . '"'); - } - if ($type === EShapeType::ListOfVideo && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_numeric($item))) > 0)) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-video list item provided for ListOfTexts key: "' . $key . '"'); - } - if ($type === EShapeType::File && !is_numeric($io[$key])) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-file item provided for File key: "' . $key . '"'); - } - if ($type === EShapeType::ListOfFiles && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_numeric($item))) > 0)) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-audio list item provided for ListOfFiles key: "' . $key . '"'); + try { + $type->validateInput($io[$key]); + } catch (ValidationException $e) { + throw new ValidationException('Failed to validate input key "' . $key . '": ' . $e->getMessage()); } } } @@ -520,43 +489,12 @@ class Manager implements IManager { if ($optional) { continue; } - throw new \OCP\TaskProcessing\Exception\ValidationException('Missing key: "' . $key . '"'); + throw new ValidationException('Missing key: "' . $key . '"'); } - if ($type === EShapeType::Text && !is_string($io[$key])) { - throw new \OCP\TaskProcessing\Exception\ValidationException('Non-text item provided for Text key: "' . $key . '"'); - } - if ($type === EShapeType::ListOfTexts && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_string($item))) > 0)) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-text list item provided for ListOfTexts key: "' . $key . '"'); - } - if ($type === EShapeType::Number && !is_numeric($io[$key])) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-numeric item provided for Number key: "' . $key . '"'); - } - if ($type === EShapeType::ListOfNumbers && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_numeric($item))) > 0)) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-numeric list item provided for ListOfNumbers key: "' . $key . '"'); - } - if ($type === EShapeType::Image && !is_string($io[$key])) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-image item provided for Image key: "' . $key . '". Expecting base64 encoded image data.'); - } - if ($type === EShapeType::ListOfImages && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_string($item))) > 0)) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-image list item provided for ListOfImages key: "' . $key . '". Expecting base64 encoded image data.'); - } - if ($type === EShapeType::Audio && !is_string($io[$key])) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-audio item provided for Audio key: "' . $key . '". Expecting base64 encoded audio data.'); - } - if ($type === EShapeType::ListOfAudio && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_string($item))) > 0)) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-audio list item provided for ListOfAudio key: "' . $key . '". Expecting base64 encoded audio data.'); - } - if ($type === EShapeType::Video && !is_string($io[$key])) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-video item provided for Video key: "' . $key . '". Expecting base64 encoded video data.'); - } - if ($type === EShapeType::ListOfVideo && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_string($item))) > 0)) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-video list item provided for ListOfTexts key: "' . $key . '". Expecting base64 encoded video data.'); - } - if ($type === EShapeType::File && !is_string($io[$key])) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-file item provided for File key: "' . $key . '". Expecting base64 encoded file data.'); - } - if ($type === EShapeType::ListOfFiles && (!is_array($io[$key]) || count(array_filter($io[$key], fn ($item) => !is_string($item))) > 0)) { - throw new \OCP\TaskProcessing\Exception\ValidationException('None-audio list item provided for ListOfFiles key: "' . $key . '". Expecting base64 encoded image data.'); + try { + $type->validateOutput($io[$key]); + } catch (ValidationException $e) { + throw new ValidationException('Failed to validate output key "' . $key . '": ' . $e->getMessage()); } } } @@ -800,7 +738,7 @@ class Manager implements IManager { if (!isset($input[$key])) { continue; } - if (!in_array(EShapeType::from($type->value % 10), [EShapeType::Image, EShapeType::Audio, EShapeType::Video, EShapeType::File], true)) { + if (!in_array(EShapeType::getScalarType($type), [EShapeType::Image, EShapeType::Audio, EShapeType::Video, EShapeType::File], true)) { $newInputOutput[$key] = $input[$key]; continue; } @@ -857,7 +795,7 @@ class Manager implements IManager { if (!isset($output[$key])) { continue; } - if (!in_array(EShapeType::from($type->value % 10), [EShapeType::Image, EShapeType::Audio, EShapeType::Video, EShapeType::File], true)) { + if (!in_array(EShapeType::getScalarType($type), [EShapeType::Image, EShapeType::Audio, EShapeType::Video, EShapeType::File], true)) { $newOutput[$key] = $output[$key]; continue; } diff --git a/lib/public/TaskProcessing/EShapeType.php b/lib/public/TaskProcessing/EShapeType.php index 3da7391daa1..e2b2837e8e1 100644 --- a/lib/public/TaskProcessing/EShapeType.php +++ b/lib/public/TaskProcessing/EShapeType.php @@ -25,8 +25,11 @@ declare(strict_types=1); namespace OCP\TaskProcessing; +use OCP\TaskProcessing\Exception\ValidationException; + /** * The input and output Shape types + * * @since 30.0.0 */ enum EShapeType: int { @@ -42,4 +45,92 @@ enum EShapeType: int { case ListOfAudio = 13; case ListOfVideo = 14; case ListOfFiles = 15; + + /** + * @param mixed $value + * @return void + * @throws ValidationException + */ + private function validateNonFileType(mixed $value): void { + if ($this === EShapeType::Text && !is_string($value)) { + throw new ValidationException('Non-text item provided for Text slot'); + } + if ($this === EShapeType::ListOfTexts && (!is_array($value) || count(array_filter($value, fn($item) => !is_string($item))) > 0)) { + throw new ValidationException('Non-text list item provided for ListOfTexts slot'); + } + if ($this === EShapeType::Number && !is_numeric($value)) { + throw new ValidationException('Non-numeric item provided for Number slot'); + } + if ($this === EShapeType::ListOfNumbers && (!is_array($value) || count(array_filter($value, fn($item) => !is_numeric($item))) > 0)) { + throw new ValidationException('Non-numeric list item provided for ListOfNumbers slot'); + } + } + + /** + * @param mixed $value + * @return void + * @throws Exception\ValidationException + */ + public function validateInput(mixed $value): void { + $this->validateNonFileType($value); + if ($this === EShapeType::Image && !is_numeric($value)) { + throw new ValidationException('Non-image item provided for Image slot'); + } + if ($this === EShapeType::ListOfImages && (!is_array($value) || count(array_filter($value, fn ($item) => !is_numeric($item))) > 0)) { + throw new ValidationException('Non-image list item provided for ListOfImages slot'); + } + if ($this === EShapeType::Audio && !is_numeric($value)) { + throw new ValidationException('Non-audio item provided for Audio slot'); + } + if ($this === EShapeType::ListOfAudio && (!is_array($value) || count(array_filter($value, fn ($item) => !is_numeric($item))) > 0)) { + throw new ValidationException('Non-audio list item provided for ListOfAudio slot'); + } + if ($this === EShapeType::Video && !is_numeric($value)) { + throw new ValidationException('Non-video item provided for Video slot'); + } + if ($this === EShapeType::ListOfVideo && (!is_array($value) || count(array_filter($value, fn ($item) => !is_numeric($item))) > 0)) { + throw new ValidationException('Non-video list item provided for ListOfTexts slot'); + } + if ($this === EShapeType::File && !is_numeric($value)) { + throw new ValidationException('Non-file item provided for File slot'); + } + if ($this === EShapeType::ListOfFiles && (!is_array($value) || count(array_filter($value, fn ($item) => !is_numeric($item))) > 0)) { + throw new ValidationException('Non-audio list item provided for ListOfFiles slot'); + } + } + + /** + * @throws ValidationException + */ + public function validateOutput(mixed $value) { + $this->validateNonFileType($value); + if ($this === EShapeType::Image && !is_string($value)) { + throw new ValidationException('Non-image item provided for Image slot'); + } + if ($this === EShapeType::ListOfImages && (!is_array($value) || count(array_filter($value, fn ($item) => !is_string($item))) > 0)) { + throw new ValidationException('Non-image list item provided for ListOfImages slot'); + } + if ($this === EShapeType::Audio && !is_string($value)) { + throw new ValidationException('Non-audio item provided for Audio slot'); + } + if ($this === EShapeType::ListOfAudio && (!is_array($value) || count(array_filter($value, fn ($item) => !is_string($item))) > 0)) { + throw new ValidationException('Non-audio list item provided for ListOfAudio slot'); + } + if ($this === EShapeType::Video && !is_string($value)) { + throw new ValidationException('Non-video item provided for Video slot'); + } + if ($this === EShapeType::ListOfVideo && (!is_array($value) || count(array_filter($value, fn ($item) => !is_string($item))) > 0)) { + throw new ValidationException('Non-video list item provided for ListOfTexts slot'); + } + if ($this === EShapeType::File && !is_string($value)) { + throw new ValidationException('Non-file item provided for File slot'); + } + if ($this === EShapeType::ListOfFiles && (!is_array($value) || count(array_filter($value, fn ($item) => !is_string($item))) > 0)) { + throw new ValidationException('Non-audio list item provided for ListOfFiles slot'); + } + } + + public static function getScalarType(EShapeType $type): EShapeType { + return EShapeType::from($type->value % 10); + } } diff --git a/lib/public/TaskProcessing/IManager.php b/lib/public/TaskProcessing/IManager.php index 11b969ec379..6c374d3fb35 100644 --- a/lib/public/TaskProcessing/IManager.php +++ b/lib/public/TaskProcessing/IManager.php @@ -138,7 +138,7 @@ interface IManager { * @param string|null $identifier * @return list * @throws Exception If the query failed - * @throws NotFoundException If the task could not be found + * @throws \JsonException If parsing the task input and output failed * @since 30.0.0 */ public function getUserTasksByApp(?string $userId, string $appId, ?string $identifier = null): array;