Skip to content

Commit 3e4e544

Browse files
committed
feat(TaskProcessing): add endpoints for ExApp access without userId
Signed-off-by: Anupam Kumar <[email protected]>
1 parent 1a7f2f8 commit 3e4e544

File tree

4 files changed

+3540
-57
lines changed

4 files changed

+3540
-57
lines changed

core/Controller/TaskProcessingApiController.php

Lines changed: 204 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,9 @@ public function __construct(
5858
parent::__construct($appName, $request);
5959
}
6060

61-
/**
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
67-
*/
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) {
61+
private function getTaskTypesInternal(): array {
62+
/** @var array<string, CoreTaskProcessingTaskType> */
63+
return array_map(function (array $tt) {
7364
$tt['inputShape'] = array_map(function ($descriptor) {
7465
return $descriptor->jsonSerialize();
7566
}, $tt['inputShape']);
@@ -134,11 +125,74 @@ public function taskTypes(): DataResponse {
134125
}
135126
return $tt;
136127
}, $this->taskProcessingManager->getAvailableTaskTypes());
128+
}
129+
130+
/**
131+
* Returns all available TaskProcessing task types
132+
*
133+
* @return DataResponse<Http::STATUS_OK, array{types: array<string, CoreTaskProcessingTaskType>}, array{}>
134+
*
135+
* 200: Task types returned
136+
*/
137+
#[NoAdminRequired]
138+
#[ApiRoute(verb: 'GET', url: '/tasktypes', root: '/taskprocessing')]
139+
public function taskTypes(): DataResponse {
137140
return new DataResponse([
138-
'types' => $taskTypes,
141+
'types' => $this->getTaskTypesInternal(),
139142
]);
140143
}
141144

145+
/**
146+
* Returns all available TaskProcessing task types
147+
*
148+
* Endpoint for ExApp usage without user context
149+
*
150+
* @return DataResponse<Http::STATUS_OK, array{types: array<string, CoreTaskProcessingTaskType>}, array{}>
151+
*
152+
* 200: Task types returned
153+
*/
154+
#[ExAppRequired]
155+
#[ApiRoute(verb: 'GET', url: '/tasks_consumer/tasktypes', root: '/taskprocessing')]
156+
public function taskTypesExAppEndpoint(): DataResponse {
157+
return new DataResponse([
158+
'types' => $this->getTaskTypesInternal(),
159+
]);
160+
}
161+
162+
/**
163+
* @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{}>
164+
*/
165+
private function handleScheduleTaskInternal(
166+
array $input, string $type, string $appId, string $customId = '',
167+
?string $webhookUri = null, ?string $webhookMethod = null, bool $includeWatermark = true,
168+
): DataResponse {
169+
$task = new Task($type, $input, $appId, $this->userId, $customId);
170+
$task->setWebhookUri($webhookUri);
171+
$task->setWebhookMethod($webhookMethod);
172+
$task->setIncludeWatermark($includeWatermark);
173+
try {
174+
$this->taskProcessingManager->scheduleTask($task);
175+
176+
/** @var CoreTaskProcessingTask $json */
177+
$json = $task->jsonSerialize();
178+
179+
return new DataResponse([
180+
'task' => $json,
181+
]);
182+
} catch (PreConditionNotMetException) {
183+
return new DataResponse(['message' => $this->l->t('The given provider is not available')], Http::STATUS_PRECONDITION_FAILED);
184+
} catch (ValidationException $e) {
185+
return new DataResponse(['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
186+
} catch (UnauthorizedException) {
187+
if ($this->userId === null) {
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,70 @@ 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+
/**
268+
* @return DataResponse<Http::STATUS_OK, array{task: CoreTaskProcessingTask}, array{}>|DataResponse<Http::STATUS_NOT_FOUND|Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}>
269+
*/
270+
private function handleGetTaskInternal(int $id): DataResponse {
170271
try {
171-
$this->taskProcessingManager->scheduleTask($task);
272+
$task = $this->taskProcessingManager->getUserTask($id, $this->userId);
172273

173274
/** @var CoreTaskProcessingTask $json */
174275
$json = $task->jsonSerialize();
175276

176277
return new DataResponse([
177278
'task' => $json,
178279
]);
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);
280+
} catch (NotFoundException) {
281+
return new DataResponse(['message' => $this->l->t('Task not found')], Http::STATUS_NOT_FOUND);
282+
} catch (RuntimeException) {
283+
return new DataResponse(['message' => $this->l->t('Internal error')], Http::STATUS_INTERNAL_SERVER_ERROR);
187284
}
188285
}
189286

@@ -202,18 +299,42 @@ public function schedule(
202299
#[NoAdminRequired]
203300
#[ApiRoute(verb: 'GET', url: '/task/{id}', root: '/taskprocessing')]
204301
public function getTask(int $id): DataResponse {
302+
return $this->handleGetTaskInternal($id);
303+
}
304+
305+
/**
306+
* Gets a task including status and result
307+
*
308+
* Endpoint for ExApp usage without user context
309+
*
310+
* Tasks are removed 1 week after receiving their last update
311+
*
312+
* @param int $id The id of the task
313+
*
314+
* @return DataResponse<Http::STATUS_OK, array{task: CoreTaskProcessingTask}, array{}>|DataResponse<Http::STATUS_NOT_FOUND|Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}>
315+
*
316+
* 200: Task returned
317+
* 404: Task not found
318+
*/
319+
#[ExAppRequired]
320+
#[ApiRoute(verb: 'GET', url: '/tasks_consumer/task/{id}', root: '/taskprocessing')]
321+
public function getTaskExAppEndpoint(int $id): DataResponse {
322+
return $this->handleGetTaskInternal($id);
323+
}
324+
325+
/**
326+
* @return DataResponse<Http::STATUS_OK, null, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}>
327+
*/
328+
private function handleDeleteTaskInternal(int $id): DataResponse {
205329
try {
206330
$task = $this->taskProcessingManager->getUserTask($id, $this->userId);
207331

208-
/** @var CoreTaskProcessingTask $json */
209-
$json = $task->jsonSerialize();
332+
$this->taskProcessingManager->deleteTask($task);
210333

211-
return new DataResponse([
212-
'task' => $json,
213-
]);
334+
return new DataResponse(null);
214335
} catch (NotFoundException) {
215-
return new DataResponse(['message' => $this->l->t('Task not found')], Http::STATUS_NOT_FOUND);
216-
} catch (RuntimeException) {
336+
return new DataResponse(null);
337+
} catch (Exception) {
217338
return new DataResponse(['message' => $this->l->t('Internal error')], Http::STATUS_INTERNAL_SERVER_ERROR);
218339
}
219340
}
@@ -230,17 +351,24 @@ public function getTask(int $id): DataResponse {
230351
#[NoAdminRequired]
231352
#[ApiRoute(verb: 'DELETE', url: '/task/{id}', root: '/taskprocessing')]
232353
public function deleteTask(int $id): DataResponse {
233-
try {
234-
$task = $this->taskProcessingManager->getUserTask($id, $this->userId);
235-
236-
$this->taskProcessingManager->deleteTask($task);
354+
return $this->handleDeleteTaskInternal($id);
355+
}
237356

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-
}
357+
/**
358+
* Deletes a task
359+
*
360+
* Endpoint for ExApp usage without user context
361+
*
362+
* @param int $id The id of the task
363+
*
364+
* @return DataResponse<Http::STATUS_OK, null, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}>
365+
*
366+
* 200: Task deleted
367+
*/
368+
#[ExAppRequired]
369+
#[ApiRoute(verb: 'DELETE', url: '/tasks_consumer/task/{id}', root: '/taskprocessing')]
370+
public function deleteTaskExAppEndpoint(int $id): DataResponse {
371+
return $this->handleDeleteTaskInternal($id);
244372
}
245373

246374

@@ -490,17 +618,9 @@ public function setResult(int $taskId, ?array $output = null, ?string $errorMess
490618
}
491619

492620
/**
493-
* Cancels a task
494-
*
495-
* @param int $taskId The id of the task
496621
* @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
500622
*/
501-
#[NoAdminRequired]
502-
#[ApiRoute(verb: 'POST', url: '/tasks/{taskId}/cancel', root: '/taskprocessing')]
503-
public function cancelTask(int $taskId): DataResponse {
623+
private function handleCancelTaskInternal(int $taskId): DataResponse {
504624
try {
505625
// Check if the current user can access the task
506626
$this->taskProcessingManager->getUserTask($taskId, $this->userId);
@@ -521,6 +641,38 @@ public function cancelTask(int $taskId): DataResponse {
521641
}
522642
}
523643

644+
/**
645+
* Cancels a task
646+
*
647+
* @param int $taskId The id of the task
648+
* @return DataResponse<Http::STATUS_OK, array{task: CoreTaskProcessingTask}, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
649+
*
650+
* 200: Task canceled successfully
651+
* 404: Task not found
652+
*/
653+
#[NoAdminRequired]
654+
#[ApiRoute(verb: 'POST', url: '/tasks/{taskId}/cancel', root: '/taskprocessing')]
655+
public function cancelTask(int $taskId): DataResponse {
656+
return $this->handleCancelTaskInternal($taskId);
657+
}
658+
659+
/**
660+
* Cancels a task
661+
*
662+
* Endpoint for ExApp usage without user context
663+
*
664+
* @param int $taskId The id of the task
665+
* @return DataResponse<Http::STATUS_OK, array{task: CoreTaskProcessingTask}, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
666+
*
667+
* 200: Task canceled successfully
668+
* 404: Task not found
669+
*/
670+
#[ExAppRequired]
671+
#[ApiRoute(verb: 'POST', url: '/tasks_consumer/tasks/{taskId}/cancel', root: '/taskprocessing')]
672+
public function cancelTaskExAppEndpoint(int $taskId): DataResponse {
673+
return $this->handleCancelTaskInternal($taskId);
674+
}
675+
524676
/**
525677
* Returns the next scheduled task for the taskTypeId
526678
*

0 commit comments

Comments
 (0)