Signed-off-by: Marcel Klehr <mklehr@gmx.net>pull/45094/head
@@ -46,6 +46,7 @@ use OCP\Lock\LockedException; | |||
use OCP\PreConditionNotMetException; | |||
use OCP\TaskProcessing\EShapeType; | |||
use OCP\TaskProcessing\Exception\Exception; | |||
use OCP\TaskProcessing\Exception\UnauthorizedException; | |||
use OCP\TaskProcessing\Exception\ValidationException; | |||
use OCP\TaskProcessing\ShapeDescriptor; | |||
use OCP\TaskProcessing\Task; | |||
@@ -124,10 +125,12 @@ class TaskProcessingApiController extends \OCP\AppFramework\OCSController { | |||
return new DataResponse([ | |||
'task' => $json, | |||
]); | |||
} catch (PreConditionNotMetException) { | |||
} catch (\OCP\TaskProcessing\Exception\PreConditionNotMetException) { | |||
return new DataResponse(['message' => $this->l->t('The given provider is not available')], Http::STATUS_PRECONDITION_FAILED); | |||
} catch (ValidationException $e) { | |||
return new DataResponse(['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST); | |||
} catch (UnauthorizedException $e) { | |||
return new DataResponse(['message' => 'User does not have access to the files mentioned in the task input'], Http::STATUS_UNAUTHORIZED); | |||
} catch (\OCP\TaskProcessing\Exception\Exception $e) { | |||
return new DataResponse(['message' => 'Internal server error'], Http::STATUS_INTERNAL_SERVER_ERROR); | |||
} | |||
@@ -269,13 +272,21 @@ class TaskProcessingApiController extends \OCP\AppFramework\OCSController { | |||
$taskType = $taskTypes[$task->getTaskTypeId()]; | |||
foreach ($taskType['inputShape'] + $taskType['optionalInputShape'] as $key => $descriptor) { | |||
if (in_array(EShapeType::getScalarType($descriptor->getShapeType()), [EShapeType::File, EShapeType::Image, EShapeType::Audio, EShapeType::Video], true)) { | |||
$ids[] = $task->getInput()[$key]; | |||
if (is_array($task->getInput()[$key])) { | |||
$ids += $task->getInput()[$key]; | |||
} else { | |||
$ids[] = $task->getInput()[$key]; | |||
} | |||
} | |||
} | |||
if ($task->getOutput() !== null) { | |||
foreach ($taskType['outputShape'] + $taskType['optionalOutputShape'] as $key => $descriptor) { | |||
if (in_array(EShapeType::getScalarType($descriptor->getShapeType()), [EShapeType::File, EShapeType::Image, EShapeType::Audio, EShapeType::Video], true)) { | |||
$ids[] = $task->getOutput()[$key]; | |||
if (is_array($task->getInput()[$key])) { | |||
$ids += $task->getOutput()[$key]; | |||
} else { | |||
$ids[] = $task->getOutput()[$key]; | |||
} | |||
} | |||
} | |||
} |
@@ -52,6 +52,7 @@ use OCP\TaskProcessing\Events\TaskFailedEvent; | |||
use OCP\TaskProcessing\Events\TaskSuccessfulEvent; | |||
use OCP\TaskProcessing\Exception\NotFoundException; | |||
use OCP\TaskProcessing\Exception\ProcessingException; | |||
use OCP\TaskProcessing\Exception\UnauthorizedException; | |||
use OCP\TaskProcessing\Exception\ValidationException; | |||
use OCP\TaskProcessing\IManager; | |||
use OCP\TaskProcessing\IProvider; | |||
@@ -93,6 +94,7 @@ class Manager implements IManager { | |||
private \OCP\TextProcessing\IManager $textProcessingManager, | |||
private \OCP\TextToImage\IManager $textToImageManager, | |||
private \OCP\SpeechToText\ISpeechToTextManager $speechToTextManager, | |||
private \OCP\Share\IManager $shareManager, | |||
) { | |||
$this->appData = $appDataFactory->get('core'); | |||
} | |||
@@ -553,7 +555,7 @@ class Manager implements IManager { | |||
public function scheduleTask(Task $task): void { | |||
if (!$this->canHandleTask($task)) { | |||
throw new PreConditionNotMetException('No task processing provider is installed that can handle this task type: ' . $task->getTaskTypeId()); | |||
throw new \OCP\TaskProcessing\Exception\PreConditionNotMetException('No task processing provider is installed that can handle this task type: ' . $task->getTaskTypeId()); | |||
} | |||
$taskTypes = $this->getAvailableTaskTypes(); | |||
$inputShape = $taskTypes[$task->getTaskTypeId()]['inputShape']; | |||
@@ -561,6 +563,32 @@ class Manager implements IManager { | |||
// validate input | |||
$this->validateInput($inputShape, $task->getInput()); | |||
$this->validateInput($optionalInputShape, $task->getInput(), true); | |||
// authenticate access to mentioned files | |||
$ids = []; | |||
foreach ($inputShape + $optionalInputShape as $key => $descriptor) { | |||
if (in_array(EShapeType::getScalarType($descriptor->getShapeType()), [EShapeType::File, EShapeType::Image, EShapeType::Audio, EShapeType::Video], true)) { | |||
if (is_array($task->getInput()[$key])) { | |||
$ids += $task->getInput()[$key]; | |||
} else { | |||
$ids[] = $task->getInput()[$key]; | |||
} | |||
} | |||
} | |||
foreach ($ids as $fileId) { | |||
$node = $this->rootFolder->getFirstNodeById($fileId); | |||
if ($node === null) { | |||
$node = $this->rootFolder->getFirstNodeByIdInPath($fileId, '/' . $this->rootFolder->getAppDataDirectoryName() . '/'); | |||
if ($node === null) { | |||
throw new ValidationException('Could not find file ' . $fileId); | |||
} | |||
} | |||
/** @var array{users:array<string,array{node_id:int, node_path: string}>, remote: array<string,array{node_id:int, node_path: string}>, mail: array<string,array{node_id:int, node_path: string}>} $accessList */ | |||
$accessList = $this->shareManager->getAccessList($node, true, true); | |||
$userIds = array_map(fn ($id) => strval($id), array_keys($accessList['users'])); | |||
if (!in_array($task->getUserId(), $userIds)) { | |||
throw new UnauthorizedException('User ' . $task->getUserId() . ' does not have access to file ' . $fileId); | |||
} | |||
} | |||
// remove superfluous keys and set input | |||
$task->setInput($this->removeSuperfluousArrayKeys($task->getInput(), $inputShape, $optionalInputShape)); | |||
$task->setStatus(Task::STATUS_SCHEDULED); |
@@ -0,0 +1,10 @@ | |||
<?php | |||
namespace OCP\TaskProcessing\Exception; | |||
/** | |||
* @since 30.0.0 | |||
*/ | |||
class PreConditionNotMetException extends Exception { | |||
} |
@@ -0,0 +1,10 @@ | |||
<?php | |||
namespace OCP\TaskProcessing\Exception; | |||
/** | |||
* @since 30.0.0 | |||
*/ | |||
class UnauthorizedException extends Exception { | |||
} |
@@ -29,9 +29,10 @@ namespace OCP\TaskProcessing; | |||
use OCP\Files\GenericFileException; | |||
use OCP\Files\NotPermittedException; | |||
use OCP\Lock\LockedException; | |||
use OCP\PreConditionNotMetException; | |||
use OCP\TaskProcessing\Exception\PreConditionNotMetException; | |||
use OCP\TaskProcessing\Exception\Exception; | |||
use OCP\TaskProcessing\Exception\NotFoundException; | |||
use OCP\TaskProcessing\Exception\UnauthorizedException; | |||
use OCP\TaskProcessing\Exception\ValidationException; | |||
/** | |||
@@ -62,6 +63,7 @@ interface IManager { | |||
* @throws PreConditionNotMetException If no or not the requested provider was registered but this method was still called | |||
* @throws ValidationException the given task input didn't pass validation against the task type's input shape and/or the providers optional input shape specs | |||
* @throws Exception storing the task in the database failed | |||
* @throws UnauthorizedException the user scheduling the task does not have access to the files used in the input | |||
* @since 30.0.0 | |||
*/ | |||
public function scheduleTask(Task $task): void; |