fixup! add most entity for switch to sql

This commit is contained in:
Michael Schramm 2021-04-30 15:21:48 +02:00
parent 8d05f15b4c
commit 93b6596b1b
171 changed files with 1723 additions and 2545 deletions

21
ormconfig_pg.json Normal file
View File

@ -0,0 +1,21 @@
{
"type": "postgres",
"host": "localhost",
"username": "root",
"password": "root",
"database": "ohmyform",
"synchronize": true,
"logging": false,
"entities": [
"src/entity/**/*.ts"
],
"migrations": [
"src/migrations/**/*.ts"
],
"subscribers": [
"src/subscriber/**/*.ts"
],
"cli": {
"migrationsDir": "src/migrations"
}
}

15
ormconfig_sqlite.json Normal file
View File

@ -0,0 +1,15 @@
{
"type": "sqlite",
"database": "data.sqlite",
"synchronize": true,
"logging": false,
"entities": [
"src/entity/**/*.ts"
],
"migrations": [
"src/migrations/**/*.ts"
],
"cli": {
"migrationsDir": "src/migrations"
}
}

View File

@ -24,13 +24,13 @@
"typeorm:pg": "cross-env TS_NODE_TRANSPILE_ONLY=true ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js -f ormconfig_pg.json" "typeorm:pg": "cross-env TS_NODE_TRANSPILE_ONLY=true ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js -f ormconfig_pg.json"
}, },
"dependencies": { "dependencies": {
"@apollo/gateway": "^0.27.1",
"@nestjs-modules/mailer": "^1.6.0", "@nestjs-modules/mailer": "^1.6.0",
"@nestjs/common": "^7.6.15", "@nestjs/common": "^7.6.15",
"@nestjs/config": "^0.6.3", "@nestjs/config": "^0.6.3",
"@nestjs/core": "^7.6.15", "@nestjs/core": "^7.6.15",
"@nestjs/graphql": "^7.10.6", "@nestjs/graphql": "^7.10.6",
"@nestjs/jwt": "^7.2.0", "@nestjs/jwt": "^7.2.0",
"@nestjs/mongoose": "^7.2.4",
"@nestjs/passport": "^7.1.5", "@nestjs/passport": "^7.1.5",
"@nestjs/platform-express": "^7.6.15", "@nestjs/platform-express": "^7.6.15",
"@nestjs/serve-static": "^2.1.4", "@nestjs/serve-static": "^2.1.4",
@ -52,9 +52,7 @@
"inquirer": "^8.0.0", "inquirer": "^8.0.0",
"ioredis": "^4.27.1", "ioredis": "^4.27.1",
"matomo-tracker": "^2.2.4", "matomo-tracker": "^2.2.4",
"migrate-mongoose": "^4.0.0",
"mjml": "^4.9.1", "mjml": "^4.9.1",
"mongoose": "^5.12.6",
"mysql2": "^2.2.5", "mysql2": "^2.2.5",
"nestjs-console": "^4.0.0", "nestjs-console": "^4.0.0",
"nestjs-pino": "^1.4.0", "nestjs-pino": "^1.4.0",
@ -75,13 +73,11 @@
"@nestjs/schematics": "^7.3.1", "@nestjs/schematics": "^7.3.1",
"@nestjs/testing": "^7.6.15", "@nestjs/testing": "^7.6.15",
"@types/bcrypt": "^3.0.1", "@types/bcrypt": "^3.0.1",
"@types/express": "^4.17.11",
"@types/express-serve-static-core": "^4.17.19", "@types/express-serve-static-core": "^4.17.19",
"@types/handlebars": "^4.1.0", "@types/handlebars": "^4.1.0",
"@types/html-to-text": "^6.0.0", "@types/html-to-text": "^6.0.0",
"@types/inquirer": "^7.3.1", "@types/inquirer": "^7.3.1",
"@types/jest": "26.0.23", "@types/jest": "26.0.23",
"@types/mongoose": "^5.10.5",
"@types/node": "^15.0.1", "@types/node": "^15.0.1",
"@types/passport-jwt": "^3.0.5", "@types/passport-jwt": "^3.0.5",
"@types/passport-local": "^1.0.33", "@types/passport-local": "^1.0.33",

View File

@ -1,21 +1,17 @@
import { MailerModule } from '@nestjs-modules/mailer'; import { MailerModule } from '@nestjs-modules/mailer'
import { HttpModule, RequestMethod } from '@nestjs/common'; import { HttpModule, RequestMethod } from '@nestjs/common'
import { ConfigModule, ConfigService } from '@nestjs/config'; import { ConfigModule, ConfigService } from '@nestjs/config'
import { GraphQLModule } from '@nestjs/graphql'; import { GraphQLModule } from '@nestjs/graphql'
import { JwtModule, JwtModuleOptions } from '@nestjs/jwt'; import { JwtModule, JwtModuleOptions } from '@nestjs/jwt'
import { MongooseModule } from '@nestjs/mongoose'; import { ServeStaticModule } from '@nestjs/serve-static'
import { MongooseModuleOptions } from '@nestjs/mongoose/dist/interfaces/mongoose-options.interface';
import { ServeStaticModule } from '@nestjs/serve-static';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm' import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm'
import crypto from 'crypto'; import crypto from 'crypto'
import { Request } from 'express-serve-static-core'; import { Request } from 'express-serve-static-core'
import { IncomingHttpHeaders } from 'http'; import { IncomingHttpHeaders } from 'http'
import { ConsoleModule } from 'nestjs-console'; import { ConsoleModule } from 'nestjs-console'
import { LoggerModule, Params as LoggerModuleParams } from 'nestjs-pino/dist'; import { LoggerModule, Params as LoggerModuleParams } from 'nestjs-pino/dist'
import { join } from 'path'; import { join } from 'path'
import { DatabaseType } from 'typeorm'
import { entities } from './entity' import { entities } from './entity'
import { schema } from './schema';
export const LoggerConfig: LoggerModuleParams = { export const LoggerConfig: LoggerModuleParams = {
pinoHttp: { pinoHttp: {
@ -111,30 +107,18 @@ export const imports = [
inject: [ConfigService], inject: [ConfigService],
useFactory: (configService: ConfigService): TypeOrmModuleOptions => ({ useFactory: (configService: ConfigService): TypeOrmModuleOptions => ({
name: 'ohmyform', name: 'ohmyform',
url: configService.get<string>('DB_URI', 'sqlite://data.sqlite') as any, type: configService.get<string>('DB_TYPE', 'sqlite') as any,
url: configService.get<string>('DB_URI', 'sqlite://data.sqlite'),
entityPrefix: configService.get<string>('DB_TABLE_PREFIX', ''), entityPrefix: configService.get<string>('DB_TABLE_PREFIX', ''),
logging: configService.get<string>('DB_LOGGING', 'false') === 'true', logging: configService.get<string>('DB_LOGGING', 'false') === 'true',
entities, entities,
migrationsTableName: 'nest_migrations',
migrations: [ migrations: [
`${__dirname}/**/migrations/**/*{.ts,.js}`, `${__dirname}/**/migrations/**/*{.ts,.js}`,
], ],
migrationsRun: configService.get<boolean>('DB_MIGRATE', true), migrationsRun: configService.get<boolean>('DB_MIGRATE', true),
}), }),
}), }),
MongooseModule.forRootAsync({ TypeOrmModule.forFeature(entities),
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService): Promise<MongooseModuleOptions> => ({
uri: configService.get<string>('MONGODB_URI', 'mongodb://localhost/ohmyform'),
// takes care of deprecations from https://mongoosejs.com/docs/deprecations.html
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
useFindAndModify: false,
})
}),
MongooseModule.forFeature(schema),
MailerModule.forRootAsync({ MailerModule.forRootAsync({
imports: [ConfigModule], imports: [ConfigModule],
inject: [ConfigService], inject: [ConfigService],

View File

@ -1,7 +1,7 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { imports } from './app.imports'; import { imports } from './app.imports'
import { providers } from './app.providers'; import { providers } from './app.providers'
import { controllers } from './controller'; import { controllers } from './controller'
@Module({ @Module({
imports, imports,

View File

@ -1,7 +1,7 @@
import { commands } from './command'; import { commands } from './command'
import { guards } from './guard'; import { guards } from './guard'
import { resolvers } from './resolver'; import { resolvers } from './resolver'
import { services } from './service'; import { services } from './service'
export const providers = [ export const providers = [
...resolvers, ...resolvers,

View File

@ -1,5 +1,5 @@
import { BootstrapConsole } from 'nestjs-console'; import { BootstrapConsole } from 'nestjs-console'
import { AppModule } from './app.module'; import { AppModule } from './app.module'
const bootstrap = new BootstrapConsole({ const bootstrap = new BootstrapConsole({
module: AppModule, module: AppModule,

View File

@ -1,4 +1,4 @@
import { UserCommand } from './user.command'; import { UserCommand } from './user.command'
export const commands = [ export const commands = [
UserCommand, UserCommand,

View File

@ -1,7 +1,7 @@
import inquirer from 'inquirer'; import inquirer from 'inquirer'
import { Command, Console } from 'nestjs-console'; import { Command, Console } from 'nestjs-console'
import { matchType, validatePassword } from '../config/fields'; import { matchType, validatePassword } from '../config/fields'
import { UserCreateService } from '../service/user/user.create.service'; import { UserCreateService } from '../service/user/user.create.service'
@Console({ @Console({
name: 'user', name: 'user',

View File

@ -1,15 +1,23 @@
export const languages = [ export const languages = [
'cn',
'de',
'en', 'en',
'es', 'ar',
'cn',
'da',
'nl',
'fr', 'fr',
'de',
'hi',
'it', 'it',
'ja', 'ja',
'pl', 'pl',
'pt', 'pt_BR',
'pt_PT',
'ru', 'ru',
'es',
'sv',
'ta',
'uk',
] ]
export const defaultLanguage = 'en' export const defaultLanguage = 'en'

View File

@ -1,4 +1,4 @@
import { Controller, Get } from '@nestjs/common'; import { Controller, Get } from '@nestjs/common'
@Controller() @Controller()
export class HealthController { export class HealthController {

View File

@ -1,4 +1,4 @@
import { HealthController } from './health.controller'; import { HealthController } from './health.controller'
export const controllers = [ export const controllers = [
HealthController, HealthController,

View File

@ -1,4 +1,4 @@
import { SetMetadata } from '@nestjs/common'; import { SetMetadata } from '@nestjs/common'
import { rolesType } from '../config/roles'; import { rolesType } from '../config/roles'
export const Roles = (...roles: rolesType) => SetMetadata('roles', roles); export const Roles = (...roles: rolesType) => SetMetadata('roles', roles);

View File

@ -1,5 +1,5 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common'; import { createParamDecorator, ExecutionContext } from '@nestjs/common'
import { GqlExecutionContext } from '@nestjs/graphql'; import { GqlExecutionContext } from '@nestjs/graphql'
export const User = createParamDecorator( export const User = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => (data: unknown, ctx: ExecutionContext) =>

View File

@ -1,4 +1,4 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
@ObjectType('AuthToken') @ObjectType('AuthToken')
export class AuthJwtModel { export class AuthJwtModel {

View File

@ -1,4 +1,4 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
@ObjectType('Deleted') @ObjectType('Deleted')
export class DeletedModel { export class DeletedModel {

View File

@ -1,13 +0,0 @@
import { Field, InputType } from '@nestjs/graphql';
@InputType('NotificationInput', { isAbstract: true })
export class AbstractNotificationInput {
@Field({ nullable: true })
readonly subject?: string
@Field({ nullable: true })
readonly htmlTemplate?: string
@Field()
readonly enabled: boolean
}

View File

@ -1,20 +0,0 @@
import { Field, InterfaceType } from '@nestjs/graphql';
import { Notifications } from '../../schema/form.schema';
@InterfaceType('Notification')
export class AbstractNotificationModel {
@Field({ nullable: true })
readonly subject?: string
@Field({ nullable: true })
readonly htmlTemplate?: string
@Field()
readonly enabled: boolean
constructor(partial: Partial<Notifications>) {
this.subject = partial.subject
this.htmlTemplate = partial.htmlTemplate
this.enabled = partial.enabled
}
}

View File

@ -1,4 +1,4 @@
import { Field, InputType } from '@nestjs/graphql'; import { Field, InputType } from '@nestjs/graphql'
@InputType() @InputType()
export class ButtonInput { export class ButtonInput {

View File

@ -1,4 +1,5 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
import { PageButtonEntity } from '../../entity/page.button.entity'
@ObjectType('Button') @ObjectType('Button')
export class ButtonModel { export class ButtonModel {
@ -20,7 +21,7 @@ export class ButtonModel {
@Field({ nullable: true }) @Field({ nullable: true })
readonly color?: string readonly color?: string
constructor(button: Partial<ButtonModel>) { constructor(button: Partial<PageButtonEntity>) {
this.url = button.url this.url = button.url
this.action = button.action this.action = button.action
this.text = button.text this.text = button.text

View File

@ -1,22 +1,22 @@
import { Field, InputType } from '@nestjs/graphql'; import { Field, InputType } from '@nestjs/graphql'
@InputType() @InputType()
export class ColorsInput { export class ColorsInput {
@Field() @Field()
readonly backgroundColor: string readonly background: string
@Field() @Field()
readonly questionColor: string readonly question: string
@Field() @Field()
readonly answerColor: string readonly answer: string
@Field() @Field()
readonly buttonColor: string readonly button: string
@Field() @Field()
readonly buttonActiveColor: string readonly buttonActive: string
@Field() @Field()
readonly buttonTextColor: string readonly buttonText: string
} }

View File

@ -1,32 +1,32 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
import { Colors } from '../../schema/form.schema'; import { ColorsEmbedded } from '../../entity/embedded/colors.embedded'
@ObjectType('Colors') @ObjectType('Colors')
export class ColorsModel { export class ColorsModel {
@Field() @Field()
readonly backgroundColor: string readonly background: string
@Field() @Field()
readonly questionColor: string readonly question: string
@Field() @Field()
readonly answerColor: string readonly answer: string
@Field() @Field()
readonly buttonColor: string readonly button: string
@Field() @Field()
readonly buttonActiveColor: string readonly buttonActive: string
@Field() @Field()
readonly buttonTextColor: string readonly buttonText: string
constructor(partial: Partial<Colors>) { constructor(partial: Partial<ColorsEmbedded>) {
this.backgroundColor = partial.backgroundColor this.background = partial.background
this.questionColor = partial.questionColor this.question = partial.question
this.answerColor = partial.answerColor this.answer = partial.answer
this.buttonColor = partial.buttonColor this.button = partial.button
this.buttonActiveColor = partial.buttonActiveColor this.buttonActive = partial.buttonActive
this.buttonTextColor = partial.buttonTextColor this.buttonText = partial.buttonText
} }
} }

View File

@ -1,5 +1,5 @@
import { Field, InputType } from '@nestjs/graphql'; import { Field, InputType } from '@nestjs/graphql'
import { ColorsInput } from './colors.input'; import { ColorsInput } from './colors.input'
@InputType() @InputType()
export class DesignInput { export class DesignInput {

View File

@ -1,6 +1,6 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
import { Design } from '../../schema/form.schema'; import { DesignEmbedded } from '../../entity/embedded/design.embedded'
import { ColorsModel } from './colors.model'; import { ColorsModel } from './colors.model'
@ObjectType('Design') @ObjectType('Design')
export class DesignModel { export class DesignModel {
@ -10,7 +10,7 @@ export class DesignModel {
@Field({ nullable: true }) @Field({ nullable: true })
readonly font?: string readonly font?: string
constructor(partial: Partial<Design>) { constructor(partial: Partial<DesignEmbedded>) {
this.colors = new ColorsModel(partial.colors) this.colors = new ColorsModel(partial.colors)
this.font = partial.font this.font = partial.font
} }

View File

@ -1,4 +1,4 @@
import { Field, InputType } from '@nestjs/graphql'; import { Field, InputType } from '@nestjs/graphql'
@InputType('FormCreateInput') @InputType('FormCreateInput')
export class FormCreateInput { export class FormCreateInput {

View File

@ -1,8 +1,8 @@
import { Field, ID, InputType } from '@nestjs/graphql'; import { Field, ID, InputType } from '@nestjs/graphql'
import { FormFieldOptionInput } from './form.field.option.input'; import { FormFieldLogicInput } from './form.field.logic.input'
import { FormFieldRatingInput } from './form.field.rating.input'; import { FormFieldLogicModel } from './form.field.logic.model'
import { LogicJumpInput } from './logic.jump.input'; import { FormFieldOptionInput } from './form.field.option.input'
import { LogicJumpModel } from './logic.jump.model'; import { FormFieldRatingInput } from './form.field.rating.input'
@InputType() @InputType()
export class FormFieldInput { export class FormFieldInput {
@ -28,10 +28,10 @@ export class FormFieldInput {
readonly value: string readonly value: string
@Field(() => [FormFieldOptionInput], { nullable: true }) @Field(() => [FormFieldOptionInput], { nullable: true })
readonly options: [FormFieldOptionInput] readonly options: FormFieldOptionInput[]
@Field(() => LogicJumpInput, { nullable: true }) @Field(() => [FormFieldLogicInput], { nullable: true })
readonly logicJump: LogicJumpModel readonly logic: FormFieldLogicInput[]
@Field(() => FormFieldRatingInput, { nullable: true }) @Field(() => FormFieldRatingInput, { nullable: true })
readonly rating: FormFieldRatingInput readonly rating: FormFieldRatingInput

View File

@ -0,0 +1,25 @@
import { Field, ID, InputType } from '@nestjs/graphql'
@InputType()
export class FormFieldLogicInput {
@Field({ nullable: true })
readonly formula: string
@Field({ nullable: true })
readonly action: string
@Field(() => ID, { nullable: true })
readonly jumpTo?: string
@Field({ nullable: true })
readonly visible?: boolean
@Field({ nullable: true })
readonly disable?: boolean
@Field({ nullable: true })
readonly require?: boolean
@Field({ nullable: true })
readonly enabled: boolean
}

View File

@ -0,0 +1,42 @@
import { Field, ID, ObjectType } from '@nestjs/graphql'
import { FormFieldLogicEntity } from '../../entity/form.field.logic.entity'
@ObjectType('FormFieldLogic')
export class FormFieldLogicModel {
@Field(() => ID)
readonly id: string
@Field({ nullable: true })
readonly formula: string
@Field()
readonly action: string
@Field(() => ID, { nullable: true })
readonly jumpTo?: string
@Field({ nullable: true })
readonly visible?: boolean
@Field({ nullable: true })
readonly disable?: boolean
@Field({ nullable: true })
readonly require?: boolean
@Field()
readonly enabled: boolean
constructor(document: FormFieldLogicEntity) {
this.id = document.id.toString()
this.enabled = document.enabled
this.formula = document.formula
this.jumpTo = document.jumpTo?.id.toString()
this.action = document.action
this.visible = document.visible
this.disable = document.disable
this.require = document.require
}
}

View File

@ -1,8 +1,8 @@
import { Field, ID, ObjectType } from '@nestjs/graphql'; import { Field, ID, ObjectType } from '@nestjs/graphql'
import { FormFieldDocument } from '../../schema/form.field.schema'; import { FormFieldEntity } from '../../entity/form.field.entity'
import { FormFieldOptionModel } from './form.field.option.model'; import { FormFieldLogicModel } from './form.field.logic.model'
import { FormFieldRatingModel } from './form.field.rating.model'; import { FormFieldOptionModel } from './form.field.option.model'
import { LogicJumpModel } from './logic.jump.model'; import { FormFieldRatingModel } from './form.field.rating.model'
@ObjectType('FormField') @ObjectType('FormField')
export class FormFieldModel { export class FormFieldModel {
@ -28,16 +28,16 @@ export class FormFieldModel {
readonly value: string readonly value: string
@Field(() => [FormFieldOptionModel]) @Field(() => [FormFieldOptionModel])
readonly options: [FormFieldOptionModel] readonly options: FormFieldOptionModel[]
@Field(() => LogicJumpModel) @Field(() => [FormFieldLogicModel])
readonly logicJump: LogicJumpModel readonly logic: FormFieldLogicModel[]
@Field(() => FormFieldRatingModel, { nullable: true }) @Field(() => FormFieldRatingModel, { nullable: true })
readonly rating: FormFieldRatingModel readonly rating: FormFieldRatingModel
constructor(document: FormFieldDocument) { constructor(document: FormFieldEntity) {
this.id = document.id this.id = document.id.toString()
this.title = document.title this.title = document.title
this.slug = document.slug this.slug = document.slug
this.type = document.type this.type = document.type
@ -45,7 +45,7 @@ export class FormFieldModel {
this.required = document.required this.required = document.required
this.value = document.value this.value = document.value
this.options = document.options ? document.options.map(option => new FormFieldOptionModel(option)) : [] this.options = document.options ? document.options.map(option => new FormFieldOptionModel(option)) : []
this.logicJump = new LogicJumpModel(document.logicJump) this.logic = document.logic ? document.logic.map(logic => new FormFieldLogicModel(logic)) : []
this.rating = document.rating ? new FormFieldRatingModel(document.rating) : null this.rating = document.rating ? new FormFieldRatingModel(document.rating) : null
} }
} }

View File

@ -1,4 +1,4 @@
import { Field, InputType } from '@nestjs/graphql'; import { Field, InputType } from '@nestjs/graphql'
@InputType() @InputType()
export class FormFieldOptionInput { export class FormFieldOptionInput {

View File

@ -1,5 +1,5 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
import { FieldOptionDocument } from '../../schema/embedded/field.option'; import { FormFieldOptionEntity } from '../../entity/form.field.option.entity'
@ObjectType('FormFieldOption') @ObjectType('FormFieldOption')
export class FormFieldOptionModel { export class FormFieldOptionModel {
@ -12,7 +12,7 @@ export class FormFieldOptionModel {
@Field() @Field()
readonly value: string readonly value: string
constructor(option: FieldOptionDocument) { constructor(option: FormFieldOptionEntity) {
this.key = option.key this.key = option.key
this.title = option.title this.title = option.title
this.value = option.value this.value = option.value

View File

@ -1,5 +1,5 @@
import { Field, InputType } from '@nestjs/graphql'; import { Field, InputType } from '@nestjs/graphql'
import { GraphQLInt } from 'graphql'; import { GraphQLInt } from 'graphql'
@InputType() @InputType()
export class FormFieldRatingInput { export class FormFieldRatingInput {

View File

@ -1,6 +1,6 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
import { GraphQLInt } from 'graphql'; import { GraphQLInt } from 'graphql'
import { RatingFieldDocument } from '../../schema/embedded/rating.field'; import { RatingEmbedded } from '../../entity/embedded/rating.embedded'
@ObjectType('FormFieldRating') @ObjectType('FormFieldRating')
export class FormFieldRatingModel { export class FormFieldRatingModel {
@ -10,7 +10,7 @@ export class FormFieldRatingModel {
@Field({ nullable: true }) @Field({ nullable: true })
readonly shape: string readonly shape: string
constructor(option: RatingFieldDocument) { constructor(option: RatingEmbedded) {
this.steps = option.steps this.steps = option.steps
this.shape = option.shape this.shape = option.shape
} }

View File

@ -1,5 +1,4 @@
import { Field, ID, InputType } from '@nestjs/graphql' import { Field, ID, InputType } from '@nestjs/graphql'
import { GraphQLInt } from 'graphql';
@InputType() @InputType()
export class FormHookInput { export class FormHookInput {

View File

@ -1,5 +1,5 @@
import { Field, ID, ObjectType } from '@nestjs/graphql'; import { Field, ID, ObjectType } from '@nestjs/graphql'
import { FormHookDocument } from '../../schema/form.hook.schema' import { FormHookEntity } from '../../entity/form.hook.entity'
@ObjectType('FormHook') @ObjectType('FormHook')
export class FormHookModel { export class FormHookModel {
@ -15,8 +15,8 @@ export class FormHookModel {
@Field({ nullable: true }) @Field({ nullable: true })
readonly format?: string readonly format?: string
constructor(hook: FormHookDocument) { constructor(hook: FormHookEntity) {
this.id = hook.id this.id = hook.id.toString()
this.enabled = hook.enabled this.enabled = hook.enabled
this.url = hook.url this.url = hook.url
this.format = hook.format this.format = hook.format

View File

@ -1,5 +1,5 @@
import { Field, ID, ObjectType } from '@nestjs/graphql'; import { Field, ID, ObjectType } from '@nestjs/graphql'
import { FormDocument } from '../../schema/form.schema'; import { FormEntity } from '../../entity/form.entity'
@ObjectType('Form') @ObjectType('Form')
export class FormModel { export class FormModel {
@ -21,8 +21,8 @@ export class FormModel {
@Field() @Field()
readonly showFooter: boolean readonly showFooter: boolean
constructor(form: FormDocument) { constructor(form: FormEntity) {
this.id = form.id this.id = form.id.toString()
this.title = form.title this.title = form.title
this.created = form.created this.created = form.created
this.lastModified = form.lastModified this.lastModified = form.lastModified

View File

@ -0,0 +1,25 @@
import { Field, InputType } from '@nestjs/graphql'
@InputType('FormNotificationInput')
export class FormNotificationInput {
@Field({ nullable: true })
readonly subject?: string
@Field({ nullable: true })
readonly htmlTemplate?: string
@Field({ nullable: true })
readonly toField?: string
@Field({ nullable: true })
readonly fromEmail?: string
@Field({ nullable: true })
readonly fromField?: string
@Field({ nullable: true })
readonly toEmail?: string
@Field()
readonly enabled: boolean
}

View File

@ -0,0 +1,36 @@
import { Field, InterfaceType } from '@nestjs/graphql'
import { FormNotificationEntity } from '../../entity/form.notification.entity'
@InterfaceType('FormNotification')
export class FormNotificationModel {
@Field({ nullable: true })
readonly subject?: string
@Field({ nullable: true })
readonly htmlTemplate?: string
@Field({ nullable: true })
readonly toField?: string
@Field({ nullable: true })
readonly fromEmail?: string
@Field({ nullable: true })
readonly fromField?: string
@Field({ nullable: true })
readonly toEmail?: string
@Field()
readonly enabled: boolean
constructor(partial: Partial<FormNotificationEntity>) {
this.subject = partial.subject
this.htmlTemplate = partial.htmlTemplate
this.enabled = partial.enabled
this.toField = partial.toField?.id.toString()
this.toEmail = partial.toEmail
this.fromField = partial.fromField?.id.toString()
this.fromEmail = partial.fromEmail
}
}

View File

@ -1,9 +1,9 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
import { GraphQLInt } from 'graphql'; import { GraphQLInt } from 'graphql'
import { FormModel } from './form.model'; import { FormModel } from './form.model'
@ObjectType('PagerForm') @ObjectType('FormPager')
export class PagerFormModel { export class FormPagerModel {
@Field(() => [FormModel]) @Field(() => [FormModel])
entries: FormModel[] entries: FormModel[]

View File

@ -1,4 +1,4 @@
import { ObjectType } from '@nestjs/graphql'; import { ObjectType } from '@nestjs/graphql'
@ObjectType('FormStatistic') @ObjectType('FormStatistic')
export class FormStatisticModel { export class FormStatisticModel {

View File

@ -1,10 +1,9 @@
import { Field, ID, InputType } from '@nestjs/graphql'; import { Field, ID, InputType } from '@nestjs/graphql'
import { DesignInput } from './design.input'; import { DesignInput } from './design.input'
import { FormFieldInput } from './form.field.input'; import { FormFieldInput } from './form.field.input'
import { FormHookInput } from './form.hook.input' import { FormHookInput } from './form.hook.input'
import { PageInput } from './page.input'; import { FormNotificationInput } from './form.notification.input'
import { RespondentNotificationsInput } from './respondent.notifications.input'; import { PageInput } from './page.input'
import { SelfNotificationsInput } from './self.notifications.input';
@InputType() @InputType()
export class FormUpdateInput { export class FormUpdateInput {
@ -38,9 +37,6 @@ export class FormUpdateInput {
@Field({ nullable: true }) @Field({ nullable: true })
readonly endPage: PageInput readonly endPage: PageInput
@Field({ nullable: true }) @Field(() => [FormNotificationInput], { nullable: true })
readonly selfNotifications: SelfNotificationsInput readonly notifications: FormNotificationInput[]
@Field({ nullable: true })
readonly respondentNotifications: RespondentNotificationsInput
} }

View File

@ -1,19 +0,0 @@
import { Field, ID, InputType } from '@nestjs/graphql';
@InputType()
export class LogicJumpInput {
@Field(() => ID, { nullable: true })
readonly fieldA: string
@Field({ nullable: true })
readonly valueB: string
@Field({ nullable: true })
readonly expressionString: string
@Field(() => ID, { nullable: true })
readonly jumpTo: string
@Field({ nullable: true })
readonly enabled: boolean
}

View File

@ -1,33 +0,0 @@
import { Field, ID, ObjectType } from '@nestjs/graphql';
import { LogicJumpDocument } from '../../schema/embedded/logic.jump';
@ObjectType('LogicJump')
export class LogicJumpModel {
@Field(() => ID, { nullable: true })
readonly fieldA: string
@Field({ nullable: true })
readonly valueB: string
@Field({ nullable: true })
readonly expressionString: string
@Field(() => ID, { nullable: true })
readonly jumpTo: string
@Field()
readonly enabled: boolean
constructor(document: LogicJumpDocument) {
if (!document) {
this.enabled = false
return
}
this.fieldA = document.fieldA
this.valueB = document.valueB
this.expressionString = document.expressionString
this.jumpTo = document.jumpTo
this.enabled = !!document.enabled
}
}

View File

@ -1,5 +1,5 @@
import { Field, InputType } from '@nestjs/graphql'; import { Field, InputType } from '@nestjs/graphql'
import { ButtonInput } from './button.input'; import { ButtonInput } from './button.input'
@InputType() @InputType()
export class PageInput { export class PageInput {

View File

@ -1,6 +1,6 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
import { FormPage } from '../../schema/form.schema'; import { PageEntity } from '../../entity/page.entity'
import { ButtonModel } from './button.model'; import { ButtonModel } from './button.model'
@ObjectType('Page') @ObjectType('Page')
export class PageModel { export class PageModel {
@ -19,7 +19,7 @@ export class PageModel {
@Field(() => [ButtonModel]) @Field(() => [ButtonModel])
readonly buttons: ButtonModel[] readonly buttons: ButtonModel[]
constructor(page: Partial<FormPage>) { constructor(page: Partial<PageEntity>) {
this.show = page.show this.show = page.show
this.title = page.title this.title = page.title
this.paragraph = page.paragraph this.paragraph = page.paragraph

View File

@ -1,11 +0,0 @@
import { Field, InputType } from '@nestjs/graphql';
import { AbstractNotificationInput } from './abstract.notification.input';
@InputType()
export class RespondentNotificationsInput extends AbstractNotificationInput {
@Field({ nullable: true })
readonly toField?: string
@Field({ nullable: true })
readonly fromEmail?: string
}

View File

@ -1,21 +0,0 @@
import { Field, ObjectType } from '@nestjs/graphql';
import { RespondentNotifications } from '../../schema/form.schema';
import { AbstractNotificationModel } from './abstract.notification.model';
@ObjectType({
implements: [AbstractNotificationModel],
})
export class RespondentNotificationsModel extends AbstractNotificationModel {
@Field({ nullable: true })
readonly toField?: string
@Field({ nullable: true })
readonly fromEmail?: string
constructor(partial: Partial<RespondentNotifications>) {
super(partial);
this.toField = partial.toField
this.fromEmail = partial.fromEmail
}
}

View File

@ -1,11 +0,0 @@
import { Field, InputType } from '@nestjs/graphql';
import { AbstractNotificationInput } from './abstract.notification.input';
@InputType()
export class SelfNotificationsInput extends AbstractNotificationInput {
@Field({ nullable: true })
readonly fromField?: string
@Field({ nullable: true })
readonly toEmail?: string
}

View File

@ -1,21 +0,0 @@
import { Field, ObjectType } from '@nestjs/graphql';
import { SelfNotifications } from '../../schema/form.schema';
import { AbstractNotificationModel } from './abstract.notification.model';
@ObjectType({
implements: [AbstractNotificationModel],
})
export class SelfNotificationsModel extends AbstractNotificationModel {
@Field({ nullable: true })
readonly fromField?: string
@Field({ nullable: true })
readonly toEmail?: string
constructor(partial: Partial<SelfNotifications>) {
super(partial);
this.fromField = partial.fromField
this.toEmail = partial.toEmail
}
}

View File

@ -1,13 +1,13 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
import { UserDocument } from '../../schema/user.schema'; import { UserEntity } from '../../entity/user.entity'
import { UserModel } from '../user/user.model'; import { UserModel } from '../user/user.model'
@ObjectType('Profile') @ObjectType('Profile')
export class ProfileModel extends UserModel { export class ProfileModel extends UserModel {
@Field(() => [String]) @Field(() => [String])
readonly roles: string[] readonly roles: string[]
constructor(user: UserDocument) { constructor(user: UserEntity) {
super(user) super(user)
this.roles = user.roles this.roles = user.roles

View File

@ -1,4 +1,4 @@
import { Field, ID, InputType } from '@nestjs/graphql'; import { Field, ID, InputType } from '@nestjs/graphql'
@InputType() @InputType()
export class ProfileUpdateInput { export class ProfileUpdateInput {

View File

@ -1,4 +1,4 @@
import { Field, ID, ObjectType } from '@nestjs/graphql'; import { Field, ID, ObjectType } from '@nestjs/graphql'
@ObjectType('Setting') @ObjectType('Setting')
export class SettingModel { export class SettingModel {

View File

@ -1,9 +1,9 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
import { GraphQLInt } from 'graphql'; import { GraphQLInt } from 'graphql'
import {SettingModel} from './setting.model' import { SettingModel } from './setting.model'
@ObjectType('PagerSetting') @ObjectType('SettingPager')
export class PagerSettingModel { export class SettingPagerModel {
@Field(() => [SettingModel]) @Field(() => [SettingModel])
entries: SettingModel[] entries: SettingModel[]

View File

@ -1,4 +1,4 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
@ObjectType('Version') @ObjectType('Version')
export class StatusModel { export class StatusModel {

View File

@ -1,4 +1,4 @@
import { Field, InputType } from '@nestjs/graphql'; import { Field, InputType } from '@nestjs/graphql'
@InputType() @InputType()
export class DeviceInput { export class DeviceInput {
@ -7,4 +7,7 @@ export class DeviceInput {
@Field() @Field()
readonly name: string readonly name: string
@Field({ nullable: true })
readonly language: string
} }

View File

@ -1,5 +1,5 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
import { Device } from '../../schema/submission.schema'; import { DeviceEmbedded } from '../../entity/embedded/device.embedded'
@ObjectType('Device') @ObjectType('Device')
export class DeviceModel { export class DeviceModel {
@ -9,8 +9,12 @@ export class DeviceModel {
@Field() @Field()
readonly name: string readonly name: string
constructor(device: Device) { @Field({ nullable: true })
readonly language: string
constructor(device: DeviceEmbedded) {
this.type = device.type this.type = device.type
this.name = device.name this.name = device.name
this.language = device.language
} }
} }

View File

@ -1,5 +1,5 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
import { GeoLocation } from '../../schema/submission.schema'; import { GeoLocationEmbedded } from '../../entity/embedded/geo.location.embedded'
@ObjectType('GeoLocation') @ObjectType('GeoLocation')
export class GeoLocationModel { export class GeoLocationModel {
@ -9,7 +9,7 @@ export class GeoLocationModel {
@Field({ nullable: true }) @Field({ nullable: true })
city?: string city?: string
constructor(geo: GeoLocation) { constructor(geo: GeoLocationEmbedded) {
this.country = geo.country this.country = geo.country
this.city = geo.city this.city = geo.city
} }

View File

@ -1,5 +1,5 @@
import { Field, ID, ObjectType } from '@nestjs/graphql'; import { Field, ID, ObjectType } from '@nestjs/graphql'
import { SubmissionFieldDocument } from '../../schema/submission.field.schema'; import { SubmissionFieldEntity } from '../../entity/submission.field.entity'
@ObjectType('SubmissionField') @ObjectType('SubmissionField')
export class SubmissionFieldModel { export class SubmissionFieldModel {
@ -12,8 +12,8 @@ export class SubmissionFieldModel {
@Field() @Field()
readonly type: string readonly type: string
constructor(field: SubmissionFieldDocument) { constructor(field: SubmissionFieldEntity) {
this.id = field.id this.id = field.id.toString()
this.value = JSON.stringify(field.fieldValue) this.value = JSON.stringify(field.fieldValue)
this.type = field.fieldType this.type = field.fieldType
} }

View File

@ -1,12 +1,12 @@
import { Field, ID, ObjectType } from '@nestjs/graphql'; import { Field, ID, ObjectType } from '@nestjs/graphql'
import { SubmissionDocument } from '../../schema/submission.schema'; import { SubmissionEntity } from '../../entity/submission.entity'
import { DeviceModel } from './device.model'; import { DeviceModel } from './device.model'
import { GeoLocationModel } from './geo.location.model'; import { GeoLocationModel } from './geo.location.model'
@ObjectType('Submission') @ObjectType('Submission')
export class SubmissionModel { export class SubmissionModel {
@Field(() => ID) @Field(() => ID)
readonly id: string readonly id: number
@Field() @Field()
readonly ipAddr: string readonly ipAddr: string
@ -29,7 +29,7 @@ export class SubmissionModel {
@Field({ nullable: true }) @Field({ nullable: true })
readonly lastModified?: Date readonly lastModified?: Date
constructor(submission: SubmissionDocument) { constructor(submission: SubmissionEntity) {
this.id = submission.id this.id = submission.id
this.ipAddr = submission.ipAddr this.ipAddr = submission.ipAddr

View File

@ -1,9 +1,9 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
import { GraphQLInt } from 'graphql'; import { GraphQLInt } from 'graphql'
import { SubmissionModel } from './submission.model'; import { SubmissionModel } from './submission.model'
@ObjectType('PagerSubmission') @ObjectType('SubmissionPager')
export class PagerSubmissionModel { export class SubmissionPagerModel {
@Field(() => [SubmissionModel]) @Field(() => [SubmissionModel])
entries: SubmissionModel[] entries: SubmissionModel[]

View File

@ -1,5 +1,5 @@
import { Field, ID, ObjectType } from '@nestjs/graphql'; import { Field, ID, ObjectType } from '@nestjs/graphql'
import { SubmissionDocument } from '../../schema/submission.schema'; import { SubmissionEntity } from '../../entity/submission.entity'
@ObjectType('SubmissionProgress') @ObjectType('SubmissionProgress')
export class SubmissionProgressModel { export class SubmissionProgressModel {
@ -18,8 +18,8 @@ export class SubmissionProgressModel {
@Field({ nullable: true }) @Field({ nullable: true })
readonly lastModified?: Date readonly lastModified?: Date
constructor(submission: Partial<SubmissionDocument>) { constructor(submission: Partial<SubmissionEntity>) {
this.id = submission.id this.id = submission.id.toString()
this.timeElapsed = submission.timeElapsed this.timeElapsed = submission.timeElapsed
this.percentageComplete = submission.percentageComplete this.percentageComplete = submission.percentageComplete

View File

@ -1,4 +1,4 @@
import { Field, ID, InputType } from '@nestjs/graphql'; import { Field, ID, InputType } from '@nestjs/graphql'
@InputType() @InputType()
export class SubmissionSetFieldInput { export class SubmissionSetFieldInput {

View File

@ -1,5 +1,5 @@
import { Field, InputType } from '@nestjs/graphql'; import { Field, InputType } from '@nestjs/graphql'
import { DeviceInput } from './device.input'; import { DeviceInput } from './device.input'
@InputType() @InputType()
export class SubmissionStartInput { export class SubmissionStartInput {

View File

@ -1,4 +1,4 @@
import { ObjectType } from '@nestjs/graphql'; import { ObjectType } from '@nestjs/graphql'
@ObjectType('SubmissionStatistic') @ObjectType('SubmissionStatistic')
export class SubmissionStatisticModel { export class SubmissionStatisticModel {

View File

@ -1,5 +1,5 @@
import { Field, InputType } from '@nestjs/graphql'; import { Field, InputType } from '@nestjs/graphql'
import { IsEmail, IsNotEmpty, MaxLength, MinLength } from 'class-validator'; import { IsEmail, IsNotEmpty, MaxLength, MinLength } from 'class-validator'
@InputType() @InputType()
export class UserCreateInput { export class UserCreateInput {

View File

@ -1,5 +1,5 @@
import { Field, ID, ObjectType } from '@nestjs/graphql'; import { Field, ID, ObjectType } from '@nestjs/graphql'
import { UserDocument } from '../../schema/user.schema'; import { UserEntity } from '../../entity/user.entity'
@ObjectType('User') @ObjectType('User')
export class UserModel { export class UserModel {
@ -30,8 +30,8 @@ export class UserModel {
@Field({ nullable: true }) @Field({ nullable: true })
readonly lastModified: Date readonly lastModified: Date
constructor(user: UserDocument) { constructor(user: UserEntity) {
this.id = user.id this.id = user.id.toString()
this.username = user.username this.username = user.username
this.email = user.email this.email = user.email

View File

@ -1,9 +1,9 @@
import { Field, ObjectType } from '@nestjs/graphql'; import { Field, ObjectType } from '@nestjs/graphql'
import { GraphQLInt } from 'graphql'; import { GraphQLInt } from 'graphql'
import { UserModel } from './user.model'; import { UserModel } from './user.model'
@ObjectType('PagerUser') @ObjectType('UserPager')
export class PagerUserModel { export class UserPagerModel {
@Field(() => [UserModel]) @Field(() => [UserModel])
entries: UserModel[] entries: UserModel[]

View File

@ -1,4 +1,4 @@
import { ObjectType } from '@nestjs/graphql'; import { ObjectType } from '@nestjs/graphql'
@ObjectType('UserStatistic') @ObjectType('UserStatistic')
export class UserStatisticModel { export class UserStatisticModel {

View File

@ -1,5 +1,4 @@
import { Field, ID, InputType } from '@nestjs/graphql'; import { Field, ID, InputType } from '@nestjs/graphql'
import { GraphQLString } from 'graphql';
@InputType() @InputType()
export class UserUpdateInput { export class UserUpdateInput {
@ -21,7 +20,7 @@ export class UserUpdateInput {
@Field({ nullable: true }) @Field({ nullable: true })
readonly password: string readonly password: string
@Field(() => [GraphQLString], { nullable: true }) @Field(() => [String], { nullable: true })
readonly roles: string[] readonly roles: string[]
@Field({ nullable: true }) @Field({ nullable: true })

View File

@ -1,3 +1,6 @@
import { Column } from 'typeorm'
export class AnalyticsEmbedded { export class AnalyticsEmbedded {
@Column({ nullable: true })
readonly gaCode?: string readonly gaCode?: string
} }

View File

@ -1,8 +1,21 @@
import { Column } from 'typeorm'
export class ColorsEmbedded { export class ColorsEmbedded {
readonly background: string @Column({ nullable: true })
readonly question: string public background?: string
readonly answer: string
readonly button: string @Column({ nullable: true })
readonly buttonActive: string public question?: string
readonly buttonText: string
@Column({ nullable: true })
public answer?: string
@Column({ nullable: true })
public button?: string
@Column({ nullable: true })
public buttonActive?: string
@Column({ nullable: true })
public buttonText?: string
} }

View File

@ -1,7 +1,10 @@
import { ColorsEmbedded } from './form.design.colors.embedded' import { Column } from 'typeorm'
import { ColorsEmbedded } from './colors.embedded'
export class DesignEmbedded { export class DesignEmbedded {
colors: ColorsEmbedded @Column(() => ColorsEmbedded)
colors: ColorsEmbedded = new ColorsEmbedded()
@Column({ nullable: true })
font?: string font?: string
} }

View File

@ -1,4 +1,12 @@
import { Column } from 'typeorm'
export class DeviceEmbedded { export class DeviceEmbedded {
readonly type?: string @Column({ nullable: true })
readonly name?: string public language?: string
@Column({ nullable: true })
public type?: string
@Column({ nullable: true })
public name?: string
} }

View File

@ -1,4 +1,9 @@
import { Column } from 'typeorm'
export class GeoLocationEmbedded { export class GeoLocationEmbedded {
@Column({ nullable: true })
readonly country?: string readonly country?: string
@Column({ nullable: true })
readonly city?: string readonly city?: string
} }

View File

@ -1,8 +0,0 @@
import { FormFieldEntity } from '../form.field.entity'
export class LogicEmbedded {
readonly formula?: string
readonly hide?: boolean
readonly jumpTo?: FormFieldEntity
readonly enabled?: boolean
}

View File

@ -1,4 +1,9 @@
import { Column } from 'typeorm'
export class RatingEmbedded { export class RatingEmbedded {
@Column({ nullable: true })
readonly steps?: number readonly steps?: number
@Column({ nullable: true })
readonly shape?: string readonly shape?: string
} }

View File

@ -4,17 +4,18 @@ import {
Entity, Entity,
ManyToOne, ManyToOne,
OneToMany, OneToMany,
PrimaryGeneratedColumn, UpdateDateColumn PrimaryGeneratedColumn,
UpdateDateColumn
} from 'typeorm' } from 'typeorm'
import { AnalyticsEmbedded } from './embedded/analytics.embedded' import { AnalyticsEmbedded } from './embedded/analytics.embedded'
import { DesignEmbedded } from './embedded/design.embedded' import { DesignEmbedded } from './embedded/design.embedded'
import { FormFieldEntity } from './form.field.entity' import { FormFieldEntity } from './form.field.entity'
import { FormHookEntity } from './form.hook.entity' import { FormHookEntity } from './form.hook.entity'
import { FormNotificationEntity } from './form.notification.entity' import { FormNotificationEntity } from './form.notification.entity'
import { SubmissionEntity } from './submission.entity'
import { VisitorEntity } from './visitor.entity'
import { PageEntity } from './page.entity' import { PageEntity } from './page.entity'
import { SubmissionEntity } from './submission.entity'
import { UserEntity } from './user.entity' import { UserEntity } from './user.entity'
import { VisitorEntity } from './visitor.entity'
@Entity({ name: 'form' }) @Entity({ name: 'form' })
export class FormEntity { export class FormEntity {
@ -28,7 +29,7 @@ export class FormEntity {
public language: string public language: string
@Column(() => AnalyticsEmbedded) @Column(() => AnalyticsEmbedded)
public analytics: AnalyticsEmbedded public analytics: AnalyticsEmbedded = new AnalyticsEmbedded()
@OneToMany(() => VisitorEntity, visitor => visitor.form) @OneToMany(() => VisitorEntity, visitor => visitor.form)
public visitors: VisitorEntity[] public visitors: VisitorEntity[]
@ -36,22 +37,22 @@ export class FormEntity {
@OneToMany(() => SubmissionEntity, submission => submission.form) @OneToMany(() => SubmissionEntity, submission => submission.form)
public submissions: SubmissionEntity[] public submissions: SubmissionEntity[]
@OneToMany(() => FormFieldEntity, field => field.form) @OneToMany(() => FormFieldEntity, field => field.form, { eager: true, orphanedRowAction: 'delete' })
public fields: FormFieldEntity[] public fields: FormFieldEntity[]
@OneToMany(() => FormHookEntity, field => field.form) @OneToMany(() => FormHookEntity, field => field.form, { eager: true, orphanedRowAction: 'delete' })
public hooks: FormHookEntity[] public hooks: FormHookEntity[]
@ManyToOne(() => UserEntity) @ManyToOne(() => UserEntity, { eager: true })
public admin: UserEntity public admin: UserEntity
@ManyToOne(() => PageEntity) @ManyToOne(() => PageEntity, { eager: true })
public startPage: PageEntity; public startPage: PageEntity;
@ManyToOne(() => PageEntity) @ManyToOne(() => PageEntity, { eager: true })
public endPage: PageEntity; public endPage: PageEntity;
@OneToMany(() => FormNotificationEntity, notification => notification.form) @OneToMany(() => FormNotificationEntity, notification => notification.form, { eager: true, orphanedRowAction: 'delete' })
public notifications: FormNotificationEntity[] public notifications: FormNotificationEntity[]
@Column() @Column()
@ -61,7 +62,7 @@ export class FormEntity {
public isLive: boolean; public isLive: boolean;
@Column(() => DesignEmbedded) @Column(() => DesignEmbedded)
public design: DesignEmbedded; public design: DesignEmbedded = new DesignEmbedded();
@CreateDateColumn() @CreateDateColumn()
public created: Date public created: Date

View File

@ -1,5 +1,4 @@
import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from 'typeorm' import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from 'typeorm'
import { LogicEmbedded } from './embedded/logic.embedded'
import { RatingEmbedded } from './embedded/rating.embedded' import { RatingEmbedded } from './embedded/rating.embedded'
import { FormEntity } from './form.entity' import { FormEntity } from './form.entity'
import { FormFieldLogicEntity } from './form.field.logic.entity' import { FormFieldLogicEntity } from './form.field.logic.entity'
@ -22,13 +21,13 @@ export class FormFieldEntity {
@Column({ nullable: true }) @Column({ nullable: true })
public slug?: string public slug?: string
@OneToMany(() => FormFieldLogicEntity, logic => logic.field) @OneToMany(() => FormFieldLogicEntity, logic => logic.field, { eager: true })
public logic: FormFieldLogicEntity[] public logic: FormFieldLogicEntity[]
@Column(() => RatingEmbedded) @Column(() => RatingEmbedded)
public rating: RatingEmbedded = new RatingEmbedded() public rating: RatingEmbedded = new RatingEmbedded()
@OneToMany(() => FormFieldOptionEntity, option => option.field) @OneToMany(() => FormFieldOptionEntity, option => option.field, { eager: true })
public options?: FormFieldOptionEntity[] public options?: FormFieldOptionEntity[]
@Column() @Column()

View File

@ -1,4 +1,4 @@
import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from 'typeorm' import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'
import { FormFieldEntity } from './form.field.entity' import { FormFieldEntity } from './form.field.entity'
type LogicAction = 'visible' | 'require' | 'disable' | 'jumpTo' type LogicAction = 'visible' | 'require' | 'disable' | 'jumpTo'

View File

@ -10,11 +10,11 @@ export class FormHookEntity {
public form: FormEntity public form: FormEntity
@Column() @Column()
readonly enabled: boolean public enabled: boolean
@Column() @Column()
readonly url: string public url: string
@Column({ nullable: true }) @Column({ nullable: true })
readonly format?: string public format?: string
} }

View File

@ -1,10 +1,10 @@
import { ButtonEntity } from './button.entity'
import { FormEntity } from './form.entity' import { FormEntity } from './form.entity'
import { FormFieldEntity } from './form.field.entity' import { FormFieldEntity } from './form.field.entity'
import { FormFieldLogicEntity } from './form.field.logic.entity' import { FormFieldLogicEntity } from './form.field.logic.entity'
import { FormFieldOptionEntity } from './form.field.option.entity' import { FormFieldOptionEntity } from './form.field.option.entity'
import { FormHookEntity } from './form.hook.entity' import { FormHookEntity } from './form.hook.entity'
import { FormNotificationEntity } from './form.notification.entity' import { FormNotificationEntity } from './form.notification.entity'
import { PageButtonEntity } from './page.button.entity'
import { PageEntity } from './page.entity' import { PageEntity } from './page.entity'
import { SubmissionEntity } from './submission.entity' import { SubmissionEntity } from './submission.entity'
import { SubmissionFieldEntity } from './submission.field.entity' import { SubmissionFieldEntity } from './submission.field.entity'
@ -12,13 +12,13 @@ import { UserEntity } from './user.entity'
import { VisitorEntity } from './visitor.entity' import { VisitorEntity } from './visitor.entity'
export const entities = [ export const entities = [
ButtonEntity,
FormEntity, FormEntity,
FormFieldEntity, FormFieldEntity,
FormFieldLogicEntity, FormFieldLogicEntity,
FormFieldOptionEntity, FormFieldOptionEntity,
FormHookEntity, FormHookEntity,
FormNotificationEntity, FormNotificationEntity,
PageButtonEntity,
PageEntity, PageEntity,
SubmissionEntity, SubmissionEntity,
SubmissionFieldEntity, SubmissionFieldEntity,

View File

@ -1,10 +1,14 @@
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm' import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'
import { PageEntity } from './page.entity'
@Entity({ name: 'button' }) @Entity({ name: 'page_button' })
export class ButtonEntity { export class PageButtonEntity {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
public id: number public id: number
@ManyToOne(() => PageEntity, page => page.buttons)
public page: PageEntity
@Column({ nullable: true }) @Column({ nullable: true })
readonly url?: string readonly url?: string

View File

@ -1,5 +1,5 @@
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm' import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm'
import { ButtonEntity } from './button.entity' import { PageButtonEntity } from './page.button.entity'
@Entity({ name: 'page' }) @Entity({ name: 'page' })
export class PageEntity { export class PageEntity {
@ -18,5 +18,6 @@ export class PageEntity {
@Column({ nullable: true }) @Column({ nullable: true })
readonly buttonText?: string readonly buttonText?: string
readonly buttons: ButtonEntity[] @OneToMany(() => PageButtonEntity, button => button.page)
readonly buttons: PageButtonEntity[]
} }

View File

@ -1,25 +1,57 @@
import { Entity, PrimaryGeneratedColumn } from 'typeorm' import {
Column,
CreateDateColumn,
Entity,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
UpdateDateColumn
} from 'typeorm'
import { DeviceEmbedded } from './embedded/device.embedded' import { DeviceEmbedded } from './embedded/device.embedded'
import { GeoLocationEmbedded } from './embedded/geo.location.embedded' import { GeoLocationEmbedded } from './embedded/geo.location.embedded'
import { FormEntity } from './form.entity' import { FormEntity } from './form.entity'
import { SubmissionFieldEntity } from './submission.field.entity' import { SubmissionFieldEntity } from './submission.field.entity'
import { UserEntity } from './user.entity' import { UserEntity } from './user.entity'
import { VisitorEntity } from './visitor.entity'
@Entity({ name: 'submission' }) @Entity({ name: 'submission' })
export class SubmissionEntity { export class SubmissionEntity {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
public id: number public id: number
readonly fields: SubmissionFieldEntity[] @OneToMany(() => SubmissionFieldEntity, field => field.submission, { eager: true })
readonly form: FormEntity public fields: SubmissionFieldEntity[]
readonly ipAddr: string
readonly tokenHash: string
readonly geoLocation: GeoLocationEmbedded
readonly device: DeviceEmbedded
readonly timeElapsed: number
readonly percentageComplete: number
readonly user?: UserEntity @ManyToOne(() => FormEntity, form => form.submissions, { eager: true })
readonly created: Date public form: FormEntity
readonly lastModified: Date
@ManyToOne(() => VisitorEntity, visitor => visitor.submissions)
public visitor: VisitorEntity
@Column()
public ipAddr: string
@Column()
public tokenHash: string
@Column(() => GeoLocationEmbedded)
public geoLocation: GeoLocationEmbedded = new GeoLocationEmbedded()
@Column(() => DeviceEmbedded)
public device: DeviceEmbedded = new DeviceEmbedded()
@Column()
public timeElapsed: number
@Column()
public percentageComplete: number
@ManyToOne(() => UserEntity, { eager: true })
public user?: UserEntity
@CreateDateColumn()
public created: Date
@UpdateDateColumn()
public lastModified: Date
} }

View File

@ -1,13 +1,21 @@
import { Entity, PrimaryGeneratedColumn } from 'typeorm' import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'
import { FormFieldDocument } from '../schema/form.field.schema'
import { FormFieldEntity } from './form.field.entity' import { FormFieldEntity } from './form.field.entity'
import { SubmissionEntity } from './submission.entity'
@Entity({ name: 'submission_field' }) @Entity({ name: 'submission_field' })
export class SubmissionFieldEntity { export class SubmissionFieldEntity {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
public id: number public id: number
readonly field: FormFieldEntity @ManyToOne(() => SubmissionEntity, submission => submission.fields)
readonly fieldType: string public submission: SubmissionEntity
readonly fieldValue: any
@ManyToOne(() => FormFieldEntity, { eager: true })
public field: FormFieldEntity
@Column()
public fieldType: string
@Column()
public fieldValue: string
} }

View File

@ -1,4 +1,4 @@
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm' import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'
import { rolesType } from '../config/roles' import { rolesType } from '../config/roles'
@Entity({ name: 'user' }) @Entity({ name: 'user' })
@ -6,7 +6,10 @@ export class UserEntity {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
public id: number public id: number
@Column({ nullable: true })
public firstName?: string public firstName?: string
@Column({ nullable: true })
public lastName?: string public lastName?: string
@Column({ length: 255, unique: true }) @Column({ length: 255, unique: true })
@ -15,15 +18,36 @@ export class UserEntity {
@Column({ length: 255, unique: true }) @Column({ length: 255, unique: true })
public username: string public username: string
@Column()
public passwordHash: string public passwordHash: string
@Column({ nullable: true })
public salt: string public salt: string
@Column()
public provider: string public provider: string
@Column({ type: 'simple-array' })
public roles: rolesType public roles: rolesType
@Column()
public language: string public language: string
@Column({ nullable: true })
public resetPasswordToken?: string public resetPasswordToken?: string
@Column({ nullable: true })
public resetPasswordExpires?: Date public resetPasswordExpires?: Date
@Column({ nullable: true })
public token?: string public token?: string
@Column({ nullable: true })
public apiKey?: string public apiKey?: string
@CreateDateColumn()
public created: Date public created: Date
@UpdateDateColumn()
public lastModified: Date public lastModified: Date
} }

View File

@ -1,7 +1,16 @@
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm' import {
import { FormFieldDocument } from '../schema/form.field.schema' Column,
CreateDateColumn,
Entity,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
UpdateDateColumn
} from 'typeorm'
import { DeviceEmbedded } from './embedded/device.embedded'
import { GeoLocationEmbedded } from './embedded/geo.location.embedded'
import { FormEntity } from './form.entity' import { FormEntity } from './form.entity'
import { FormFieldEntity } from './form.field.entity' import { SubmissionEntity } from './submission.entity'
@Entity({ name: 'form_visitor' }) @Entity({ name: 'form_visitor' })
export class VisitorEntity { export class VisitorEntity {
@ -11,16 +20,24 @@ export class VisitorEntity {
@ManyToOne(() => FormEntity, form => form.visitors) @ManyToOne(() => FormEntity, form => form.visitors)
public form: FormEntity public form: FormEntity
@ManyToOne(() => FormEntity, form => form.visitors) @OneToMany(() => SubmissionEntity, submission => submission.visitor)
public submission: FormEntity public submissions: SubmissionEntity[]
@Column({ nullable: true }) @Column({ nullable: true })
readonly referrer?: string readonly referrer?: string
readonly timeElapsed: number @Column()
readonly isSubmitted: boolean
readonly language: string
readonly ipAddr: string readonly ipAddr: string
readonly deviceType: string
readonly userAgent: string @Column(() => GeoLocationEmbedded)
public geoLocation: GeoLocationEmbedded = new GeoLocationEmbedded()
@Column(() => DeviceEmbedded)
public device: DeviceEmbedded = new DeviceEmbedded()
@CreateDateColumn()
public created: Date
@UpdateDateColumn()
public updated: Date
} }

View File

@ -1,7 +1,7 @@
import { ExecutionContext, Injectable } from '@nestjs/common'; import { ExecutionContext, Injectable } from '@nestjs/common'
import { GqlExecutionContext } from '@nestjs/graphql'; import { GqlExecutionContext } from '@nestjs/graphql'
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport'
import { ContextCache } from '../resolver/context.cache'; import { ContextCache } from '../resolver/context.cache'
@Injectable() @Injectable()
export class GqlAuthGuard extends AuthGuard('jwt') { export class GqlAuthGuard extends AuthGuard('jwt') {

View File

@ -1,7 +1,7 @@
import { APP_GUARD } from '@nestjs/core'; import { APP_GUARD } from '@nestjs/core'
import { GqlAuthGuard } from './gql.auth.guard'; import { GqlAuthGuard } from './gql.auth.guard'
import { LocalAuthGuard } from './local.auth.guard'; import { LocalAuthGuard } from './local.auth.guard'
import { RolesGuard } from './roles.guard'; import { RolesGuard } from './roles.guard'
export const guards = [ export const guards = [
{ {

View File

@ -1,6 +1,6 @@
import { ExecutionContext, Injectable } from '@nestjs/common'; import { ExecutionContext, Injectable } from '@nestjs/common'
import { GqlExecutionContext } from '@nestjs/graphql'; import { GqlExecutionContext } from '@nestjs/graphql'
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport'
@Injectable() @Injectable()
export class LocalAuthGuard extends AuthGuard('local') { export class LocalAuthGuard extends AuthGuard('local') {

View File

@ -1,6 +1,6 @@
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'
import { Reflector } from '@nestjs/core'; import { Reflector } from '@nestjs/core'
import { GqlExecutionContext } from '@nestjs/graphql'; import { GqlExecutionContext } from '@nestjs/graphql'
@Injectable() @Injectable()
export class RolesGuard implements CanActivate { export class RolesGuard implements CanActivate {

View File

@ -1,9 +1,9 @@
import { NestApplicationOptions, ValidationPipe } from '@nestjs/common'; import { NestApplicationOptions, ValidationPipe } from '@nestjs/common'
import { NestFactory } from '@nestjs/core'; import { NestFactory } from '@nestjs/core'
import cors from 'cors'; import cors from 'cors'
import { Logger, PinoLogger } from 'nestjs-pino/dist'; import { Logger, PinoLogger } from 'nestjs-pino/dist'
import { LoggerConfig } from './app.imports'; import { LoggerConfig } from './app.imports'
import { AppModule } from './app.module'; import { AppModule } from './app.module'
(async () => { (async () => {
const options: NestApplicationOptions = { const options: NestApplicationOptions = {

View File

@ -1,24 +1,35 @@
import { MigrationInterface, QueryRunner, Table } from "typeorm" import { MigrationInterface, QueryRunner } from "typeorm"
export class initial1619723437787 implements MigrationInterface { export class initial1619723437787 implements MigrationInterface {
name = 'initial1619723437787' name = 'initial1619723437787'
public async up(queryRunner: QueryRunner): Promise<void> { public async up(queryRunner: QueryRunner): Promise<void> {
if (queryRunner.connection.driver.options.type === 'sqlite') {
if (queryRunner.connection.driver.options.type !== 'sqlite') { await queryRunner.query(`CREATE TABLE "user" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "firstName" varchar, "lastName" varchar, "email" varchar(255) NOT NULL, "username" varchar(255) NOT NULL, "passwordHash" varchar NOT NULL, "salt" varchar, "provider" varchar NOT NULL, "roles" text NOT NULL, "language" varchar NOT NULL, "resetPasswordToken" varchar, "resetPasswordExpires" datetime, "token" varchar, "apiKey" varchar, "created" datetime NOT NULL DEFAULT (datetime('now')), "lastModified" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_78a916df40e02a9deb1c4b75edb" UNIQUE ("username"), CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"))`);
await queryRunner.query(`CREATE TABLE "button" ("id" SERIAL NOT NULL, "url" VARCHAR, "action" VARCHAR, "text" VARCHAR NOT NULL, "bgColor" VARCHAR, "activeColor" VARCHAR, "color" VARCHAR, CONSTRAINT "PK_a4df4e4f7a5882bc94442d3f209" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE TABLE "page" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "show" boolean NOT NULL, "title" varchar, "paragraph" text, "buttonText" varchar)`);
await queryRunner.query(`CREATE TABLE "form_field_logic" ("id" SERIAL NOT NULL, "formula" VARCHAR NOT NULL, "action" VARCHAR(10) NOT NULL, "visible" boolean, "require" boolean, "disable" boolean, "enabled" boolean NOT NULL, "fieldId" integer, "jumpToId" integer, CONSTRAINT "PK_c40e7f583854ff1b60900d8cf1b" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE TABLE "form_field_logic" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "formula" varchar NOT NULL, "action" varchar(10) NOT NULL, "visible" boolean, "require" boolean, "disable" boolean, "enabled" boolean NOT NULL, "fieldId" integer, "jumpToId" integer, CONSTRAINT "FK_6098b83f6759445d8cfdd03d545" FOREIGN KEY ("fieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_4a8019f2b753cfb3216dc3001a6" FOREIGN KEY ("jumpToId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`CREATE TABLE "form_field_option" ("id" SERIAL NOT NULL, "key" VARCHAR, "title" VARCHAR, "value" VARCHAR NOT NULL, "fieldId" integer, CONSTRAINT "PK_812955356e516819e37b64bf39b" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE TABLE "form_field_option" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "key" varchar, "title" varchar, "value" varchar NOT NULL, "fieldId" integer, CONSTRAINT "FK_c4484ad12c2c56db31dffdbfe97" FOREIGN KEY ("fieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`CREATE TABLE "form_field" ("id" SERIAL NOT NULL, "title" VARCHAR NOT NULL, "description" text NOT NULL, "slug" VARCHAR, "required" boolean NOT NULL, "disabled" boolean NOT NULL, "type" VARCHAR NOT NULL, "value" VARCHAR NOT NULL, "formId" integer, CONSTRAINT "PK_135904ddb60085b07254ea4f485" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE TABLE "form_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "description" text NOT NULL, "slug" varchar, "required" boolean NOT NULL, "disabled" boolean NOT NULL, "type" varchar NOT NULL, "value" varchar NOT NULL, "formId" integer, "ratingSteps" integer, "ratingShape" varchar, CONSTRAINT "FK_2d83d8a334dd66445db13f92b77" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`CREATE TABLE "form_hook" ("id" SERIAL NOT NULL, "enabled" boolean NOT NULL, "url" VARCHAR NOT NULL, "format" VARCHAR, "formId" integer, CONSTRAINT "PK_4b63bd9ff09f7b3e5c4a41fcbec" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE TABLE "form_hook" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "enabled" boolean NOT NULL, "url" varchar NOT NULL, "format" varchar, "formId" integer, CONSTRAINT "FK_bbeb4d224d8857fd5a458538a30" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`CREATE TABLE "form_notification" ("id" SERIAL NOT NULL, "subject" VARCHAR, "htmlTemplate" VARCHAR, "enabled" boolean NOT NULL, "toEmail" VARCHAR, "fromEmail" VARCHAR, "formId" integer, "fromFieldId" integer, "toFieldId" integer, CONSTRAINT "PK_935306529aed07c9f6628f6e24f" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE TABLE "form_notification" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "subject" varchar, "htmlTemplate" varchar, "enabled" boolean NOT NULL, "toEmail" varchar, "fromEmail" varchar, "formId" integer, "fromFieldId" integer, "toFieldId" integer, CONSTRAINT "FK_a9ed55144108ded893b502d6321" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_0876741ce2acdaee4553d7a3bbd" FOREIGN KEY ("fromFieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_4915ebae53e09b732322d0ff6ed" FOREIGN KEY ("toFieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`CREATE TABLE "submission" ("id" SERIAL NOT NULL, CONSTRAINT "PK_7faa571d0e4a7076e85890c9bd0" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE TABLE "submission_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "fieldType" varchar NOT NULL, "fieldValue" varchar NOT NULL, "submissionId" integer, "fieldId" integer, CONSTRAINT "FK_16fae661ce5b10f27abe2e524a0" FOREIGN KEY ("submissionId") REFERENCES "submission" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_5befa92da2370b7eb1cab6ae30a" FOREIGN KEY ("fieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`CREATE TABLE "form_visitor" ("id" SERIAL NOT NULL, "referrer" VARCHAR, "formId" integer, "submissionId" integer, CONSTRAINT "PK_74224dc63e13cf5cb5f0420e65b" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE TABLE "form_visitor" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "referrer" varchar, "ipAddr" varchar NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "updated" datetime NOT NULL DEFAULT (datetime('now')), "formId" integer, "geoLocationCountry" varchar, "geoLocationCity" varchar, "deviceLanguage" varchar, "deviceType" varchar, "deviceName" varchar, CONSTRAINT "FK_72ade6c3a3e55d1fce94300f8b6" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`CREATE TABLE "page" ("id" SERIAL NOT NULL, "show" boolean NOT NULL, "title" VARCHAR, "paragraph" text, "buttonText" VARCHAR, CONSTRAINT "PK_742f4117e065c5b6ad21b37ba1f" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE TABLE "submission" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "ipAddr" varchar NOT NULL, "tokenHash" varchar NOT NULL, "timeElapsed" integer NOT NULL, "percentageComplete" integer NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "lastModified" datetime NOT NULL DEFAULT (datetime('now')), "formId" integer, "visitorId" integer, "userId" integer, "geoLocationCountry" varchar, "geoLocationCity" varchar, "deviceLanguage" varchar, "deviceType" varchar, "deviceName" varchar, CONSTRAINT "FK_7bd626272858ef6464aa2579094" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_95b73c7faf2c199f005fda5e8c8" FOREIGN KEY ("visitorId") REFERENCES "form_visitor" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_6090e1d5cbf3433ffd14e3b53e7" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`CREATE TABLE "user" ("id" SERIAL NOT NULL, "email" VARCHAR(255) NOT NULL, "username" VARCHAR(255) NOT NULL, CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"), CONSTRAINT "UQ_78a916df40e02a9deb1c4b75edb" UNIQUE ("username"), CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE TABLE "page_button" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "url" varchar, "action" varchar, "text" varchar NOT NULL, "bgColor" varchar, "activeColor" varchar, "color" varchar, "pageId" integer, CONSTRAINT "FK_d9f099286b75fa0034dcd8cf7c2" FOREIGN KEY ("pageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`CREATE TABLE "form" ("id" SERIAL NOT NULL, "title" VARCHAR NOT NULL, "language" VARCHAR(10) NOT NULL, "showFooter" boolean NOT NULL, "isLive" boolean NOT NULL, "created" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "lastModified" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "adminId" integer, "startPageId" integer, "endPageId" integer, CONSTRAINT "PK_8f72b95aa2f8ba82cf95dc7579e" PRIMARY KEY ("id"))`); await queryRunner.query(`CREATE TABLE "form" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "language" varchar(10) NOT NULL, "showFooter" boolean NOT NULL, "isLive" boolean NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "lastModified" datetime NOT NULL DEFAULT (datetime('now')), "adminId" integer, "startPageId" integer, "endPageId" integer, "analyticsGacode" varchar, "designFont" varchar, "designColorsBackground" varchar, "designColorsQuestion" varchar, "designColorsAnswer" varchar, "designColorsButton" varchar, "designColorsButtonactive" varchar, "designColorsButtontext" varchar, CONSTRAINT "FK_a7cb33580bca2b362e5e34fdfcd" FOREIGN KEY ("adminId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_023d9cf1d97e93facc96c86ca70" FOREIGN KEY ("startPageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_e5d158932e43cfbf9958931ee01" FOREIGN KEY ("endPageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`CREATE TABLE "submission_field" ("id" SERIAL NOT NULL, CONSTRAINT "PK_5443f5f769fce3107982c16e0b5" PRIMARY KEY ("id"))`); } else {
await queryRunner.query(`CREATE TABLE "form_field_logic" ("id" SERIAL NOT NULL, "formula" character varying NOT NULL, "action" character varying(10) NOT NULL, "visible" boolean, "require" boolean, "disable" boolean, "enabled" boolean NOT NULL, "fieldId" integer, "jumpToId" integer, CONSTRAINT "PK_c40e7f583854ff1b60900d8cf1b" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TABLE "form_field_option" ("id" SERIAL NOT NULL, "key" character varying, "title" character varying, "value" character varying NOT NULL, "fieldId" integer, CONSTRAINT "PK_812955356e516819e37b64bf39b" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TABLE "form_field" ("id" SERIAL NOT NULL, "title" character varying NOT NULL, "description" text NOT NULL, "slug" character varying, "required" boolean NOT NULL, "disabled" boolean NOT NULL, "type" character varying NOT NULL, "value" character varying NOT NULL, "formId" integer, "ratingSteps" integer, "ratingShape" character varying, CONSTRAINT "PK_135904ddb60085b07254ea4f485" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TABLE "form_hook" ("id" SERIAL NOT NULL, "enabled" boolean NOT NULL, "url" character varying NOT NULL, "format" character varying, "formId" integer, CONSTRAINT "PK_4b63bd9ff09f7b3e5c4a41fcbec" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TABLE "form_notification" ("id" SERIAL NOT NULL, "subject" character varying, "htmlTemplate" character varying, "enabled" boolean NOT NULL, "toEmail" character varying, "fromEmail" character varying, "formId" integer, "fromFieldId" integer, "toFieldId" integer, CONSTRAINT "PK_935306529aed07c9f6628f6e24f" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TABLE "submission_field" ("id" SERIAL NOT NULL, "fieldType" character varying NOT NULL, "fieldValue" character varying NOT NULL, "submissionId" integer, "fieldId" integer, CONSTRAINT "PK_5443f5f769fce3107982c16e0b5" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TABLE "user" ("id" SERIAL NOT NULL, "firstName" character varying, "lastName" character varying, "email" character varying(255) NOT NULL, "username" character varying(255) NOT NULL, "passwordHash" character varying NOT NULL, "salt" character varying, "provider" character varying NOT NULL, "roles" character varying(10) NOT NULL, "language" character varying NOT NULL, "resetPasswordToken" character varying, "resetPasswordExpires" TIMESTAMP, "token" character varying, "apiKey" character varying, "created" TIMESTAMP NOT NULL DEFAULT now(), "lastModified" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"), CONSTRAINT "UQ_78a916df40e02a9deb1c4b75edb" UNIQUE ("username"), CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TABLE "form_visitor" ("id" SERIAL NOT NULL, "referrer" character varying, "ipAddr" character varying NOT NULL, "created" TIMESTAMP NOT NULL DEFAULT now(), "updated" TIMESTAMP NOT NULL DEFAULT now(), "formId" integer, "geoLocationCountry" character varying, "geoLocationCity" character varying, CONSTRAINT "PK_74224dc63e13cf5cb5f0420e65b" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TABLE "submission" ("id" SERIAL NOT NULL, "ipAddr" character varying NOT NULL, "tokenHash" character varying NOT NULL, "timeElapsed" integer NOT NULL, "percentageComplete" integer NOT NULL, "created" TIMESTAMP NOT NULL DEFAULT now(), "lastModified" TIMESTAMP NOT NULL DEFAULT now(), "formId" integer, "visitorId" integer, "userId" integer, "geoLocationCountry" character varying, "geoLocationCity" character varying, CONSTRAINT "PK_7faa571d0e4a7076e85890c9bd0" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TABLE "page_button" ("id" SERIAL NOT NULL, "url" character varying, "action" character varying, "text" character varying NOT NULL, "bgColor" character varying, "activeColor" character varying, "color" character varying, "pageId" integer, CONSTRAINT "PK_6609a75a7d82775aac8af1a591c" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TABLE "page" ("id" SERIAL NOT NULL, "show" boolean NOT NULL, "title" character varying, "paragraph" text, "buttonText" character varying, CONSTRAINT "PK_742f4117e065c5b6ad21b37ba1f" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE TABLE "form" ("id" SERIAL NOT NULL, "title" character varying NOT NULL, "language" character varying(10) NOT NULL, "showFooter" boolean NOT NULL, "isLive" boolean NOT NULL, "created" TIMESTAMP NOT NULL DEFAULT now(), "lastModified" TIMESTAMP NOT NULL DEFAULT now(), "adminId" integer, "startPageId" integer, "endPageId" integer, "analyticsGacode" character varying, "designFont" character varying, "designColorsBackground" character varying, "designColorsQuestion" character varying, "designColorsAnswer" character varying, "designColorsButton" character varying, "designColorsButtonactive" character varying, "designColorsButtontext" character varying, CONSTRAINT "PK_8f72b95aa2f8ba82cf95dc7579e" PRIMARY KEY ("id"))`);
await queryRunner.query(`ALTER TABLE "form_field_logic" ADD CONSTRAINT "FK_6098b83f6759445d8cfdd03d545" FOREIGN KEY ("fieldId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); await queryRunner.query(`ALTER TABLE "form_field_logic" ADD CONSTRAINT "FK_6098b83f6759445d8cfdd03d545" FOREIGN KEY ("fieldId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "form_field_logic" ADD CONSTRAINT "FK_4a8019f2b753cfb3216dc3001a6" FOREIGN KEY ("jumpToId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); await queryRunner.query(`ALTER TABLE "form_field_logic" ADD CONSTRAINT "FK_4a8019f2b753cfb3216dc3001a6" FOREIGN KEY ("jumpToId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "form_field_option" ADD CONSTRAINT "FK_c4484ad12c2c56db31dffdbfe97" FOREIGN KEY ("fieldId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); await queryRunner.query(`ALTER TABLE "form_field_option" ADD CONSTRAINT "FK_c4484ad12c2c56db31dffdbfe97" FOREIGN KEY ("fieldId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
@ -27,24 +38,27 @@ export class initial1619723437787 implements MigrationInterface {
await queryRunner.query(`ALTER TABLE "form_notification" ADD CONSTRAINT "FK_a9ed55144108ded893b502d6321" FOREIGN KEY ("formId") REFERENCES "form"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); await queryRunner.query(`ALTER TABLE "form_notification" ADD CONSTRAINT "FK_a9ed55144108ded893b502d6321" FOREIGN KEY ("formId") REFERENCES "form"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "form_notification" ADD CONSTRAINT "FK_0876741ce2acdaee4553d7a3bbd" FOREIGN KEY ("fromFieldId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); await queryRunner.query(`ALTER TABLE "form_notification" ADD CONSTRAINT "FK_0876741ce2acdaee4553d7a3bbd" FOREIGN KEY ("fromFieldId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "form_notification" ADD CONSTRAINT "FK_4915ebae53e09b732322d0ff6ed" FOREIGN KEY ("toFieldId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); await queryRunner.query(`ALTER TABLE "form_notification" ADD CONSTRAINT "FK_4915ebae53e09b732322d0ff6ed" FOREIGN KEY ("toFieldId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "submission_field" ADD CONSTRAINT "FK_16fae661ce5b10f27abe2e524a0" FOREIGN KEY ("submissionId") REFERENCES "submission"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "submission_field" ADD CONSTRAINT "FK_5befa92da2370b7eb1cab6ae30a" FOREIGN KEY ("fieldId") REFERENCES "form_field"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "form_visitor" ADD CONSTRAINT "FK_72ade6c3a3e55d1fce94300f8b6" FOREIGN KEY ("formId") REFERENCES "form"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); await queryRunner.query(`ALTER TABLE "form_visitor" ADD CONSTRAINT "FK_72ade6c3a3e55d1fce94300f8b6" FOREIGN KEY ("formId") REFERENCES "form"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "form_visitor" ADD CONSTRAINT "FK_cc7e7beb67c46f65d57289b121d" FOREIGN KEY ("submissionId") REFERENCES "form"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); await queryRunner.query(`ALTER TABLE "submission" ADD CONSTRAINT "FK_6090e1d5cbf3433ffd14e3b53e7" FOREIGN KEY ("formId") REFERENCES "form"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "submission" ADD CONSTRAINT "FK_95b73c7faf2c199f005fda5e8c8" FOREIGN KEY ("visitorId") REFERENCES "form_visitor"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "submission" ADD CONSTRAINT "FK_7bd626272858ef6464aa2579094" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "page_button" ADD CONSTRAINT "FK_d9f099286b75fa0034dcd8cf7c2" FOREIGN KEY ("pageId") REFERENCES "page"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "form" ADD CONSTRAINT "FK_a7cb33580bca2b362e5e34fdfcd" FOREIGN KEY ("adminId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); await queryRunner.query(`ALTER TABLE "form" ADD CONSTRAINT "FK_a7cb33580bca2b362e5e34fdfcd" FOREIGN KEY ("adminId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "form" ADD CONSTRAINT "FK_023d9cf1d97e93facc96c86ca70" FOREIGN KEY ("startPageId") REFERENCES "page"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); await queryRunner.query(`ALTER TABLE "form" ADD CONSTRAINT "FK_023d9cf1d97e93facc96c86ca70" FOREIGN KEY ("startPageId") REFERENCES "page"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "form" ADD CONSTRAINT "FK_e5d158932e43cfbf9958931ee01" FOREIGN KEY ("endPageId") REFERENCES "page"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); await queryRunner.query(`ALTER TABLE "form" ADD CONSTRAINT "FK_e5d158932e43cfbf9958931ee01" FOREIGN KEY ("endPageId") REFERENCES "page"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
} else {
await queryRunner.query(`CREATE TABLE "button" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "url" varchar, "action" varchar, "text" varchar NOT NULL, "bgColor" varchar, "activeColor" varchar, "color" varchar)`);
await queryRunner.query(`CREATE TABLE "submission" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL)`); await queryRunner.query(`ALTER TABLE "form_visitor" ADD "deviceLanguage" character varying`);
await queryRunner.query(`CREATE TABLE "page" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "show" boolean NOT NULL, "title" varchar, "paragraph" text, "buttonText" varchar)`); await queryRunner.query(`ALTER TABLE "form_visitor" ADD "deviceType" character varying`);
await queryRunner.query(`CREATE TABLE "user" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "email" varchar(255) NOT NULL, "username" varchar(255) NOT NULL, CONSTRAINT "UQ_78a916df40e02a9deb1c4b75edb" UNIQUE ("username"), CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"))`); await queryRunner.query(`ALTER TABLE "form_visitor" ADD "deviceName" character varying`);
await queryRunner.query(`CREATE TABLE "form" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "language" varchar(10) NOT NULL, "showFooter" boolean NOT NULL, "isLive" boolean NOT NULL, "created" datetime NOT NULL DEFAULT (datetime('now')), "lastModified" datetime NOT NULL DEFAULT (datetime('now')), "adminId" integer, "startPageId" integer, "endPageId" integer, CONSTRAINT "FK_a7cb33580bca2b362e5e34fdfcd" FOREIGN KEY ("adminId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_023d9cf1d97e93facc96c86ca70" FOREIGN KEY ("startPageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_e5d158932e43cfbf9958931ee01" FOREIGN KEY ("endPageId") REFERENCES "page" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); await queryRunner.query(`ALTER TABLE "submission" ADD "deviceLanguage" character varying`);
await queryRunner.query(`CREATE TABLE "submission_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL)`); await queryRunner.query(`ALTER TABLE "submission" ADD "deviceType" character varying`);
await queryRunner.query(`CREATE TABLE "form_field_logic" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "formula" varchar NOT NULL, "action" varchar(10) NOT NULL, "visible" boolean, "require" boolean, "disable" boolean, "enabled" boolean NOT NULL, "fieldId" integer, "jumpToId" integer, CONSTRAINT "FK_6098b83f6759445d8cfdd03d545" FOREIGN KEY ("fieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_4a8019f2b753cfb3216dc3001a6" FOREIGN KEY ("jumpToId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); await queryRunner.query(`ALTER TABLE "submission" ADD "deviceName" character varying`);
await queryRunner.query(`CREATE TABLE "form_field_option" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "key" varchar, "title" varchar, "value" varchar NOT NULL, "fieldId" integer, CONSTRAINT "FK_c4484ad12c2c56db31dffdbfe97" FOREIGN KEY ("fieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`CREATE TABLE "form_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar NOT NULL, "description" text NOT NULL, "slug" varchar, "required" boolean NOT NULL, "disabled" boolean NOT NULL, "type" varchar NOT NULL, "value" varchar NOT NULL, "formId" integer, CONSTRAINT "FK_2d83d8a334dd66445db13f92b77" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "roles"`);
await queryRunner.query(`CREATE TABLE "form_hook" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "enabled" boolean NOT NULL, "url" varchar NOT NULL, "format" varchar, "formId" integer, CONSTRAINT "FK_bbeb4d224d8857fd5a458538a30" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`); await queryRunner.query(`ALTER TABLE "user" ADD "roles" text NOT NULL`);
await queryRunner.query(`CREATE TABLE "form_notification" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "subject" varchar, "htmlTemplate" varchar, "enabled" boolean NOT NULL, "toEmail" varchar, "fromEmail" varchar, "formId" integer, "fromFieldId" integer, "toFieldId" integer, CONSTRAINT "FK_a9ed55144108ded893b502d6321" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_0876741ce2acdaee4553d7a3bbd" FOREIGN KEY ("fromFieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_4915ebae53e09b732322d0ff6ed" FOREIGN KEY ("toFieldId") REFERENCES "form_field" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`CREATE TABLE "form_visitor" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "referrer" varchar, "formId" integer, "submissionId" integer, CONSTRAINT "FK_72ade6c3a3e55d1fce94300f8b6" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_cc7e7beb67c46f65d57289b121d" FOREIGN KEY ("submissionId") REFERENCES "form" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
} }
} }
@ -53,8 +67,13 @@ export class initial1619723437787 implements MigrationInterface {
await queryRunner.query(`ALTER TABLE "form" DROP CONSTRAINT "FK_e5d158932e43cfbf9958931ee01"`); await queryRunner.query(`ALTER TABLE "form" DROP CONSTRAINT "FK_e5d158932e43cfbf9958931ee01"`);
await queryRunner.query(`ALTER TABLE "form" DROP CONSTRAINT "FK_023d9cf1d97e93facc96c86ca70"`); await queryRunner.query(`ALTER TABLE "form" DROP CONSTRAINT "FK_023d9cf1d97e93facc96c86ca70"`);
await queryRunner.query(`ALTER TABLE "form" DROP CONSTRAINT "FK_a7cb33580bca2b362e5e34fdfcd"`); await queryRunner.query(`ALTER TABLE "form" DROP CONSTRAINT "FK_a7cb33580bca2b362e5e34fdfcd"`);
await queryRunner.query(`ALTER TABLE "form_visitor" DROP CONSTRAINT "FK_cc7e7beb67c46f65d57289b121d"`); await queryRunner.query(`ALTER TABLE "page_button" DROP CONSTRAINT "FK_d9f099286b75fa0034dcd8cf7c2"`);
await queryRunner.query(`ALTER TABLE "submission" DROP CONSTRAINT "FK_7bd626272858ef6464aa2579094"`);
await queryRunner.query(`ALTER TABLE "submission" DROP CONSTRAINT "FK_95b73c7faf2c199f005fda5e8c8"`);
await queryRunner.query(`ALTER TABLE "submission" DROP CONSTRAINT "FK_6090e1d5cbf3433ffd14e3b53e7"`);
await queryRunner.query(`ALTER TABLE "form_visitor" DROP CONSTRAINT "FK_72ade6c3a3e55d1fce94300f8b6"`); await queryRunner.query(`ALTER TABLE "form_visitor" DROP CONSTRAINT "FK_72ade6c3a3e55d1fce94300f8b6"`);
await queryRunner.query(`ALTER TABLE "submission_field" DROP CONSTRAINT "FK_5befa92da2370b7eb1cab6ae30a"`);
await queryRunner.query(`ALTER TABLE "submission_field" DROP CONSTRAINT "FK_16fae661ce5b10f27abe2e524a0"`);
await queryRunner.query(`ALTER TABLE "form_notification" DROP CONSTRAINT "FK_4915ebae53e09b732322d0ff6ed"`); await queryRunner.query(`ALTER TABLE "form_notification" DROP CONSTRAINT "FK_4915ebae53e09b732322d0ff6ed"`);
await queryRunner.query(`ALTER TABLE "form_notification" DROP CONSTRAINT "FK_0876741ce2acdaee4553d7a3bbd"`); await queryRunner.query(`ALTER TABLE "form_notification" DROP CONSTRAINT "FK_0876741ce2acdaee4553d7a3bbd"`);
await queryRunner.query(`ALTER TABLE "form_notification" DROP CONSTRAINT "FK_a9ed55144108ded893b502d6321"`); await queryRunner.query(`ALTER TABLE "form_notification" DROP CONSTRAINT "FK_a9ed55144108ded893b502d6321"`);
@ -65,18 +84,17 @@ export class initial1619723437787 implements MigrationInterface {
await queryRunner.query(`ALTER TABLE "form_field_logic" DROP CONSTRAINT "FK_6098b83f6759445d8cfdd03d545"`); await queryRunner.query(`ALTER TABLE "form_field_logic" DROP CONSTRAINT "FK_6098b83f6759445d8cfdd03d545"`);
} }
await queryRunner.query(`DROP TABLE "submission_field"`);
await queryRunner.query(`DROP TABLE "form"`); await queryRunner.query(`DROP TABLE "form"`);
await queryRunner.query(`DROP TABLE "user"`);
await queryRunner.query(`DROP TABLE "page"`); await queryRunner.query(`DROP TABLE "page"`);
await queryRunner.query(`DROP TABLE "form_visitor"`); await queryRunner.query(`DROP TABLE "page_button"`);
await queryRunner.query(`DROP TABLE "submission"`); await queryRunner.query(`DROP TABLE "submission"`);
await queryRunner.query(`DROP TABLE "form_visitor"`);
await queryRunner.query(`DROP TABLE "user"`);
await queryRunner.query(`DROP TABLE "submission_field"`);
await queryRunner.query(`DROP TABLE "form_notification"`); await queryRunner.query(`DROP TABLE "form_notification"`);
await queryRunner.query(`DROP TABLE "form_hook"`); await queryRunner.query(`DROP TABLE "form_hook"`);
await queryRunner.query(`DROP TABLE "form_field"`); await queryRunner.query(`DROP TABLE "form_field"`);
await queryRunner.query(`DROP TABLE "form_field_option"`); await queryRunner.query(`DROP TABLE "form_field_option"`);
await queryRunner.query(`DROP TABLE "form_field_logic"`); await queryRunner.query(`DROP TABLE "form_field_logic"`);
await queryRunner.query(`DROP TABLE "button"`);
} }
} }

View File

@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common'
import { Args, Mutation } from '@nestjs/graphql'; import { Args, Mutation } from '@nestjs/graphql'
import { AuthJwtModel } from '../../dto/auth/auth.jwt.model'; import { AuthJwtModel } from '../../dto/auth/auth.jwt.model'
import { AuthService } from '../../service/auth/auth.service'; import { AuthService } from '../../service/auth/auth.service'
@Injectable() @Injectable()
export class AuthLoginResolver { export class AuthLoginResolver {
@ -12,8 +12,8 @@ export class AuthLoginResolver {
@Mutation(() => AuthJwtModel) @Mutation(() => AuthJwtModel)
async authLogin( async authLogin(
@Args({ name: 'username', type: () => String }) username, @Args({ name: 'username', type: () => String }) username: string,
@Args({ name: 'password', type: () => String }) password, @Args({ name: 'password', type: () => String }) password: string,
): Promise<AuthJwtModel> { ): Promise<AuthJwtModel> {
const user = await this.auth.validateUser(username, password) const user = await this.auth.validateUser(username, password)

View File

@ -1,11 +1,11 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common'
import { Args, Mutation } from '@nestjs/graphql'; import { Args, Mutation } from '@nestjs/graphql'
import { PinoLogger } from 'nestjs-pino/dist'; import { PinoLogger } from 'nestjs-pino/dist'
import { AuthJwtModel } from '../../dto/auth/auth.jwt.model'; import { AuthJwtModel } from '../../dto/auth/auth.jwt.model'
import { UserCreateInput } from '../../dto/user/user.create.input'; import { UserCreateInput } from '../../dto/user/user.create.input'
import { AuthService } from '../../service/auth/auth.service'; import { AuthService } from '../../service/auth/auth.service'
import {SettingService} from '../../service/setting.service' import { SettingService } from '../../service/setting.service'
import { UserCreateService } from '../../service/user/user.create.service'; import { UserCreateService } from '../../service/user/user.create.service'
@Injectable() @Injectable()
export class AuthRegisterResolver { export class AuthRegisterResolver {

View File

@ -1,5 +1,5 @@
import { AuthLoginResolver } from './auth.login.resolver'; import { AuthLoginResolver } from './auth.login.resolver'
import { AuthRegisterResolver } from './auth.register.resolver'; import { AuthRegisterResolver } from './auth.register.resolver'
export const authServices = [ export const authServices = [
AuthRegisterResolver, AuthRegisterResolver,

View File

@ -1,67 +1,29 @@
import { FormFieldDocument } from '../schema/form.field.schema';
import { FormDocument } from '../schema/form.schema';
import { SubmissionFieldDocument } from '../schema/submission.field.schema';
import { SubmissionDocument } from '../schema/submission.schema';
import { UserDocument } from '../schema/user.schema';
export class ContextCache { type ID = string | number
private users: {
[id: string]: UserDocument, export class ContextCache<A = any> {
private cache: {
[key: string]: any
} = {} } = {}
private forms: { public getCacheKey(type: string, id: ID): string {
[id: string]: FormDocument, return `${type}:${id}`
} = {}
private submissions: {
[id: string]: SubmissionDocument,
} = {}
private submissionFields: {
[id: string]: SubmissionFieldDocument,
} = {}
private formFields: {
[id: string]: FormFieldDocument,
} = {}
public addUser(user: UserDocument) {
this.users[user.id] = user;
} }
public async getUser(id: any): Promise<UserDocument> { public add<B = A>(key: string, element: B): void {
return this.users[id] this.cache[key] = element
} }
public addForm(form: FormDocument) { public get<B = A>(key: string, init?: () => Promise<B>): B | Promise<B> {
this.forms[form.id] = form if (!this.cache[key] && init) {
const result = init()
void result.then(r => {
this.cache[key] = r
})
return result
} }
public async getForm(id: any): Promise<FormDocument> { return this.cache[key]
return this.forms[id]
}
public addSubmission(submission: SubmissionDocument) {
this.submissions[submission.id] = submission
}
public async getSubmission(id: any): Promise<SubmissionDocument> {
return this.submissions[id]
}
public addFormField(field: FormFieldDocument) {
this.formFields[field.id] = field
}
public async getFormField(id: any): Promise<FormFieldDocument> {
return this.formFields[id]
}
public addSubmissionField(field: SubmissionFieldDocument) {
this.submissionFields[field.id] = field
}
public async getSubmissionField(id: any): Promise<SubmissionFieldDocument> {
return this.submissionFields[id]
} }
} }

View File

@ -1,12 +1,13 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common'
import { Args, Context, Mutation } from '@nestjs/graphql'; import { Args, Context, Mutation } from '@nestjs/graphql'
import { Roles } from '../../decorator/roles.decorator'; import { Roles } from '../../decorator/roles.decorator'
import { User } from '../../decorator/user.decorator'; import { User } from '../../decorator/user.decorator'
import { FormCreateInput } from '../../dto/form/form.create.input'; import { FormCreateInput } from '../../dto/form/form.create.input'
import { FormModel } from '../../dto/form/form.model'; import { FormModel } from '../../dto/form/form.model'
import { UserDocument } from '../../schema/user.schema'; import { FormEntity } from '../../entity/form.entity'
import { FormCreateService } from '../../service/form/form.create.service'; import { UserEntity } from '../../entity/user.entity'
import { ContextCache } from '../context.cache'; import { FormCreateService } from '../../service/form/form.create.service'
import { ContextCache } from '../context.cache'
@Injectable() @Injectable()
export class FormCreateMutation { export class FormCreateMutation {
@ -18,13 +19,13 @@ export class FormCreateMutation {
@Mutation(() => FormModel) @Mutation(() => FormModel)
@Roles('admin') @Roles('admin')
async createForm( async createForm(
@User() user: UserDocument, @User() user: UserEntity,
@Args({ name: 'form', type: () => FormCreateInput }) input: FormCreateInput, @Args({ name: 'form', type: () => FormCreateInput }) input: FormCreateInput,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,
): Promise<FormModel> { ): Promise<FormModel> {
const form = await this.createService.create(user, input) const form = await this.createService.create(user, input)
cache.addForm(form) cache.add(cache.getCacheKey(FormEntity.name, form.id), form)
return new FormModel(form) return new FormModel(form)
} }

View File

@ -1,11 +1,11 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common'
import { Args, ID, Mutation } from '@nestjs/graphql'; import { Args, ID, Mutation } from '@nestjs/graphql'
import { Roles } from '../../decorator/roles.decorator'; import { Roles } from '../../decorator/roles.decorator'
import { User } from '../../decorator/user.decorator'; import { User } from '../../decorator/user.decorator'
import { DeletedModel } from '../../dto/deleted.model'; import { DeletedModel } from '../../dto/deleted.model'
import { UserDocument } from '../../schema/user.schema'; import { UserEntity } from '../../entity/user.entity'
import { FormDeleteService } from '../../service/form/form.delete.service'; import { FormDeleteService } from '../../service/form/form.delete.service'
import { FormService } from '../../service/form/form.service'; import { FormService } from '../../service/form/form.service'
@Injectable() @Injectable()
export class FormDeleteMutation { export class FormDeleteMutation {
@ -18,9 +18,9 @@ export class FormDeleteMutation {
@Mutation(() => DeletedModel) @Mutation(() => DeletedModel)
@Roles('admin') @Roles('admin')
async deleteForm( async deleteForm(
@User() user: UserDocument, @User() user: UserEntity,
@Args({ name: 'id', type: () => ID}) id: string, @Args({ name: 'id', type: () => ID}) id: string,
) { ): Promise<DeletedModel> {
const form = await this.formService.findById(id) const form = await this.formService.findById(id)
if (!form.isLive && !await this.formService.isAdmin(form, user)) { if (!form.isLive && !await this.formService.isAdmin(form, user)) {

View File

@ -0,0 +1,39 @@
import { Args, Context, ID, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql'
import { Roles } from '../../decorator/roles.decorator'
import { User } from '../../decorator/user.decorator'
import { DesignModel } from '../../dto/form/design.model'
import { FormFieldModel } from '../../dto/form/form.field.model'
import { FormHookModel } from '../../dto/form/form.hook.model'
import { FormModel } from '../../dto/form/form.model'
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 { UserEntity } from '../../entity/user.entity'
import { FormService } from '../../service/form/form.service'
import { ContextCache } from '../context.cache'
@Resolver(() => FormModel)
export class FormResolver {
constructor(
private readonly formService: FormService,
) {
}
@Query(() => FormModel)
async getFormById(
@User() user: UserEntity,
@Args('id', {type: () => ID}) id,
@Context('cache') cache: ContextCache,
): Promise<FormModel> {
const form = await this.formService.findById(id)
if (!form.isLive && !await this.formService.isAdmin(form, user)) {
throw new Error('invalid form')
}
cache.add(cache.getCacheKey(FormEntity.name, form.id), form)
return new FormModel(form)
}
}

Some files were not shown because too many files have changed in this diff Show More