From 356ebb80c1d5488a7902e8a868515508f5a403c3 Mon Sep 17 00:00:00 2001 From: Michael Schramm Date: Sat, 1 May 2021 10:32:51 +0200 Subject: [PATCH] update for sql based backend --- doc/environment.md | 3 + src/dto/form/button.input.ts | 5 +- src/dto/form/button.model.ts | 6 +- src/dto/form/colors.model.ts | 12 +- src/dto/form/form.field.input.ts | 3 + src/dto/form/form.field.logic.input.ts | 3 + src/dto/form/form.field.option.input.ts | 5 +- src/dto/form/form.field.option.model.ts | 6 +- src/dto/form/form.notification.input.ts | 5 +- src/dto/form/form.notification.model.ts | 8 +- src/dto/form/page.input.ts | 5 +- src/dto/form/page.model.ts | 16 +- src/entity/form.entity.ts | 10 +- src/entity/form.field.entity.ts | 4 +- src/entity/form.notification.entity.ts | 14 +- src/entity/page.button.entity.ts | 12 +- src/entity/page.entity.ts | 12 +- src/resolver/form/form.query.ts | 2 +- src/resolver/form/form.resolver.ts | 5 - src/resolver/form/form.search.resolver.ts | 4 +- src/resolver/form/index.ts | 2 + src/service/auth/auth.service.ts | 2 + src/service/form/form.create.service.ts | 6 +- src/service/form/form.service.ts | 6 + src/service/form/form.update.service.ts | 200 ++++++++++++++++++---- 25 files changed, 269 insertions(+), 87 deletions(-) diff --git a/doc/environment.md b/doc/environment.md index 40d9919..f7904a2 100644 --- a/doc/environment.md +++ b/doc/environment.md @@ -6,6 +6,9 @@ | SECRET_KEY | `changeMe` | JWT Secret for authentication | | CLI | *automatically* | activates pretty print for log output | | NODE_ENV | `production` | | +| HIDE_CONTRIB | `false` | decide if backlings to ohmyform should be added | +| SIGNUP_DISABLED | `false` | if users can sign up | +| LOGIN_NOTE | *not set* | Info box on top of login screen | ## Mailing diff --git a/src/dto/form/button.input.ts b/src/dto/form/button.input.ts index 63c4d33..230afe4 100644 --- a/src/dto/form/button.input.ts +++ b/src/dto/form/button.input.ts @@ -1,7 +1,10 @@ -import { Field, InputType } from '@nestjs/graphql' +import { Field, ID, InputType } from '@nestjs/graphql' @InputType() export class ButtonInput { + @Field(() => ID, { nullable: true }) + readonly id?: string + @Field({ nullable: true }) readonly url?: string diff --git a/src/dto/form/button.model.ts b/src/dto/form/button.model.ts index 3561d9f..aabb1b8 100644 --- a/src/dto/form/button.model.ts +++ b/src/dto/form/button.model.ts @@ -1,8 +1,11 @@ -import { Field, ObjectType } from '@nestjs/graphql' +import { Field, ID, ObjectType } from '@nestjs/graphql' import { PageButtonEntity } from '../../entity/page.button.entity' @ObjectType('Button') export class ButtonModel { + @Field(() => ID) + readonly id: string + @Field({ nullable: true }) readonly url?: string @@ -22,6 +25,7 @@ export class ButtonModel { readonly color?: string constructor(button: Partial) { + this.id = button.id.toString() this.url = button.url this.action = button.action this.text = button.text diff --git a/src/dto/form/colors.model.ts b/src/dto/form/colors.model.ts index 78de467..b73afc8 100644 --- a/src/dto/form/colors.model.ts +++ b/src/dto/form/colors.model.ts @@ -22,11 +22,11 @@ export class ColorsModel { readonly buttonText: string constructor(partial: Partial) { - this.background = partial.background - this.question = partial.question - this.answer = partial.answer - this.button = partial.button - this.buttonActive = partial.buttonActive - this.buttonText = partial.buttonText + this.background = partial.background ?? '#fff' + this.question = partial.question ?? '#333' + this.answer = partial.answer ?? '#333' + this.button = partial.button ?? '#fff' + this.buttonActive = partial.buttonActive ?? '#40a9ff' + this.buttonText = partial.buttonText ?? '#666' } } diff --git a/src/dto/form/form.field.input.ts b/src/dto/form/form.field.input.ts index 47b9ed6..0ac3cb1 100644 --- a/src/dto/form/form.field.input.ts +++ b/src/dto/form/form.field.input.ts @@ -27,6 +27,9 @@ export class FormFieldInput { @Field() readonly value: string + @Field({ nullable: true }) + readonly disabled?: boolean + @Field(() => [FormFieldOptionInput], { nullable: true }) readonly options: FormFieldOptionInput[] diff --git a/src/dto/form/form.field.logic.input.ts b/src/dto/form/form.field.logic.input.ts index 0f0423c..b3f844e 100644 --- a/src/dto/form/form.field.logic.input.ts +++ b/src/dto/form/form.field.logic.input.ts @@ -2,6 +2,9 @@ import { Field, ID, InputType } from '@nestjs/graphql' @InputType() export class FormFieldLogicInput { + @Field(() => ID, { nullable: true }) + readonly id?: string + @Field({ nullable: true }) readonly formula: string diff --git a/src/dto/form/form.field.option.input.ts b/src/dto/form/form.field.option.input.ts index f13315a..d730ad4 100644 --- a/src/dto/form/form.field.option.input.ts +++ b/src/dto/form/form.field.option.input.ts @@ -1,7 +1,10 @@ -import { Field, InputType } from '@nestjs/graphql' +import { Field, ID, InputType } from '@nestjs/graphql' @InputType() export class FormFieldOptionInput { + @Field(() => ID, { nullable: true }) + readonly id?: string + @Field({ nullable: true }) readonly key: string diff --git a/src/dto/form/form.field.option.model.ts b/src/dto/form/form.field.option.model.ts index 8b1f447..cb3c714 100644 --- a/src/dto/form/form.field.option.model.ts +++ b/src/dto/form/form.field.option.model.ts @@ -1,8 +1,11 @@ -import { Field, ObjectType } from '@nestjs/graphql' +import { Field, ID, ObjectType } from '@nestjs/graphql' import { FormFieldOptionEntity } from '../../entity/form.field.option.entity' @ObjectType('FormFieldOption') export class FormFieldOptionModel { + @Field(() => ID) + readonly id: string + @Field({ nullable: true }) readonly key: string @@ -13,6 +16,7 @@ export class FormFieldOptionModel { readonly value: string constructor(option: FormFieldOptionEntity) { + this.id = option.id.toString() this.key = option.key this.title = option.title this.value = option.value diff --git a/src/dto/form/form.notification.input.ts b/src/dto/form/form.notification.input.ts index afabd33..dc4b251 100644 --- a/src/dto/form/form.notification.input.ts +++ b/src/dto/form/form.notification.input.ts @@ -1,7 +1,10 @@ -import { Field, InputType } from '@nestjs/graphql' +import { Field, ID, InputType } from '@nestjs/graphql' @InputType('FormNotificationInput') export class FormNotificationInput { + @Field(() => ID, { nullable: true }) + readonly id?: string + @Field({ nullable: true }) readonly subject?: string diff --git a/src/dto/form/form.notification.model.ts b/src/dto/form/form.notification.model.ts index 62943b9..83e5114 100644 --- a/src/dto/form/form.notification.model.ts +++ b/src/dto/form/form.notification.model.ts @@ -1,8 +1,11 @@ -import { Field, InterfaceType } from '@nestjs/graphql' +import { Field, ID, InterfaceType, ObjectType } from '@nestjs/graphql' import { FormNotificationEntity } from '../../entity/form.notification.entity' -@InterfaceType('FormNotification') +@ObjectType('FormNotification') export class FormNotificationModel { + @Field(() => ID) + readonly id: string + @Field({ nullable: true }) readonly subject?: string @@ -25,6 +28,7 @@ export class FormNotificationModel { readonly enabled: boolean constructor(partial: Partial) { + this.id = partial.id.toString() this.subject = partial.subject this.htmlTemplate = partial.htmlTemplate this.enabled = partial.enabled diff --git a/src/dto/form/page.input.ts b/src/dto/form/page.input.ts index 8768ea1..9f63984 100644 --- a/src/dto/form/page.input.ts +++ b/src/dto/form/page.input.ts @@ -1,8 +1,11 @@ -import { Field, InputType } from '@nestjs/graphql' +import { Field, ID, InputType } from '@nestjs/graphql' import { ButtonInput } from './button.input' @InputType() export class PageInput { + @Field(() => ID, { nullable: true }) + readonly id?: string + @Field() readonly show: boolean diff --git a/src/dto/form/page.model.ts b/src/dto/form/page.model.ts index baa4735..da3c441 100644 --- a/src/dto/form/page.model.ts +++ b/src/dto/form/page.model.ts @@ -1,9 +1,13 @@ -import { Field, ObjectType } from '@nestjs/graphql' +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { randomBytes } from 'crypto' import { PageEntity } from '../../entity/page.entity' import { ButtonModel } from './button.model' @ObjectType('Page') export class PageModel { + @Field(() => ID) + readonly id: string + @Field() readonly show: boolean @@ -20,10 +24,18 @@ export class PageModel { readonly buttons: ButtonModel[] constructor(page: Partial) { + if (!page) { + this.id = Math.random().toString() + this.show = false + this.buttons = [] + return + } + + this.id = page.id.toString() 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)) + this.buttons = (page.buttons || []).map(button => new ButtonModel(button)) } } diff --git a/src/entity/form.entity.ts b/src/entity/form.entity.ts index 67b2ebd..9b8bedb 100644 --- a/src/entity/form.entity.ts +++ b/src/entity/form.entity.ts @@ -37,22 +37,22 @@ export class FormEntity { @OneToMany(() => SubmissionEntity, submission => submission.form) public submissions: SubmissionEntity[] - @OneToMany(() => FormFieldEntity, field => field.form, { eager: true, orphanedRowAction: 'delete' }) + @OneToMany(() => FormFieldEntity, field => field.form, { eager: true, orphanedRowAction: 'delete', cascade: true }) public fields: FormFieldEntity[] - @OneToMany(() => FormHookEntity, field => field.form, { eager: true, orphanedRowAction: 'delete' }) + @OneToMany(() => FormHookEntity, field => field.form, { eager: true, orphanedRowAction: 'delete', cascade: true }) public hooks: FormHookEntity[] @ManyToOne(() => UserEntity, { eager: true }) public admin: UserEntity - @ManyToOne(() => PageEntity, { eager: true }) + @ManyToOne(() => PageEntity, { eager: true, cascade: true }) public startPage: PageEntity; - @ManyToOne(() => PageEntity, { eager: true }) + @ManyToOne(() => PageEntity, { eager: true, cascade: true }) public endPage: PageEntity; - @OneToMany(() => FormNotificationEntity, notification => notification.form, { eager: true, orphanedRowAction: 'delete' }) + @OneToMany(() => FormNotificationEntity, notification => notification.form, { eager: true, orphanedRowAction: 'delete', cascade: true }) public notifications: FormNotificationEntity[] @Column() diff --git a/src/entity/form.field.entity.ts b/src/entity/form.field.entity.ts index a014073..50a68a3 100644 --- a/src/entity/form.field.entity.ts +++ b/src/entity/form.field.entity.ts @@ -33,8 +33,8 @@ export class FormFieldEntity { @Column() public required: boolean - @Column() - public disabled: boolean + @Column({ type: 'boolean' }) + public disabled = false @Column() public type: string diff --git a/src/entity/form.notification.entity.ts b/src/entity/form.notification.entity.ts index f529f72..2d71e02 100644 --- a/src/entity/form.notification.entity.ts +++ b/src/entity/form.notification.entity.ts @@ -11,23 +11,23 @@ export class FormNotificationEntity { public form: FormEntity @Column({ nullable: true }) - readonly subject?: string + public subject?: string @Column({ nullable: true }) - readonly htmlTemplate?: string + public htmlTemplate?: string @Column() - readonly enabled: boolean + public enabled: boolean @ManyToOne(() => FormFieldEntity) - readonly fromField?: FormFieldEntity + public fromField?: FormFieldEntity @ManyToOne(() => FormFieldEntity) - readonly toField?: FormFieldEntity + public toField?: FormFieldEntity @Column({ nullable: true }) - readonly toEmail?: string + public toEmail?: string @Column({ nullable: true }) - readonly fromEmail?: string + public fromEmail?: string } diff --git a/src/entity/page.button.entity.ts b/src/entity/page.button.entity.ts index db7c1c7..399af1c 100644 --- a/src/entity/page.button.entity.ts +++ b/src/entity/page.button.entity.ts @@ -10,20 +10,20 @@ export class PageButtonEntity { public page: PageEntity @Column({ nullable: true }) - readonly url?: string + public url?: string @Column({ nullable: true }) - readonly action?: string + public action?: string @Column() - readonly text: string + public text: string @Column({ nullable: true }) - readonly bgColor?: string + public bgColor?: string @Column({ nullable: true }) - readonly activeColor?: string + public activeColor?: string @Column({ nullable: true }) - readonly color?: string + public color?: string } diff --git a/src/entity/page.entity.ts b/src/entity/page.entity.ts index 2aa1a98..25612a3 100644 --- a/src/entity/page.entity.ts +++ b/src/entity/page.entity.ts @@ -7,17 +7,17 @@ export class PageEntity { public id: number @Column() - readonly show: boolean + public show: boolean @Column({ nullable: true }) - readonly title?: string + public title?: string @Column({ type: 'text', nullable: true }) - readonly paragraph?: string + public paragraph?: string @Column({ nullable: true }) - readonly buttonText?: string + public buttonText?: string - @OneToMany(() => PageButtonEntity, button => button.page) - readonly buttons: PageButtonEntity[] + @OneToMany(() => PageButtonEntity, button => button.page, { eager: true, orphanedRowAction: 'delete', cascade: true }) + public buttons: PageButtonEntity[] } diff --git a/src/resolver/form/form.query.ts b/src/resolver/form/form.query.ts index 32fdeaa..8b8e9ef 100644 --- a/src/resolver/form/form.query.ts +++ b/src/resolver/form/form.query.ts @@ -14,7 +14,7 @@ import { FormService } from '../../service/form/form.service' import { ContextCache } from '../context.cache' @Resolver(() => FormModel) -export class FormResolver { +export class FormQuery { constructor( private readonly formService: FormService, ) { diff --git a/src/resolver/form/form.resolver.ts b/src/resolver/form/form.resolver.ts index 207394b..56ccb73 100644 --- a/src/resolver/form/form.resolver.ts +++ b/src/resolver/form/form.resolver.ts @@ -113,11 +113,6 @@ export class FormResolver { ): Promise { const form = await cache.get(cache.getCacheKey(FormEntity.name, parent.id)) - if (!form.populated('admin')) { - form.populate('admin') - await form.execPopulate() - } - if (!form.admin) { return null } diff --git a/src/resolver/form/form.search.resolver.ts b/src/resolver/form/form.search.resolver.ts index 45eb832..25e7d74 100644 --- a/src/resolver/form/form.search.resolver.ts +++ b/src/resolver/form/form.search.resolver.ts @@ -1,5 +1,6 @@ import { Args, Context, Query, Resolver } from '@nestjs/graphql' import { GraphQLInt } from 'graphql' +import { Roles } from '../../decorator/roles.decorator' import { User } from '../../decorator/user.decorator' import { FormModel } from '../../dto/form/form.model' import { FormPagerModel } from '../../dto/form/form.pager.model' @@ -16,12 +17,13 @@ export class FormSearchResolver { } @Query(() => FormPagerModel) + @Roles('user') async listForms( @User() user: UserEntity, @Args('start', {type: () => GraphQLInt, defaultValue: 0, nullable: true}) start: number, @Args('limit', {type: () => GraphQLInt, defaultValue: 50, nullable: true}) limit: number, @Context('cache') cache: ContextCache, - ) { + ): Promise { const [forms, total] = await this.formService.find( start, limit, diff --git a/src/resolver/form/index.ts b/src/resolver/form/index.ts index fd3c151..2231cf8 100644 --- a/src/resolver/form/index.ts +++ b/src/resolver/form/index.ts @@ -1,5 +1,6 @@ import { FormCreateMutation } from './form.create.mutation' import { FormDeleteMutation } from './form.delete.mutation' +import { FormQuery } from './form.query' import { FormResolver } from './form.resolver' import { FormSearchResolver } from './form.search.resolver' import { FormStatisticResolver } from './form.statistic.resolver' @@ -8,6 +9,7 @@ import { FormUpdateMutation } from './form.update.mutation' export const formResolvers = [ FormCreateMutation, FormDeleteMutation, + FormQuery, FormResolver, FormSearchResolver, FormStatisticResolver, diff --git a/src/service/auth/auth.service.ts b/src/service/auth/auth.service.ts index 127ccba..930bda6 100644 --- a/src/service/auth/auth.service.ts +++ b/src/service/auth/auth.service.ts @@ -36,6 +36,8 @@ export class AuthService { username: user.username, roles: user.roles, sub: user.id, + }, { + expiresIn: '4h', }), refreshToken: this.jwtService.sign({ sub: user.id, diff --git a/src/service/form/form.create.service.ts b/src/service/form/form.create.service.ts index db742ae..580cec0 100644 --- a/src/service/form/form.create.service.ts +++ b/src/service/form/form.create.service.ts @@ -17,9 +17,9 @@ export class FormCreateService { const form = new FormEntity() form.title = input.title - form.isLive = input.isLive - form.showFooter = input.showFooter - form.language = input.language + form.isLive = Boolean(input.isLive) + form.showFooter = Boolean(input.showFooter) + form.language = input.language || 'en' form.admin = admin diff --git a/src/service/form/form.service.ts b/src/service/form/form.service.ts index 28d9e58..5eef386 100644 --- a/src/service/form/form.service.ts +++ b/src/service/form/form.service.ts @@ -13,6 +13,10 @@ export class FormService { } async isAdmin(form: FormEntity, user: UserEntity): Promise { + if (!user) { + return false + } + if (user.roles.includes('superuser')) { return true } @@ -23,6 +27,8 @@ export class FormService { async find(start: number, limit: number, sort: any = {}, user?: UserEntity): Promise<[FormEntity[], number]> { const qb = this.formRepository.createQueryBuilder('f') + qb.leftJoinAndSelect('f.admin', 'a') + if (user) { qb.where('f.admin = :user', { user: user.id }) } diff --git a/src/service/form/form.update.service.ts b/src/service/form/form.update.service.ts index cf86ad2..e317b62 100644 --- a/src/service/form/form.update.service.ts +++ b/src/service/form/form.update.service.ts @@ -4,7 +4,12 @@ import { Repository } from 'typeorm' import { FormUpdateInput } from '../../dto/form/form.update.input' import { FormEntity } from '../../entity/form.entity' import { FormFieldEntity } from '../../entity/form.field.entity' +import { FormFieldLogicEntity } from '../../entity/form.field.logic.entity' +import { FormFieldOptionEntity } from '../../entity/form.field.option.entity' 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' @Injectable() export class FormUpdateService { @@ -35,36 +40,83 @@ export class FormUpdateService { form.isLive = input.isLive } - const fieldMapping = {} - if (input.fields !== undefined) { form.fields = await Promise.all(input.fields.map(async (nextField) => { - let field = form.fields.find(field => field.id.toString() === nextField.id) + let field = form.fields.find(field => field.id?.toString() === nextField.id) if (!field) { field = new FormFieldEntity() field.type = nextField.type } - // ability for other fields to apply mapping - fieldMapping[nextField.id] = field.id.toString() - field.title = nextField.title - field.description = nextField.description - field.required = nextField.required - field.value = nextField.value + if (nextField.title !== undefined) { + field.title = nextField.title + } + + if (nextField.description !== undefined) { + field.description = nextField.description + } + + if (nextField.disabled !== undefined) { + field.disabled = nextField.disabled + } + + if (nextField.required !== undefined) { + field.required = nextField.required + } + + if (nextField.value !== undefined) { + field.value = nextField.value + } if (nextField.slug !== undefined) { field.slug = nextField.slug } if (nextField.logic !== undefined) { - // TODO prepare logic entries - // field.logicJump = nextField.logicJump + field.logic = nextField.logic.map(nextLogic => { + const logic = field.logic?.find(logic => logic.id?.toString() === nextLogic.id) || new FormFieldLogicEntity() + + logic.field = field + + if (nextLogic.formula !== undefined) { + logic.formula = nextLogic.formula + } + if (nextLogic.action !== undefined) { + logic.action = nextLogic.action as any + } + if (nextLogic.visible !== undefined) { + logic.visible = nextLogic.visible + } + if (nextLogic.require !== undefined) { + logic.require = nextLogic.require + } + if (nextLogic.disable !== undefined) { + logic.disable = nextLogic.disable + } + if (nextLogic.jumpTo !== undefined) { + logic.jumpTo = form.fields.find(value => value.id?.toString() === nextLogic.jumpTo) + } + if (nextLogic.enabled !== undefined) { + logic.enabled = nextLogic.enabled + } + + return logic + }) } if (nextField.options !== undefined) { - // TODO prepare options - // field.options = nextField.options + field.options = nextField.options.map(nextOption => { + const option = field.options?.find(option => option.id?.toString() === nextOption.id) || new FormFieldOptionEntity() + + option.field = field + + option.title = nextOption.title + option.value = nextOption.value + option.key = nextOption.key + + return option + }) } if (nextField.rating !== undefined) { @@ -78,11 +130,7 @@ export class FormUpdateService { if (input.hooks !== undefined) { form.hooks = input.hooks.map((nextHook) => { - let hook = form.hooks && form.hooks.find(hook => hook.id.toString() === nextHook.id) - - if (!hook) { - hook = new FormHookEntity() - } + const hook = form.hooks?.find(hook => hook.id?.toString() === nextHook.id) || new FormHookEntity() // ability for other fields to apply mapping hook.url = nextHook.url @@ -97,14 +145,6 @@ export class FormUpdateService { } - const extractField = (id) => { - if (id && fieldMapping[id]) { - return fieldMapping[id] - } - - return null - } - if (input.design !== undefined) { if (input.design.font !== undefined) { form.design.font = input.design.font @@ -132,14 +172,38 @@ export class FormUpdateService { } } - /* - if (input.selfNotifications !== undefined) { - form.set('selfNotifications', { - ...input.selfNotifications, - fromField: extractField(input.selfNotifications.fromField) + + if (input.notifications !== undefined) { + form.notifications = input.notifications.map(notificationInput => { + const notification = form.notifications?.find(value => value.id?.toString() === notificationInput.id) || new FormNotificationEntity() + + notification.form = form + notification.enabled = notificationInput.enabled + + if (notificationInput.fromEmail !== undefined) { + notification.fromEmail = notificationInput.fromEmail + } + if (notificationInput.fromField !== undefined) { + notification.fromField = form.fields.find(value => value.id?.toString() === notificationInput.fromField) + } + if (notificationInput.subject !== undefined) { + notification.subject = notificationInput.subject + } + if (notificationInput.htmlTemplate !== undefined) { + notification.htmlTemplate = notificationInput.htmlTemplate + } + if (notificationInput.toEmail !== undefined) { + notification.toEmail = notificationInput.toEmail + } + if (notificationInput.toField !== undefined) { + notification.toField = form.fields.find(value => value.id?.toString() === notificationInput.toField) + } + + return notification }) } + /* if (input.respondentNotifications !== undefined) { form.set('respondentNotifications', { ...input.respondentNotifications, @@ -149,13 +213,79 @@ export class FormUpdateService { */ if (input.startPage !== undefined) { - // TODO fix start page - // form.set('startPage', input.startPage) + if (!form.startPage) { + form.startPage = new PageEntity() + form.startPage.show = false + } + + if (input.startPage.show !== undefined) { + form.startPage.show = input.startPage.show + } + + if (input.startPage.title !== undefined) { + form.startPage.title = input.startPage.title + } + + if (input.startPage.paragraph !== undefined) { + form.startPage.paragraph = input.startPage.paragraph + } + + if (input.startPage.buttonText !== undefined) { + form.startPage.buttonText = input.startPage.buttonText + } + + if (input.startPage.buttons !== undefined) { + form.startPage.buttons = input.startPage.buttons.map(buttonInput => { + const entity = form.startPage?.buttons?.find(value => value.id?.toString() === buttonInput.id) || new PageButtonEntity() + entity.page = form.startPage + entity.url = buttonInput.url + entity.action = buttonInput.action + entity.text = buttonInput.text + entity.color = buttonInput.color + entity.bgColor = buttonInput.bgColor + entity.activeColor = buttonInput.activeColor + + return entity + }) + } } if (input.endPage !== undefined) { - // TODO fix end page - // form.set('endPage', input.endPage) + if (!form.endPage) { + form.endPage = new PageEntity() + form.endPage.show = false + } + + if (input.endPage.show !== undefined) { + form.endPage.show = input.endPage.show + } + + if (input.endPage.title !== undefined) { + form.endPage.title = input.endPage.title + } + + if (input.endPage.paragraph !== undefined) { + form.endPage.paragraph = input.endPage.paragraph + } + + if (input.endPage.buttonText !== undefined) { + form.endPage.buttonText = input.endPage.buttonText + } + + if (input.endPage.buttons !== undefined) { + form.endPage.buttons = input.endPage.buttons.map(buttonInput => { + const entity = form.endPage?.buttons?.find(value => value.id?.toString() === buttonInput.id) || new PageButtonEntity() + entity.page = form.endPage + entity.url = buttonInput.url + entity.action = buttonInput.action + entity.text = buttonInput.text + entity.color = buttonInput.color + entity.bgColor = buttonInput.bgColor + entity.activeColor = buttonInput.activeColor + + return entity + }) + } } await this.formRepository.save(form)