From b4f7fe2cb60ad412a4ce8a4fa05b74fbd5b6ff91 Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Wed, 26 Nov 2025 15:48:30 +0100 Subject: [PATCH] feat(taskprocessing): add a boolean 'includeWatermark' to taskprocessing tasks and pass it to ISynchronousWatermarkingProvider::process Signed-off-by: Julien Veyssier --- .../TaskProcessingApiController.php | 4 +- .../Version33000Date20251126152410.php | 46 +++++++++++++++++++ core/ResponseDefinitions.php | 1 + core/openapi-ex_app.json | 6 ++- core/openapi-full.json | 11 ++++- core/openapi.json | 11 ++++- lib/composer/composer/autoload_classmap.php | 2 + lib/composer/composer/autoload_static.php | 2 + lib/private/TaskProcessing/Db/Task.php | 10 +++- lib/private/TaskProcessing/Manager.php | 7 ++- .../ISynchronousWatermarkingProvider.php | 35 ++++++++++++++ lib/public/TaskProcessing/Task.php | 21 ++++++++- openapi.json | 11 ++++- version.php | 2 +- 14 files changed, 159 insertions(+), 10 deletions(-) create mode 100644 core/Migrations/Version33000Date20251126152410.php create mode 100644 lib/public/TaskProcessing/ISynchronousWatermarkingProvider.php diff --git a/core/Controller/TaskProcessingApiController.php b/core/Controller/TaskProcessingApiController.php index 778483073de..955b357aa1b 100644 --- a/core/Controller/TaskProcessingApiController.php +++ b/core/Controller/TaskProcessingApiController.php @@ -148,6 +148,7 @@ class TaskProcessingApiController extends OCSController { * @param string $customId An arbitrary identifier for the task * @param string|null $webhookUri URI to be requested when the task finishes * @param string|null $webhookMethod Method used for the webhook request (HTTP:GET, HTTP:POST, HTTP:PUT, HTTP:DELETE or AppAPI:APP_ID:GET, AppAPI:APP_ID:POST...) + * @param bool $includeWatermark Whether to include a watermark in the output file or not * @return DataResponse|DataResponse * * 200: Task scheduled successfully @@ -160,11 +161,12 @@ class TaskProcessingApiController extends OCSController { #[ApiRoute(verb: 'POST', url: '/schedule', root: '/taskprocessing')] public function schedule( array $input, string $type, string $appId, string $customId = '', - ?string $webhookUri = null, ?string $webhookMethod = null, + ?string $webhookUri = null, ?string $webhookMethod = null, bool $includeWatermark = true, ): DataResponse { $task = new Task($type, $input, $appId, $this->userId, $customId); $task->setWebhookUri($webhookUri); $task->setWebhookMethod($webhookMethod); + $task->setIncludeWatermark($includeWatermark); try { $this->taskProcessingManager->scheduleTask($task); diff --git a/core/Migrations/Version33000Date20251126152410.php b/core/Migrations/Version33000Date20251126152410.php new file mode 100644 index 00000000000..96d590409db --- /dev/null +++ b/core/Migrations/Version33000Date20251126152410.php @@ -0,0 +1,46 @@ +hasTable('taskprocessing_tasks')) { + $table = $schema->getTable('taskprocessing_tasks'); + if (!$table->hasColumn('include_watermark')) { + $table->addColumn('include_watermark', Types::SMALLINT, [ + 'notnull' => true, + 'default' => 1, + 'unsigned' => true, + ]); + return $schema; + } + } + + return null; + } +} diff --git a/core/ResponseDefinitions.php b/core/ResponseDefinitions.php index a52b8a0bc0b..82421a58039 100644 --- a/core/ResponseDefinitions.php +++ b/core/ResponseDefinitions.php @@ -211,6 +211,7 @@ namespace OC\Core; * startedAt: ?int, * endedAt: ?int, * allowCleanup: bool, + * includeWatermark: bool, * } * * @psalm-type CoreProfileAction = array{ diff --git a/core/openapi-ex_app.json b/core/openapi-ex_app.json index 5269e76c9f3..647c9fcd5d9 100644 --- a/core/openapi-ex_app.json +++ b/core/openapi-ex_app.json @@ -165,7 +165,8 @@ "scheduledAt", "startedAt", "endedAt", - "allowCleanup" + "allowCleanup", + "includeWatermark" ], "properties": { "id": { @@ -239,6 +240,9 @@ }, "allowCleanup": { "type": "boolean" + }, + "includeWatermark": { + "type": "boolean" } } } diff --git a/core/openapi-full.json b/core/openapi-full.json index f7bb992043f..2116be274a8 100644 --- a/core/openapi-full.json +++ b/core/openapi-full.json @@ -659,7 +659,8 @@ "scheduledAt", "startedAt", "endedAt", - "allowCleanup" + "allowCleanup", + "includeWatermark" ], "properties": { "id": { @@ -733,6 +734,9 @@ }, "allowCleanup": { "type": "boolean" + }, + "includeWatermark": { + "type": "boolean" } } }, @@ -4944,6 +4948,11 @@ "nullable": true, "default": null, "description": "Method used for the webhook request (HTTP:GET, HTTP:POST, HTTP:PUT, HTTP:DELETE or AppAPI:APP_ID:GET, AppAPI:APP_ID:POST...)" + }, + "includeWatermark": { + "type": "boolean", + "default": true, + "description": "Whether to include a watermark in the output file or not" } } } diff --git a/core/openapi.json b/core/openapi.json index 5980dd07d7f..8b2b725d576 100644 --- a/core/openapi.json +++ b/core/openapi.json @@ -659,7 +659,8 @@ "scheduledAt", "startedAt", "endedAt", - "allowCleanup" + "allowCleanup", + "includeWatermark" ], "properties": { "id": { @@ -733,6 +734,9 @@ }, "allowCleanup": { "type": "boolean" + }, + "includeWatermark": { + "type": "boolean" } } }, @@ -4944,6 +4948,11 @@ "nullable": true, "default": null, "description": "Method used for the webhook request (HTTP:GET, HTTP:POST, HTTP:PUT, HTTP:DELETE or AppAPI:APP_ID:GET, AppAPI:APP_ID:POST...)" + }, + "includeWatermark": { + "type": "boolean", + "default": true, + "description": "Whether to include a watermark in the output file or not" } } } diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 0269912e864..c0c3111f5fa 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -875,6 +875,7 @@ return array( 'OCP\\TaskProcessing\\IManager' => $baseDir . '/lib/public/TaskProcessing/IManager.php', 'OCP\\TaskProcessing\\IProvider' => $baseDir . '/lib/public/TaskProcessing/IProvider.php', 'OCP\\TaskProcessing\\ISynchronousProvider' => $baseDir . '/lib/public/TaskProcessing/ISynchronousProvider.php', + 'OCP\\TaskProcessing\\ISynchronousWatermarkingProvider' => $baseDir . '/lib/public/TaskProcessing/ISynchronousWatermarkingProvider.php', 'OCP\\TaskProcessing\\ITaskType' => $baseDir . '/lib/public/TaskProcessing/ITaskType.php', 'OCP\\TaskProcessing\\ITriggerableProvider' => $baseDir . '/lib/public/TaskProcessing/ITriggerableProvider.php', 'OCP\\TaskProcessing\\ShapeDescriptor' => $baseDir . '/lib/public/TaskProcessing/ShapeDescriptor.php', @@ -1536,6 +1537,7 @@ return array( 'OC\\Core\\Migrations\\Version33000Date20251023110529' => $baseDir . '/core/Migrations/Version33000Date20251023110529.php', 'OC\\Core\\Migrations\\Version33000Date20251023120529' => $baseDir . '/core/Migrations/Version33000Date20251023120529.php', 'OC\\Core\\Migrations\\Version33000Date20251106131209' => $baseDir . '/core/Migrations/Version33000Date20251106131209.php', + 'OC\\Core\\Migrations\\Version33000Date20251126152410' => $baseDir . '/core/Migrations/Version33000Date20251126152410.php', 'OC\\Core\\Notification\\CoreNotifier' => $baseDir . '/core/Notification/CoreNotifier.php', 'OC\\Core\\ResponseDefinitions' => $baseDir . '/core/ResponseDefinitions.php', 'OC\\Core\\Service\\CronService' => $baseDir . '/core/Service/CronService.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 9a6bd60c293..4a35216a172 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -916,6 +916,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\TaskProcessing\\IManager' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/IManager.php', 'OCP\\TaskProcessing\\IProvider' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/IProvider.php', 'OCP\\TaskProcessing\\ISynchronousProvider' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/ISynchronousProvider.php', + 'OCP\\TaskProcessing\\ISynchronousWatermarkingProvider' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/ISynchronousWatermarkingProvider.php', 'OCP\\TaskProcessing\\ITaskType' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/ITaskType.php', 'OCP\\TaskProcessing\\ITriggerableProvider' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/ITriggerableProvider.php', 'OCP\\TaskProcessing\\ShapeDescriptor' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/ShapeDescriptor.php', @@ -1577,6 +1578,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Core\\Migrations\\Version33000Date20251023110529' => __DIR__ . '/../../..' . '/core/Migrations/Version33000Date20251023110529.php', 'OC\\Core\\Migrations\\Version33000Date20251023120529' => __DIR__ . '/../../..' . '/core/Migrations/Version33000Date20251023120529.php', 'OC\\Core\\Migrations\\Version33000Date20251106131209' => __DIR__ . '/../../..' . '/core/Migrations/Version33000Date20251106131209.php', + 'OC\\Core\\Migrations\\Version33000Date20251126152410' => __DIR__ . '/../../..' . '/core/Migrations/Version33000Date20251126152410.php', 'OC\\Core\\Notification\\CoreNotifier' => __DIR__ . '/../../..' . '/core/Notification/CoreNotifier.php', 'OC\\Core\\ResponseDefinitions' => __DIR__ . '/../../..' . '/core/ResponseDefinitions.php', 'OC\\Core\\Service\\CronService' => __DIR__ . '/../../..' . '/core/Service/CronService.php', diff --git a/lib/private/TaskProcessing/Db/Task.php b/lib/private/TaskProcessing/Db/Task.php index 74bd154ae7d..3ac4facf97e 100644 --- a/lib/private/TaskProcessing/Db/Task.php +++ b/lib/private/TaskProcessing/Db/Task.php @@ -49,6 +49,8 @@ use OCP\TaskProcessing\Task as OCPTask; * @method int getAllowCleanup() * @method setUserFacingErrorMessage(null|string $message) * @method null|string getUserFacingErrorMessage() + * @method setIncludeWatermark(int $includeWatermark) + * @method int getIncludeWatermark() */ class Task extends Entity { protected $lastUpdated; @@ -69,16 +71,17 @@ class Task extends Entity { protected $endedAt; protected $allowCleanup; protected $userFacingErrorMessage; + protected $includeWatermark; /** * @var string[] */ - public static array $columns = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'custom_id', 'completion_expected_at', 'error_message', 'progress', 'webhook_uri', 'webhook_method', 'scheduled_at', 'started_at', 'ended_at', 'allow_cleanup', 'user_facing_error_message']; + public static array $columns = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'custom_id', 'completion_expected_at', 'error_message', 'progress', 'webhook_uri', 'webhook_method', 'scheduled_at', 'started_at', 'ended_at', 'allow_cleanup', 'user_facing_error_message', 'include_watermark']; /** * @var string[] */ - public static array $fields = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'customId', 'completionExpectedAt', 'errorMessage', 'progress', 'webhookUri', 'webhookMethod', 'scheduledAt', 'startedAt', 'endedAt', 'allowCleanup', 'userFacingErrorMessage']; + public static array $fields = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'customId', 'completionExpectedAt', 'errorMessage', 'progress', 'webhookUri', 'webhookMethod', 'scheduledAt', 'startedAt', 'endedAt', 'allowCleanup', 'userFacingErrorMessage', 'includeWatermark']; public function __construct() { @@ -102,6 +105,7 @@ class Task extends Entity { $this->addType('endedAt', 'integer'); $this->addType('allowCleanup', 'integer'); $this->addType('userFacingErrorMessage', 'string'); + $this->addType('includeWatermark', 'integer'); } public function toRow(): array { @@ -132,6 +136,7 @@ class Task extends Entity { 'endedAt' => $task->getEndedAt(), 'allowCleanup' => $task->getAllowCleanup() ? 1 : 0, 'userFacingErrorMessage' => $task->getUserFacingErrorMessage(), + 'includeWatermark' => $task->getIncludeWatermark() ? 1 : 0, ]); return $taskEntity; } @@ -156,6 +161,7 @@ class Task extends Entity { $task->setEndedAt($this->getEndedAt()); $task->setAllowCleanup($this->getAllowCleanup() !== 0); $task->setUserFacingErrorMessage($this->getUserFacingErrorMessage()); + $task->setIncludeWatermark($this->getIncludeWatermark() !== 0); return $task; } } diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index 73bf93c5934..ba185e89a0e 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -56,6 +56,7 @@ use OCP\TaskProcessing\IInternalTaskType; use OCP\TaskProcessing\IManager; use OCP\TaskProcessing\IProvider; use OCP\TaskProcessing\ISynchronousProvider; +use OCP\TaskProcessing\ISynchronousWatermarkingProvider; use OCP\TaskProcessing\ITaskType; use OCP\TaskProcessing\ITriggerableProvider; use OCP\TaskProcessing\ShapeDescriptor; @@ -1039,7 +1040,11 @@ class Manager implements IManager { } try { $this->setTaskStatus($task, Task::STATUS_RUNNING); - $output = $provider->process($task->getUserId(), $input, fn (float $progress) => $this->setTaskProgress($task->getId(), $progress)); + if ($provider instanceof ISynchronousWatermarkingProvider) { + $output = $provider->process($task->getUserId(), $input, fn (float $progress) => $this->setTaskProgress($task->getId(), $progress), $task->getIncludeWatermark()); + } else { + $output = $provider->process($task->getUserId(), $input, fn (float $progress) => $this->setTaskProgress($task->getId(), $progress)); + } } catch (ProcessingException $e) { $this->logger->warning('Failed to process a TaskProcessing task with synchronous provider ' . $provider->getId(), ['exception' => $e]); $userFacingErrorMessage = $e instanceof UserFacingProcessingException ? $e->getUserFacingMessage() : null; diff --git a/lib/public/TaskProcessing/ISynchronousWatermarkingProvider.php b/lib/public/TaskProcessing/ISynchronousWatermarkingProvider.php new file mode 100644 index 00000000000..97f283022be --- /dev/null +++ b/lib/public/TaskProcessing/ISynchronousWatermarkingProvider.php @@ -0,0 +1,35 @@ +|numeric|string|File> $input The task input + * @param callable(float):bool $reportProgress Report the task progress. If this returns false, that means the task was cancelled and processing should be stopped. + * @param bool $includeWatermark Whether to include the watermark in the output files or not + * @psalm-return array|numeric|string> + * @throws ProcessingException + * @since 33.0.0 + */ + public function process(?string $userId, array $input, callable $reportProgress, bool $includeWatermark = true): array; +} diff --git a/lib/public/TaskProcessing/Task.php b/lib/public/TaskProcessing/Task.php index 90b9be4cafd..a2899a1f1c9 100644 --- a/lib/public/TaskProcessing/Task.php +++ b/lib/public/TaskProcessing/Task.php @@ -49,6 +49,8 @@ final class Task implements \JsonSerializable { protected ?string $userFacingErrorMessage = null; + protected bool $includeWatermark = true; + /** * @since 30.0.0 */ @@ -277,7 +279,23 @@ final class Task implements \JsonSerializable { } /** - * @psalm-return array{id: int, lastUpdated: int, type: string, status: 'STATUS_CANCELLED'|'STATUS_FAILED'|'STATUS_SUCCESSFUL'|'STATUS_RUNNING'|'STATUS_SCHEDULED'|'STATUS_UNKNOWN', userId: ?string, appId: string, input: array|numeric|string>, output: ?array|numeric|string>, customId: ?string, completionExpectedAt: ?int, progress: ?float, scheduledAt: ?int, startedAt: ?int, endedAt: ?int, allowCleanup: bool} + * @return bool + * @since 33.0.0 + */ + final public function getIncludeWatermark(): bool { + return $this->includeWatermark; + } + + /** + * @param bool $includeWatermark + * @since 33.0.0 + */ + final public function setIncludeWatermark(bool $includeWatermark): void { + $this->includeWatermark = $includeWatermark; + } + + /** + * @psalm-return array{id: int, lastUpdated: int, type: string, status: 'STATUS_CANCELLED'|'STATUS_FAILED'|'STATUS_SUCCESSFUL'|'STATUS_RUNNING'|'STATUS_SCHEDULED'|'STATUS_UNKNOWN', userId: ?string, appId: string, input: array|numeric|string>, output: ?array|numeric|string>, customId: ?string, completionExpectedAt: ?int, progress: ?float, scheduledAt: ?int, startedAt: ?int, endedAt: ?int, allowCleanup: bool, includeWatermark: bool} * @since 30.0.0 */ final public function jsonSerialize(): array { @@ -297,6 +315,7 @@ final class Task implements \JsonSerializable { 'startedAt' => $this->getStartedAt(), 'endedAt' => $this->getEndedAt(), 'allowCleanup' => $this->getAllowCleanup(), + 'includeWatermark' => $this->getIncludeWatermark(), ]; } diff --git a/openapi.json b/openapi.json index 592bc2657ac..17a613cc4b4 100644 --- a/openapi.json +++ b/openapi.json @@ -701,7 +701,8 @@ "scheduledAt", "startedAt", "endedAt", - "allowCleanup" + "allowCleanup", + "includeWatermark" ], "properties": { "id": { @@ -775,6 +776,9 @@ }, "allowCleanup": { "type": "boolean" + }, + "includeWatermark": { + "type": "boolean" } } }, @@ -8475,6 +8479,11 @@ "nullable": true, "default": null, "description": "Method used for the webhook request (HTTP:GET, HTTP:POST, HTTP:PUT, HTTP:DELETE or AppAPI:APP_ID:GET, AppAPI:APP_ID:POST...)" + }, + "includeWatermark": { + "type": "boolean", + "default": true, + "description": "Whether to include a watermark in the output file or not" } } } diff --git a/version.php b/version.php index 5c151ef5d91..8ee42146790 100644 --- a/version.php +++ b/version.php @@ -9,7 +9,7 @@ // between betas, final and RCs. This is _not_ the public version number. Reset minor/patch level // when updating major/minor version number. -$OC_Version = [33, 0, 0, 4]; +$OC_Version = [33, 0, 0, 5]; // The human-readable string $OC_VersionString = '33.0.0 dev';