@@ -59,17 +59,10 @@ public function __construct(
5959 }
6060
6161 /**
62- * Returns all available TaskProcessing task types
63- *
64- * @return DataResponse<Http::STATUS_OK, array{types: array<string, CoreTaskProcessingTaskType>}, array{}>
65- *
66- * 200: Task types returned
62+ * @return array<string, CoreTaskProcessingTaskType>
6763 */
68- #[NoAdminRequired]
69- #[ApiRoute(verb: 'GET ' , url: '/tasktypes ' , root: '/taskprocessing ' )]
70- public function taskTypes (): DataResponse {
71- /** @var array<string, CoreTaskProcessingTaskType> $taskTypes */
72- $ taskTypes = array_map (function (array $ tt ) {
64+ private function getTaskTypesInternal (): array {
65+ return array_map (function (array $ tt ) {
7366 $ tt ['inputShape ' ] = array_map (function ($ descriptor ) {
7467 return $ descriptor ->jsonSerialize ();
7568 }, $ tt ['inputShape ' ]);
@@ -134,11 +127,72 @@ public function taskTypes(): DataResponse {
134127 }
135128 return $ tt ;
136129 }, $ this ->taskProcessingManager ->getAvailableTaskTypes ());
130+ }
131+
132+ /**
133+ * Returns all available TaskProcessing task types
134+ *
135+ * @return DataResponse<Http::STATUS_OK, array{types: array<string, CoreTaskProcessingTaskType>}, array{}>
136+ *
137+ * 200: Task types returned
138+ */
139+ #[NoAdminRequired]
140+ #[ApiRoute(verb: 'GET ' , url: '/tasktypes ' , root: '/taskprocessing ' )]
141+ public function taskTypes (): DataResponse {
137142 return new DataResponse ([
138- 'types ' => $ taskTypes ,
143+ 'types ' => $ this -> getTaskTypesInternal () ,
139144 ]);
140145 }
141146
147+ /**
148+ * Returns all available TaskProcessing task types
149+ *
150+ * Endpoint for ExApp usage without user context
151+ *
152+ * @return DataResponse<Http::STATUS_OK, array{types: array<string, CoreTaskProcessingTaskType>}, array{}>
153+ *
154+ * 200: Task types returned
155+ */
156+ #[ExAppRequired]
157+ #[ApiRoute(verb: 'GET ' , url: '/tasks_consumer/tasktypes ' , root: '/taskprocessing ' )]
158+ public function taskTypesExAppEndpoint (): DataResponse {
159+ return new DataResponse ([
160+ 'types ' => $ this ->getTaskTypesInternal (),
161+ ]);
162+ }
163+
164+ private function handleScheduleTaskInternal (
165+ array $ input , string $ type , string $ appId , string $ customId = '' ,
166+ ?string $ webhookUri = null , ?string $ webhookMethod = null , bool $ includeWatermark = true ,
167+ ): DataResponse {
168+ $ task = new Task ($ type , $ input , $ appId , $ this ->userId , $ customId );
169+ $ task ->setWebhookUri ($ webhookUri );
170+ $ task ->setWebhookMethod ($ webhookMethod );
171+ $ task ->setIncludeWatermark ($ includeWatermark );
172+ try {
173+ $ this ->taskProcessingManager ->scheduleTask ($ task );
174+
175+ /** @var CoreTaskProcessingTask $json */
176+ $ json = $ task ->jsonSerialize ();
177+
178+ return new DataResponse ([
179+ 'task ' => $ json ,
180+ ]);
181+ } catch (PreConditionNotMetException ) {
182+ return new DataResponse (['message ' => $ this ->l ->t ('The given provider is not available ' )], Http::STATUS_PRECONDITION_FAILED );
183+ } catch (ValidationException $ e ) {
184+ return new DataResponse (['message ' => $ e ->getMessage ()], Http::STATUS_BAD_REQUEST );
185+ } catch (UnauthorizedException ) {
186+ if ($ userId === null ) {
187+ // validation error happens in the manager if no user context is given
188+ return new DataResponse (['message ' => 'Cannot schedule task with files referenced without user context ' ], Http::STATUS_UNAUTHORIZED );
189+ }
190+ return new DataResponse (['message ' => 'User does not have access to the files mentioned in the task input ' ], Http::STATUS_UNAUTHORIZED );
191+ } catch (Exception ) {
192+ return new DataResponse (['message ' => 'Internal server error ' ], Http::STATUS_INTERNAL_SERVER_ERROR );
193+ }
194+ }
195+
142196 /**
143197 * Schedules a task
144198 *
@@ -163,27 +217,67 @@ public function schedule(
163217 array $ input , string $ type , string $ appId , string $ customId = '' ,
164218 ?string $ webhookUri = null , ?string $ webhookMethod = null , bool $ includeWatermark = true ,
165219 ): DataResponse {
166- $ task = new Task ($ type , $ input , $ appId , $ this ->userId , $ customId );
167- $ task ->setWebhookUri ($ webhookUri );
168- $ task ->setWebhookMethod ($ webhookMethod );
169- $ task ->setIncludeWatermark ($ includeWatermark );
220+ return $ this ->handleScheduleTaskInternal (
221+ $ input ,
222+ $ type ,
223+ $ appId ,
224+ $ customId ,
225+ $ webhookUri ,
226+ $ webhookMethod ,
227+ $ includeWatermark ,
228+ );
229+ }
230+
231+ /**
232+ * Schedules a task
233+ *
234+ * Endpoint for ExApp usage without user context. Files cannot be referenced in this case.
235+ *
236+ * @param array<string, mixed> $input Task's input parameters
237+ * @param string $type Type of the task
238+ * @param string $appId ID of the app that will execute the task
239+ * @param string $customId An arbitrary identifier for the task
240+ * @param string|null $webhookUri URI to be requested when the task finishes
241+ * @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...)
242+ * @param bool $includeWatermark Whether to include a watermark in the output file or not
243+ * @return DataResponse<Http::STATUS_OK, array{task: CoreTaskProcessingTask}, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_BAD_REQUEST|Http::STATUS_PRECONDITION_FAILED|Http::STATUS_UNAUTHORIZED, array{message: string}, array{}>
244+ *
245+ * 200: Task scheduled successfully
246+ * 400: Scheduling task is not possible
247+ * 412: Scheduling task is not possible
248+ * 401: Cannot schedule task because it references files in its input
249+ */
250+ #[ExAppRequired]
251+ #[ApiRoute(verb: 'POST ' , url: '/tasks_consumer/schedule ' , root: '/taskprocessing ' )]
252+ public function scheduleExAppEndpoint (
253+ array $ input , string $ type , string $ appId , string $ customId = '' ,
254+ ?string $ webhookUri = null , ?string $ webhookMethod = null , bool $ includeWatermark = true ,
255+ ): DataResponse {
256+ return $ this ->handleScheduleTaskInternal (
257+ $ input ,
258+ $ type ,
259+ $ appId ,
260+ $ customId ,
261+ $ webhookUri ,
262+ $ webhookMethod ,
263+ $ includeWatermark ,
264+ );
265+ }
266+
267+ private function handleGetTaskInternal (int $ id ): DataResponse {
170268 try {
171- $ this ->taskProcessingManager ->scheduleTask ( $ task );
269+ $ task = $ this ->taskProcessingManager ->getUserTask ( $ id , $ this -> userId );
172270
173271 /** @var CoreTaskProcessingTask $json */
174272 $ json = $ task ->jsonSerialize ();
175273
176274 return new DataResponse ([
177275 'task ' => $ json ,
178276 ]);
179- } catch (PreConditionNotMetException ) {
180- return new DataResponse (['message ' => $ this ->l ->t ('The given provider is not available ' )], Http::STATUS_PRECONDITION_FAILED );
181- } catch (ValidationException $ e ) {
182- return new DataResponse (['message ' => $ e ->getMessage ()], Http::STATUS_BAD_REQUEST );
183- } catch (UnauthorizedException ) {
184- return new DataResponse (['message ' => 'User does not have access to the files mentioned in the task input ' ], Http::STATUS_UNAUTHORIZED );
185- } catch (Exception ) {
186- return new DataResponse (['message ' => 'Internal server error ' ], Http::STATUS_INTERNAL_SERVER_ERROR );
277+ } catch (NotFoundException ) {
278+ return new DataResponse (['message ' => $ this ->l ->t ('Task not found ' )], Http::STATUS_NOT_FOUND );
279+ } catch (RuntimeException ) {
280+ return new DataResponse (['message ' => $ this ->l ->t ('Internal error ' )], Http::STATUS_INTERNAL_SERVER_ERROR );
187281 }
188282 }
189283
@@ -202,18 +296,39 @@ public function schedule(
202296 #[NoAdminRequired]
203297 #[ApiRoute(verb: 'GET ' , url: '/task/{id} ' , root: '/taskprocessing ' )]
204298 public function getTask (int $ id ): DataResponse {
299+ return $ this ->handleGetTaskInternal ($ id );
300+ }
301+
302+ /**
303+ * Gets a task including status and result
304+ *
305+ * Endpoint for ExApp usage without user context
306+ *
307+ * Tasks are removed 1 week after receiving their last update
308+ *
309+ * @param int $id The id of the task
310+ *
311+ * @return DataResponse<Http::STATUS_OK, array{task: CoreTaskProcessingTask}, array{}>|DataResponse<Http::STATUS_NOT_FOUND|Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}>
312+ *
313+ * 200: Task returned
314+ * 404: Task not found
315+ */
316+ #[ExAppRequired]
317+ #[ApiRoute(verb: 'GET ' , url: '/tasks_consumer/task/{id} ' , root: '/taskprocessing ' )]
318+ public function getTaskExAppEndpoint (int $ id ): DataResponse {
319+ return $ this ->handleGetTaskInternal ($ id );
320+ }
321+
322+ private function handleDeleteTaskInternal (int $ id ): DataResponse {
205323 try {
206324 $ task = $ this ->taskProcessingManager ->getUserTask ($ id , $ this ->userId );
207325
208- /** @var CoreTaskProcessingTask $json */
209- $ json = $ task ->jsonSerialize ();
326+ $ this ->taskProcessingManager ->deleteTask ($ task );
210327
211- return new DataResponse ([
212- 'task ' => $ json ,
213- ]);
328+ return new DataResponse (null );
214329 } catch (NotFoundException ) {
215- return new DataResponse ([ ' message ' => $ this -> l -> t ( ' Task not found ' )], Http:: STATUS_NOT_FOUND );
216- } catch (RuntimeException ) {
330+ return new DataResponse (null );
331+ } catch (Exception ) {
217332 return new DataResponse (['message ' => $ this ->l ->t ('Internal error ' )], Http::STATUS_INTERNAL_SERVER_ERROR );
218333 }
219334 }
@@ -230,17 +345,24 @@ public function getTask(int $id): DataResponse {
230345 #[NoAdminRequired]
231346 #[ApiRoute(verb: 'DELETE ' , url: '/task/{id} ' , root: '/taskprocessing ' )]
232347 public function deleteTask (int $ id ): DataResponse {
233- try {
234- $ task = $ this ->taskProcessingManager ->getUserTask ($ id , $ this ->userId );
235-
236- $ this ->taskProcessingManager ->deleteTask ($ task );
348+ return $ this ->handleDeleteTaskInternal ($ id );
349+ }
237350
238- return new DataResponse (null );
239- } catch (NotFoundException ) {
240- return new DataResponse (null );
241- } catch (Exception ) {
242- return new DataResponse (['message ' => $ this ->l ->t ('Internal error ' )], Http::STATUS_INTERNAL_SERVER_ERROR );
243- }
351+ /**
352+ * Deletes a task
353+ *
354+ * Endpoint for ExApp usage without user context
355+ *
356+ * @param int $id The id of the task
357+ *
358+ * @return DataResponse<Http::STATUS_OK, null, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}>
359+ *
360+ * 200: Task deleted
361+ */
362+ #[ExAppRequired]
363+ #[ApiRoute(verb: 'DELETE ' , url: '/tasks_consumer/task/{id} ' , root: '/taskprocessing ' )]
364+ public function deleteTaskExAppEndpoint (int $ id ): DataResponse {
365+ return $ this ->handleDeleteTaskInternal ($ id );
244366 }
245367
246368
@@ -489,18 +611,7 @@ public function setResult(int $taskId, ?array $output = null, ?string $errorMess
489611 }
490612 }
491613
492- /**
493- * Cancels a task
494- *
495- * @param int $taskId The id of the task
496- * @return DataResponse<Http::STATUS_OK, array{task: CoreTaskProcessingTask}, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
497- *
498- * 200: Task canceled successfully
499- * 404: Task not found
500- */
501- #[NoAdminRequired]
502- #[ApiRoute(verb: 'POST ' , url: '/tasks/{taskId}/cancel ' , root: '/taskprocessing ' )]
503- public function cancelTask (int $ taskId ): DataResponse {
614+ private function handleCancelTaskInternal (int $ taskId ): DataResponse {
504615 try {
505616 // Check if the current user can access the task
506617 $ this ->taskProcessingManager ->getUserTask ($ taskId , $ this ->userId );
@@ -521,6 +632,38 @@ public function cancelTask(int $taskId): DataResponse {
521632 }
522633 }
523634
635+ /**
636+ * Cancels a task
637+ *
638+ * @param int $taskId The id of the task
639+ * @return DataResponse<Http::STATUS_OK, array{task: CoreTaskProcessingTask}, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
640+ *
641+ * 200: Task canceled successfully
642+ * 404: Task not found
643+ */
644+ #[NoAdminRequired]
645+ #[ApiRoute(verb: 'POST ' , url: '/tasks/{taskId}/cancel ' , root: '/taskprocessing ' )]
646+ public function cancelTask (int $ taskId ): DataResponse {
647+ return $ this ->handleCancelTaskInternal ($ taskId );
648+ }
649+
650+ /**
651+ * Cancels a task
652+ *
653+ * Endpoint for ExApp usage without user context
654+ *
655+ * @param int $taskId The id of the task
656+ * @return DataResponse<Http::STATUS_OK, array{task: CoreTaskProcessingTask}, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
657+ *
658+ * 200: Task canceled successfully
659+ * 404: Task not found
660+ */
661+ #[ExAppRequired]
662+ #[ApiRoute(verb: 'POST ' , url: '/tasks_consumer/tasks/{taskId}/cancel ' , root: '/taskprocessing ' )]
663+ public function cancelTaskExAppInternal (int $ taskId ): DataResponse {
664+ return $ this ->handleCancelTaskInternal ($ taskId );
665+ }
666+
524667 /**
525668 * Returns the next scheduled task for the taskTypeId
526669 *
0 commit comments