diff --git a/CHANGELOG.md b/CHANGELOG.md index 38a18af..dcfc47b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ Template for next version ### Changed +- notifications / hooks / pages and buttons encode and decode their ids + ### Fixed - missing encode / decode for form fields within submissions (https://github.com/ohmyform/ui/commit/30ff2c96bca20c1641d9cbb96c34cce934e1afea#r68602651) diff --git a/src/dto/form/button.model.ts b/src/dto/form/button.model.ts index aabb1b8..d4a3104 100644 --- a/src/dto/form/button.model.ts +++ b/src/dto/form/button.model.ts @@ -3,6 +3,8 @@ import { PageButtonEntity } from '../../entity/page.button.entity' @ObjectType('Button') export class ButtonModel { + readonly _id: number + @Field(() => ID) readonly id: string @@ -24,8 +26,9 @@ export class ButtonModel { @Field({ nullable: true }) readonly color?: string - constructor(button: Partial) { - this.id = button.id.toString() + constructor(id: string, button: Partial) { + this._id = button.id + this.id = id this.url = button.url this.action = button.action this.text = button.text diff --git a/src/dto/form/form.field.logic.model.ts b/src/dto/form/form.field.logic.model.ts index 7567b1c..46a5b15 100644 --- a/src/dto/form/form.field.logic.model.ts +++ b/src/dto/form/form.field.logic.model.ts @@ -3,6 +3,8 @@ import { FormFieldLogicEntity } from '../../entity/form.field.logic.entity' @ObjectType('FormFieldLogic') export class FormFieldLogicModel { + readonly _id: number + @Field(() => ID) readonly id: string @@ -30,8 +32,9 @@ export class FormFieldLogicModel { @Field() readonly enabled: boolean - constructor(document: FormFieldLogicEntity) { - this.id = document.id.toString() + constructor(id: string, document: FormFieldLogicEntity) { + this._id = document.id + this.id = id this.enabled = document.enabled this.formula = document.formula diff --git a/src/dto/form/form.field.option.model.ts b/src/dto/form/form.field.option.model.ts index cb3c714..3f91fde 100644 --- a/src/dto/form/form.field.option.model.ts +++ b/src/dto/form/form.field.option.model.ts @@ -3,6 +3,8 @@ import { FormFieldOptionEntity } from '../../entity/form.field.option.entity' @ObjectType('FormFieldOption') export class FormFieldOptionModel { + readonly _id: number + @Field(() => ID) readonly id: string @@ -15,8 +17,9 @@ export class FormFieldOptionModel { @Field() readonly value: string - constructor(option: FormFieldOptionEntity) { - this.id = option.id.toString() + constructor(id: string, option: FormFieldOptionEntity) { + this._id = option.id + this.id = id this.key = option.key this.title = option.title this.value = option.value diff --git a/src/dto/form/form.hook.model.ts b/src/dto/form/form.hook.model.ts index 2335688..8df37c3 100644 --- a/src/dto/form/form.hook.model.ts +++ b/src/dto/form/form.hook.model.ts @@ -3,6 +3,8 @@ import { FormHookEntity } from '../../entity/form.hook.entity' @ObjectType('FormHook') export class FormHookModel { + readonly _id: number + @Field(() => ID) readonly id: string @@ -15,8 +17,9 @@ export class FormHookModel { @Field({ nullable: true }) readonly format?: string - constructor(hook: FormHookEntity) { - this.id = hook.id.toString() + constructor(id, hook: FormHookEntity) { + this._id = hook.id + this.id = id this.enabled = hook.enabled this.url = hook.url this.format = hook.format diff --git a/src/dto/form/form.notification.model.ts b/src/dto/form/form.notification.model.ts index 2d2a866..9d05c19 100644 --- a/src/dto/form/form.notification.model.ts +++ b/src/dto/form/form.notification.model.ts @@ -3,6 +3,8 @@ import { FormNotificationEntity } from '../../entity/form.notification.entity' @ObjectType('FormNotification') export class FormNotificationModel { + readonly _id: number + @Field(() => ID) readonly id: string @@ -27,8 +29,9 @@ export class FormNotificationModel { @Field() readonly enabled: boolean - constructor(partial: Partial) { - this.id = partial.id.toString() + constructor(id: string, partial: Partial) { + this._id = partial.id + this.id = id this.subject = partial.subject this.htmlTemplate = partial.htmlTemplate this.enabled = partial.enabled diff --git a/src/dto/form/page.model.ts b/src/dto/form/page.model.ts index 158c3e1..c20c183 100644 --- a/src/dto/form/page.model.ts +++ b/src/dto/form/page.model.ts @@ -1,9 +1,10 @@ import { Field, ID, ObjectType } from '@nestjs/graphql' import { PageEntity } from '../../entity/page.entity' -import { ButtonModel } from './button.model' @ObjectType('Page') export class PageModel { + readonly _id: number + @Field(() => ID) readonly id: string @@ -19,22 +20,18 @@ export class PageModel { @Field({ nullable: true }) readonly buttonText?: string - @Field(() => [ButtonModel]) - readonly buttons: ButtonModel[] - - constructor(page: Partial) { + constructor(id: string, page?: Partial) { if (!page) { - this.id = Math.random().toString() + this.id = id this.show = false - this.buttons = [] return } - this.id = page.id.toString() + this._id = page.id + this.id = id this.show = page.show this.title = page.title this.paragraph = page.paragraph this.buttonText = page.buttonText - this.buttons = (page.buttons || []).map(button => new ButtonModel(button)) } } diff --git a/src/resolver/form/form.resolver.ts b/src/resolver/form/form.resolver.ts index de98149..a3cadfa 100644 --- a/src/resolver/form/form.resolver.ts +++ b/src/resolver/form/form.resolver.ts @@ -9,6 +9,7 @@ import { FormNotificationModel } from '../../dto/form/form.notification.model' import { PageModel } from '../../dto/form/page.model' import { UserModel } from '../../dto/user/user.model' import { FormEntity } from '../../entity/form.entity' +import { PageEntity } from '../../entity/page.entity' import { UserEntity } from '../../entity/user.entity' import { FormService } from '../../service/form/form.service' import { IdService } from '../../service/id.service' @@ -55,7 +56,14 @@ export class FormResolver { throw new Error('no access to field') } - return form.hooks?.map(hook => new FormHookModel(hook)) || [] + if (!form.hooks) { + return [] + } + + return form.hooks.map(hook => new FormHookModel( + this.idService.encode(hook.id), + hook + )) } @ResolveField(() => Boolean) @@ -87,7 +95,14 @@ export class FormResolver { throw new Error('no access to field') } - return form.notifications?.map(notification => new FormNotificationModel(notification)) || [] + if (!form.notifications) { + return [] + } + + return form.notifications.map(notification => new FormNotificationModel( + this.idService.encode(notification.id), + notification + )) } @ResolveField(() => DesignModel) @@ -106,9 +121,21 @@ export class FormResolver { @Parent() parent: FormModel, @Context('cache') cache: ContextCache, ): Promise { - const form = await cache.get(cache.getCacheKey(FormEntity.name, parent._id)) + const { startPage } = await cache.get(cache.getCacheKey( + FormEntity.name, + parent._id + )) - return new PageModel(form.startPage) + if (startPage) { + cache.add(cache.getCacheKey(PageEntity.name, startPage.id), startPage) + + return new PageModel( + this.idService.encode(startPage.id), + startPage + ) + } + + return new PageModel(Math.random().toString()) } @ResolveField(() => PageModel) @@ -116,9 +143,18 @@ export class FormResolver { @Parent() parent: FormModel, @Context('cache') cache: ContextCache, ): Promise { - const form = await cache.get(cache.getCacheKey(FormEntity.name, parent._id)) + const { endPage } = await cache.get(cache.getCacheKey(FormEntity.name, parent._id)) - return new PageModel(form.endPage) + if (endPage) { + cache.add(cache.getCacheKey(PageEntity.name, endPage.id), endPage) + + return new PageModel( + this.idService.encode(endPage.id), + endPage + ) + } + + return new PageModel(Math.random().toString()) } @ResolveField(() => UserModel, { nullable: true }) diff --git a/src/resolver/form/index.ts b/src/resolver/form/index.ts index 440848f..82c01b9 100644 --- a/src/resolver/form/index.ts +++ b/src/resolver/form/index.ts @@ -6,6 +6,7 @@ import { FormResolver } from './form.resolver' import { FormStatisticQuery } from './form.statistic.query' import { FormStatisticResolver } from './form.statistic.resolver' import { FormUpdateMutation } from './form.update.mutation' +import { PageResolver } from './page.resolver' export const formResolvers = [ FormCreateMutation, @@ -16,4 +17,5 @@ export const formResolvers = [ FormStatisticQuery, FormStatisticResolver, FormUpdateMutation, + PageResolver, ] diff --git a/src/resolver/form/page.resolver.ts b/src/resolver/form/page.resolver.ts new file mode 100644 index 0000000..e157328 --- /dev/null +++ b/src/resolver/form/page.resolver.ts @@ -0,0 +1,32 @@ +import { Context, Parent, ResolveField, Resolver } from '@nestjs/graphql' +import { ButtonModel } from '../../dto/form/button.model' +import { FormModel } from '../../dto/form/form.model' +import { PageModel } from '../../dto/form/page.model' +import { PageEntity } from '../../entity/page.entity' +import { IdService } from '../../service/id.service' +import { ContextCache } from '../context.cache' + +@Resolver(() => PageModel) +export class PageResolver { + constructor( + private readonly idService: IdService, + ) { + } + + @ResolveField(() => [ButtonModel]) + async buttons( + @Parent() parent: FormModel, + @Context('cache') cache: ContextCache, + ): Promise { + if (!parent._id) { + return [] + } + + const page = await cache.get(cache.getCacheKey(PageEntity.name, parent._id)) + + return page.buttons.map(button => new ButtonModel( + this.idService.encode(button.id), + button + )) + } +} diff --git a/src/service/form/form.update.service.ts b/src/service/form/form.update.service.ts index 19ca4d1..9e64ff2 100644 --- a/src/service/form/form.update.service.ts +++ b/src/service/form/form.update.service.ts @@ -10,6 +10,7 @@ import { FormHookEntity } from '../../entity/form.hook.entity' import { FormNotificationEntity } from '../../entity/form.notification.entity' import { PageButtonEntity } from '../../entity/page.button.entity' import { PageEntity } from '../../entity/page.entity' +import { IdService } from '../id.service' @Injectable() export class FormUpdateService { @@ -20,6 +21,7 @@ export class FormUpdateService { private readonly formFieldRepository: Repository, @InjectRepository(FormHookEntity) private readonly formHookRepository: Repository, + private readonly idService: IdService, ) { } @@ -347,12 +349,12 @@ export class FormUpdateService { return form } - private findByIdInList(list: T[], id: string, fallback: T): T { + private findByIdInList(list: T[], id: string, fallback: T): T { if (!list) { return fallback } - const found = list.find((value: any) => String(value.id) === String(id)) + const found = list.find((value) => value.id === this.idService.decode(id)) if (found) { return found