Skip to content

Commit d838c65

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

File tree

4 files changed

+3540
-55
lines changed

4 files changed

+3540
-55
lines changed

core/Controller/TaskProcessingApiController.php

Lines changed: 204 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -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,74 @@ 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+
/**
165+
* @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{}>
166+
*/
167+
private function handleScheduleTaskInternal(
168+
array $input, string $type, string $appId, string $customId = '',
169+
?string $webhookUri = null, ?string $webhookMethod = null, bool $includeWatermark = true,
170+
): DataResponse {
171+
$task = new Task($type, $input, $appId, $this->userId, $customId);
172+
$task->setWebhookUri($webhookUri);
173+
$task->setWebhookMethod($webhookMethod);
174+
$task->setIncludeWatermark($includeWatermark);
175+
try {
176+
$this->taskProcessingManager->scheduleTask($task);
177+
178+
/** @var CoreTaskProcessingTask $json */
179+
$json = $task->jsonSerialize();
180+
181+
return new DataResponse([
182+
'task' => $json,
183+
]);
184+
} catch (PreConditionNotMetException) {
185+
return new DataResponse(['message' => $this->l->t('The given provider is not available')], Http::STATUS_PRECONDITION_FAILED);
186+
} catch (ValidationException $e) {
187+
return new DataResponse(['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
188+
} catch (UnauthorizedException) {
189+
if ($this->userId === null) {
190+
return new DataResponse(['message' => 'Cannot schedule task with files referenced without user context'], Http::STATUS_UNAUTHORIZED);
191+
}
192+
return new DataResponse(['message' => 'User does not have access to the files mentioned in the task input'], Http::STATUS_UNAUTHORIZED);
193+
} catch (Exception) {
194+
return new DataResponse(['message' => 'Internal server error'], Http::STATUS_INTERNAL_SERVER_ERROR);
195+
}
196+
}
197+
142198
/**
143199
* Schedules a task
144200
*
@@ -163,27 +219,70 @@ public function schedule(
163219
array $input, string $type, string $appId, string $customId = '',
164220
?string $webhookUri = null, ?string $webhookMethod = null, bool $includeWatermark = true,
165221
): DataResponse {
166-
$task = new Task($type, $input, $appId, $this->userId, $customId);
167-
$task->setWebhookUri($webhookUri);
168-
$task->setWebhookMethod($webhookMethod);
169-
$task->setIncludeWatermark($includeWatermark);
222+
return $this->handleScheduleTaskInternal(
223+
$input,
224+
$type,
225+
$appId,
226+
$customId,
227+
$webhookUri,
228+
$webhookMethod,
229+
$includeWatermark,
230+
);
231+
}
232+
233+
/**
234+
* Schedules a task
235+
*
236+
* Endpoint for ExApp usage without user context. Files cannot be referenced in this case.
237+
*
238+
* @param array<string, mixed> $input Task's input parameters
239+
* @param string $type Type of the task
240+
* @param string $appId ID of the app that will execute the task
241+
* @param string $customId An arbitrary identifier for the task
242+
* @param string|null $webhookUri URI to be requested when the task finishes
243+
* @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...)
244+
* @param bool $includeWatermark Whether to include a watermark in the output file or not
245+
* @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{}>
246+
*
247+
* 200: Task scheduled successfully
248+
* 400: Scheduling task is not possible
249+
* 412: Scheduling task is not possible
250+
* 401: Cannot schedule task because it references files in its input
251+
*/
252+
#[ExAppRequired]
253+
#[ApiRoute(verb: 'POST', url: '/tasks_consumer/schedule', root: '/taskprocessing')]
254+
public function scheduleExAppEndpoint(
255+
array $input, string $type, string $appId, string $customId = '',
256+
?string $webhookUri = null, ?string $webhookMethod = null, bool $includeWatermark = true,
257+
): DataResponse {
258+
return $this->handleScheduleTaskInternal(
259+
$input,
260+
$type,
261+
$appId,
262+
$customId,
263+
$webhookUri,
264+
$webhookMethod,
265+
$includeWatermark,
266+
);
267+
}
268+
269+
/**
270+
* @return DataResponse<Http::STATUS_OK, array{task: CoreTaskProcessingTask}, array{}>|DataResponse<Http::STATUS_NOT_FOUND|Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}>
271+
*/
272+
private function handleGetTaskInternal(int $id): DataResponse {
170273
try {
171-
$this->taskProcessingManager->scheduleTask($task);
274+
$task = $this->taskProcessingManager->getUserTask($id, $this->userId);
172275

173276
/** @var CoreTaskProcessingTask $json */
174277
$json = $task->jsonSerialize();
175278

176279
return new DataResponse([
177280
'task' => $json,
178281
]);
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);
282+
} catch (NotFoundException) {
283+
return new DataResponse(['message' => $this->l->t('Task not found')], Http::STATUS_NOT_FOUND);
284+
} catch (RuntimeException) {
285+
return new DataResponse(['message' => $this->l->t('Internal error')], Http::STATUS_INTERNAL_SERVER_ERROR);
187286
}
188287
}
189288

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

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

211-
return new DataResponse([
212-
'task' => $json,
213-
]);
336+
return new DataResponse(null);
214337
} catch (NotFoundException) {
215-
return new DataResponse(['message' => $this->l->t('Task not found')], Http::STATUS_NOT_FOUND);
216-
} catch (RuntimeException) {
338+
return new DataResponse(null);
339+
} catch (Exception) {
217340
return new DataResponse(['message' => $this->l->t('Internal error')], Http::STATUS_INTERNAL_SERVER_ERROR);
218341
}
219342
}
@@ -230,17 +353,24 @@ public function getTask(int $id): DataResponse {
230353
#[NoAdminRequired]
231354
#[ApiRoute(verb: 'DELETE', url: '/task/{id}', root: '/taskprocessing')]
232355
public function deleteTask(int $id): DataResponse {
233-
try {
234-
$task = $this->taskProcessingManager->getUserTask($id, $this->userId);
235-
236-
$this->taskProcessingManager->deleteTask($task);
356+
return $this->handleDeleteTaskInternal($id);
357+
}
237358

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

246376

@@ -490,17 +620,9 @@ public function setResult(int $taskId, ?array $output = null, ?string $errorMess
490620
}
491621

492622
/**
493-
* Cancels a task
494-
*
495-
* @param int $taskId The id of the task
496623
* @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
500624
*/
501-
#[NoAdminRequired]
502-
#[ApiRoute(verb: 'POST', url: '/tasks/{taskId}/cancel', root: '/taskprocessing')]
503-
public function cancelTask(int $taskId): DataResponse {
625+
private function handleCancelTaskInternal(int $taskId): DataResponse {
504626
try {
505627
// Check if the current user can access the task
506628
$this->taskProcessingManager->getUserTask($taskId, $this->userId);
@@ -521,6 +643,38 @@ public function cancelTask(int $taskId): DataResponse {
521643
}
522644
}
523645

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

0 commit comments

Comments
 (0)