UNPKG

@tsed/formio

Version:
137 lines (107 loc) 3.81 kB
import {AnyToPromise, AnyToPromiseStatus} from "@tsed/core"; import {Inject, InjectorService, Provider} from "@tsed/di"; import {FormioActionInfo} from "@tsed/formio-types"; import {PlatformContext, setResponseHeaders} from "@tsed/platform-http"; import {PlatformParams} from "@tsed/platform-params"; import {PlatformResponseFilter} from "@tsed/platform-response-filter"; import {EndpointMetadata} from "@tsed/schema"; import {Alter} from "../decorators/alter.js"; import {AlterHook} from "../domain/AlterHook.js"; import {SetActionItemMessage} from "../domain/FormioAction.js"; import {FormioActions} from "../domain/FormioActionsIndex.js"; import {FormioService} from "../services/FormioService.js"; @Alter("actions") export class AlterActions implements AlterHook { @Inject() protected injector: InjectorService; @Inject() protected formio: FormioService; @Inject() protected params: PlatformParams; @Inject() protected responseFilter: PlatformResponseFilter; transform(actions: FormioActions): FormioActions { const {Action} = this.formio; return this.getActions().reduce((actions, provider) => { const instance = this.injector.invoke<any>(provider.token); const options = provider.store.get<FormioActionInfo>("formio:action"); const resolveHandler = this.createHandler(provider, "resolve"); return { ...actions, [options.name]: class extends Action { static access = options.access; static async info(req: any, res: any, next: Function) { let opts = {...options}; if (instance.info) { opts = await instance.info(opts, req, res); } next(null, opts); } static async settingsForm(req: any, res: any, next: Function) { next(null, await instance.settingsForm(req, res)); } resolve(handler: string, method: string, req: any, res: any, next: Function, setActionItemMessage: SetActionItemMessage): void { resolveHandler(this, handler, method, req, res, next, setActionItemMessage); } } }; }, actions); } protected getActions() { return this.injector.getProviders("formio:action"); } protected createHandler(provider: Provider, propertyKey: string | symbol) { const compiledHandler = this.params.compileHandler({ token: provider.token, propertyKey }); return async ( action: any, handler: string, method: string, req: any, res: any, next: any, setActionItemMessage: SetActionItemMessage ) => { const {$ctx} = req; if ($ctx) { $ctx.set("ACTION_CTX", {handler, method, setActionItemMessage, action}); $ctx.endpoint = EndpointMetadata.get(provider.useClass, "resolve"); try { if (await this.onRequest(compiledHandler, $ctx)) { next(); } } catch (er) { next(er); } } }; } private async onRequest(handler: any, $ctx: PlatformContext) { const resolver = new AnyToPromise(); const {state, data, status, headers} = await resolver.call(() => handler({$ctx})); if (state === AnyToPromiseStatus.RESOLVED) { if (status) { $ctx.response.status(status); } if (headers) { $ctx.response.setHeaders(headers); } if (data !== undefined) { $ctx.data = data; return this.flush($ctx.data, $ctx); } return true; } } private async flush(data: any, $ctx: PlatformContext) { const {response} = $ctx; if (!$ctx.isDone()) { setResponseHeaders($ctx); data = await this.responseFilter.transform(data, $ctx as any); response.body(data); } return response; } }