diff --git a/ormconfig_pg.json b/ormconfig_pg.json new file mode 100644 index 0000000..622cda3 --- /dev/null +++ b/ormconfig_pg.json @@ -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" + } +} diff --git a/ormconfig_sqlite.json b/ormconfig_sqlite.json new file mode 100644 index 0000000..034d514 --- /dev/null +++ b/ormconfig_sqlite.json @@ -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" + } +} diff --git a/package.json b/package.json index d8c293e..6c9572c 100644 --- a/package.json +++ b/package.json @@ -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" }, "dependencies": { + "@apollo/gateway": "^0.27.1", "@nestjs-modules/mailer": "^1.6.0", "@nestjs/common": "^7.6.15", "@nestjs/config": "^0.6.3", "@nestjs/core": "^7.6.15", "@nestjs/graphql": "^7.10.6", "@nestjs/jwt": "^7.2.0", - "@nestjs/mongoose": "^7.2.4", "@nestjs/passport": "^7.1.5", "@nestjs/platform-express": "^7.6.15", "@nestjs/serve-static": "^2.1.4", @@ -52,9 +52,7 @@ "inquirer": "^8.0.0", "ioredis": "^4.27.1", "matomo-tracker": "^2.2.4", - "migrate-mongoose": "^4.0.0", "mjml": "^4.9.1", - "mongoose": "^5.12.6", "mysql2": "^2.2.5", "nestjs-console": "^4.0.0", "nestjs-pino": "^1.4.0", @@ -75,13 +73,11 @@ "@nestjs/schematics": "^7.3.1", "@nestjs/testing": "^7.6.15", "@types/bcrypt": "^3.0.1", - "@types/express": "^4.17.11", "@types/express-serve-static-core": "^4.17.19", "@types/handlebars": "^4.1.0", "@types/html-to-text": "^6.0.0", "@types/inquirer": "^7.3.1", "@types/jest": "26.0.23", - "@types/mongoose": "^5.10.5", "@types/node": "^15.0.1", "@types/passport-jwt": "^3.0.5", "@types/passport-local": "^1.0.33", diff --git a/src/app.imports.ts b/src/app.imports.ts index 1f61c20..6d1b781 100644 --- a/src/app.imports.ts +++ b/src/app.imports.ts @@ -1,21 +1,17 @@ -import { MailerModule } from '@nestjs-modules/mailer'; -import { HttpModule, RequestMethod } from '@nestjs/common'; -import { ConfigModule, ConfigService } from '@nestjs/config'; -import { GraphQLModule } from '@nestjs/graphql'; -import { JwtModule, JwtModuleOptions } from '@nestjs/jwt'; -import { MongooseModule } from '@nestjs/mongoose'; -import { MongooseModuleOptions } from '@nestjs/mongoose/dist/interfaces/mongoose-options.interface'; -import { ServeStaticModule } from '@nestjs/serve-static'; +import { MailerModule } from '@nestjs-modules/mailer' +import { HttpModule, RequestMethod } from '@nestjs/common' +import { ConfigModule, ConfigService } from '@nestjs/config' +import { GraphQLModule } from '@nestjs/graphql' +import { JwtModule, JwtModuleOptions } from '@nestjs/jwt' +import { ServeStaticModule } from '@nestjs/serve-static' import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm' -import crypto from 'crypto'; -import { Request } from 'express-serve-static-core'; -import { IncomingHttpHeaders } from 'http'; -import { ConsoleModule } from 'nestjs-console'; -import { LoggerModule, Params as LoggerModuleParams } from 'nestjs-pino/dist'; -import { join } from 'path'; -import { DatabaseType } from 'typeorm' +import crypto from 'crypto' +import { Request } from 'express-serve-static-core' +import { IncomingHttpHeaders } from 'http' +import { ConsoleModule } from 'nestjs-console' +import { LoggerModule, Params as LoggerModuleParams } from 'nestjs-pino/dist' +import { join } from 'path' import { entities } from './entity' -import { schema } from './schema'; export const LoggerConfig: LoggerModuleParams = { pinoHttp: { @@ -110,31 +106,19 @@ export const imports = [ imports: [ConfigModule], inject: [ConfigService], useFactory: (configService: ConfigService): TypeOrmModuleOptions => ({ - name: 'ohmyform', - url: configService.get('DB_URI', 'sqlite://data.sqlite') as any, - entityPrefix: configService.get('DB_TABLE_PREFIX', ''), - logging: configService.get('DB_LOGGING', 'false') === 'true', - entities, - migrationsTableName: 'nest_migrations', - migrations: [ - `${__dirname}/**/migrations/**/*{.ts,.js}`, - ], - migrationsRun: configService.get('DB_MIGRATE', true), - }), + name: 'ohmyform', + type: configService.get('DB_TYPE', 'sqlite') as any, + url: configService.get('DB_URI', 'sqlite://data.sqlite'), + entityPrefix: configService.get('DB_TABLE_PREFIX', ''), + logging: configService.get('DB_LOGGING', 'false') === 'true', + entities, + migrations: [ + `${__dirname}/**/migrations/**/*{.ts,.js}`, + ], + migrationsRun: configService.get('DB_MIGRATE', true), + }), }), - MongooseModule.forRootAsync({ - imports: [ConfigModule], - inject: [ConfigService], - useFactory: async (configService: ConfigService): Promise => ({ - uri: configService.get('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), + TypeOrmModule.forFeature(entities), MailerModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], diff --git a/src/app.module.ts b/src/app.module.ts index df1f8ae..9943590 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,7 +1,7 @@ -import { Module } from '@nestjs/common'; -import { imports } from './app.imports'; -import { providers } from './app.providers'; -import { controllers } from './controller'; +import { Module } from '@nestjs/common' +import { imports } from './app.imports' +import { providers } from './app.providers' +import { controllers } from './controller' @Module({ imports, diff --git a/src/app.providers.ts b/src/app.providers.ts index aba72e6..9df9955 100644 --- a/src/app.providers.ts +++ b/src/app.providers.ts @@ -1,7 +1,7 @@ -import { commands } from './command'; -import { guards } from './guard'; -import { resolvers } from './resolver'; -import { services } from './service'; +import { commands } from './command' +import { guards } from './guard' +import { resolvers } from './resolver' +import { services } from './service' export const providers = [ ...resolvers, diff --git a/src/cli.ts b/src/cli.ts index 9a96592..3bd068b 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,5 +1,5 @@ -import { BootstrapConsole } from 'nestjs-console'; -import { AppModule } from './app.module'; +import { BootstrapConsole } from 'nestjs-console' +import { AppModule } from './app.module' const bootstrap = new BootstrapConsole({ module: AppModule, diff --git a/src/command/index.ts b/src/command/index.ts index 650a4c2..e43b9a5 100644 --- a/src/command/index.ts +++ b/src/command/index.ts @@ -1,4 +1,4 @@ -import { UserCommand } from './user.command'; +import { UserCommand } from './user.command' export const commands = [ UserCommand, diff --git a/src/command/user.command.ts b/src/command/user.command.ts index 861e69b..5925334 100644 --- a/src/command/user.command.ts +++ b/src/command/user.command.ts @@ -1,7 +1,7 @@ -import inquirer from 'inquirer'; -import { Command, Console } from 'nestjs-console'; -import { matchType, validatePassword } from '../config/fields'; -import { UserCreateService } from '../service/user/user.create.service'; +import inquirer from 'inquirer' +import { Command, Console } from 'nestjs-console' +import { matchType, validatePassword } from '../config/fields' +import { UserCreateService } from '../service/user/user.create.service' @Console({ name: 'user', diff --git a/src/config/languages.ts b/src/config/languages.ts index 6a0a1fc..fcda6fc 100644 --- a/src/config/languages.ts +++ b/src/config/languages.ts @@ -1,15 +1,23 @@ export const languages = [ - 'cn', - 'de', 'en', - 'es', + 'ar', + 'cn', + 'da', + 'nl', 'fr', + 'de', + 'hi', 'it', 'ja', 'pl', - 'pt', + 'pt_BR', + 'pt_PT', 'ru', + 'es', + 'sv', + 'ta', + 'uk', ] export const defaultLanguage = 'en' diff --git a/src/controller/health.controller.ts b/src/controller/health.controller.ts index fa93c03..8fd6fee 100644 --- a/src/controller/health.controller.ts +++ b/src/controller/health.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Get } from '@nestjs/common'; +import { Controller, Get } from '@nestjs/common' @Controller() export class HealthController { diff --git a/src/controller/index.ts b/src/controller/index.ts index 2e4b32a..da8ddae 100644 --- a/src/controller/index.ts +++ b/src/controller/index.ts @@ -1,4 +1,4 @@ -import { HealthController } from './health.controller'; +import { HealthController } from './health.controller' export const controllers = [ HealthController, diff --git a/src/decorator/roles.decorator.ts b/src/decorator/roles.decorator.ts index 17d3221..5d38709 100644 --- a/src/decorator/roles.decorator.ts +++ b/src/decorator/roles.decorator.ts @@ -1,4 +1,4 @@ -import { SetMetadata } from '@nestjs/common'; -import { rolesType } from '../config/roles'; +import { SetMetadata } from '@nestjs/common' +import { rolesType } from '../config/roles' export const Roles = (...roles: rolesType) => SetMetadata('roles', roles); diff --git a/src/decorator/user.decorator.ts b/src/decorator/user.decorator.ts index 13884bd..f42c384 100644 --- a/src/decorator/user.decorator.ts +++ b/src/decorator/user.decorator.ts @@ -1,5 +1,5 @@ -import { createParamDecorator, ExecutionContext } from '@nestjs/common'; -import { GqlExecutionContext } from '@nestjs/graphql'; +import { createParamDecorator, ExecutionContext } from '@nestjs/common' +import { GqlExecutionContext } from '@nestjs/graphql' export const User = createParamDecorator( (data: unknown, ctx: ExecutionContext) => diff --git a/src/dto/auth/auth.jwt.model.ts b/src/dto/auth/auth.jwt.model.ts index eea9a36..825f563 100644 --- a/src/dto/auth/auth.jwt.model.ts +++ b/src/dto/auth/auth.jwt.model.ts @@ -1,4 +1,4 @@ -import { Field, ObjectType } from '@nestjs/graphql'; +import { Field, ObjectType } from '@nestjs/graphql' @ObjectType('AuthToken') export class AuthJwtModel { diff --git a/src/dto/deleted.model.ts b/src/dto/deleted.model.ts index 7ff97e7..bda5dfe 100644 --- a/src/dto/deleted.model.ts +++ b/src/dto/deleted.model.ts @@ -1,4 +1,4 @@ -import { Field, ObjectType } from '@nestjs/graphql'; +import { Field, ObjectType } from '@nestjs/graphql' @ObjectType('Deleted') export class DeletedModel { diff --git a/src/dto/form/abstract.notification.input.ts b/src/dto/form/abstract.notification.input.ts deleted file mode 100644 index 90a3d90..0000000 --- a/src/dto/form/abstract.notification.input.ts +++ /dev/null @@ -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 -} diff --git a/src/dto/form/abstract.notification.model.ts b/src/dto/form/abstract.notification.model.ts deleted file mode 100644 index edddbbe..0000000 --- a/src/dto/form/abstract.notification.model.ts +++ /dev/null @@ -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) { - this.subject = partial.subject - this.htmlTemplate = partial.htmlTemplate - this.enabled = partial.enabled - } -} diff --git a/src/dto/form/button.input.ts b/src/dto/form/button.input.ts index eda2e36..63c4d33 100644 --- a/src/dto/form/button.input.ts +++ b/src/dto/form/button.input.ts @@ -1,4 +1,4 @@ -import { Field, InputType } from '@nestjs/graphql'; +import { Field, InputType } from '@nestjs/graphql' @InputType() export class ButtonInput { diff --git a/src/dto/form/button.model.ts b/src/dto/form/button.model.ts index a24fdee..3561d9f 100644 --- a/src/dto/form/button.model.ts +++ b/src/dto/form/button.model.ts @@ -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') export class ButtonModel { @@ -20,7 +21,7 @@ export class ButtonModel { @Field({ nullable: true }) readonly color?: string - constructor(button: Partial) { + constructor(button: Partial) { this.url = button.url this.action = button.action this.text = button.text diff --git a/src/dto/form/colors.input.ts b/src/dto/form/colors.input.ts index 41f0478..9a7f1b9 100644 --- a/src/dto/form/colors.input.ts +++ b/src/dto/form/colors.input.ts @@ -1,22 +1,22 @@ -import { Field, InputType } from '@nestjs/graphql'; +import { Field, InputType } from '@nestjs/graphql' @InputType() export class ColorsInput { @Field() - readonly backgroundColor: string + readonly background: string @Field() - readonly questionColor: string + readonly question: string @Field() - readonly answerColor: string + readonly answer: string @Field() - readonly buttonColor: string + readonly button: string @Field() - readonly buttonActiveColor: string + readonly buttonActive: string @Field() - readonly buttonTextColor: string + readonly buttonText: string } diff --git a/src/dto/form/colors.model.ts b/src/dto/form/colors.model.ts index 3da3f12..78de467 100644 --- a/src/dto/form/colors.model.ts +++ b/src/dto/form/colors.model.ts @@ -1,32 +1,32 @@ -import { Field, ObjectType } from '@nestjs/graphql'; -import { Colors } from '../../schema/form.schema'; +import { Field, ObjectType } from '@nestjs/graphql' +import { ColorsEmbedded } from '../../entity/embedded/colors.embedded' @ObjectType('Colors') export class ColorsModel { @Field() - readonly backgroundColor: string + readonly background: string @Field() - readonly questionColor: string + readonly question: string @Field() - readonly answerColor: string + readonly answer: string @Field() - readonly buttonColor: string + readonly button: string @Field() - readonly buttonActiveColor: string + readonly buttonActive: string @Field() - readonly buttonTextColor: string + readonly buttonText: string - constructor(partial: Partial) { - this.backgroundColor = partial.backgroundColor - this.questionColor = partial.questionColor - this.answerColor = partial.answerColor - this.buttonColor = partial.buttonColor - this.buttonActiveColor = partial.buttonActiveColor - this.buttonTextColor = partial.buttonTextColor + constructor(partial: Partial) { + this.background = partial.background + this.question = partial.question + this.answer = partial.answer + this.button = partial.button + this.buttonActive = partial.buttonActive + this.buttonText = partial.buttonText } } diff --git a/src/dto/form/design.input.ts b/src/dto/form/design.input.ts index db9e5fc..67f1180 100644 --- a/src/dto/form/design.input.ts +++ b/src/dto/form/design.input.ts @@ -1,5 +1,5 @@ -import { Field, InputType } from '@nestjs/graphql'; -import { ColorsInput } from './colors.input'; +import { Field, InputType } from '@nestjs/graphql' +import { ColorsInput } from './colors.input' @InputType() export class DesignInput { diff --git a/src/dto/form/design.model.ts b/src/dto/form/design.model.ts index 4524b91..9a023bd 100644 --- a/src/dto/form/design.model.ts +++ b/src/dto/form/design.model.ts @@ -1,6 +1,6 @@ -import { Field, ObjectType } from '@nestjs/graphql'; -import { Design } from '../../schema/form.schema'; -import { ColorsModel } from './colors.model'; +import { Field, ObjectType } from '@nestjs/graphql' +import { DesignEmbedded } from '../../entity/embedded/design.embedded' +import { ColorsModel } from './colors.model' @ObjectType('Design') export class DesignModel { @@ -10,7 +10,7 @@ export class DesignModel { @Field({ nullable: true }) readonly font?: string - constructor(partial: Partial) { + constructor(partial: Partial) { this.colors = new ColorsModel(partial.colors) this.font = partial.font } diff --git a/src/dto/form/form.create.input.ts b/src/dto/form/form.create.input.ts index aa74591..51ca595 100644 --- a/src/dto/form/form.create.input.ts +++ b/src/dto/form/form.create.input.ts @@ -1,4 +1,4 @@ -import { Field, InputType } from '@nestjs/graphql'; +import { Field, InputType } from '@nestjs/graphql' @InputType('FormCreateInput') export class FormCreateInput { diff --git a/src/dto/form/form.field.input.ts b/src/dto/form/form.field.input.ts index 6c076ec..47b9ed6 100644 --- a/src/dto/form/form.field.input.ts +++ b/src/dto/form/form.field.input.ts @@ -1,8 +1,8 @@ -import { Field, ID, InputType } from '@nestjs/graphql'; -import { FormFieldOptionInput } from './form.field.option.input'; -import { FormFieldRatingInput } from './form.field.rating.input'; -import { LogicJumpInput } from './logic.jump.input'; -import { LogicJumpModel } from './logic.jump.model'; +import { Field, ID, InputType } from '@nestjs/graphql' +import { FormFieldLogicInput } from './form.field.logic.input' +import { FormFieldLogicModel } from './form.field.logic.model' +import { FormFieldOptionInput } from './form.field.option.input' +import { FormFieldRatingInput } from './form.field.rating.input' @InputType() export class FormFieldInput { @@ -28,10 +28,10 @@ export class FormFieldInput { readonly value: string @Field(() => [FormFieldOptionInput], { nullable: true }) - readonly options: [FormFieldOptionInput] + readonly options: FormFieldOptionInput[] - @Field(() => LogicJumpInput, { nullable: true }) - readonly logicJump: LogicJumpModel + @Field(() => [FormFieldLogicInput], { nullable: true }) + readonly logic: FormFieldLogicInput[] @Field(() => FormFieldRatingInput, { nullable: true }) readonly rating: FormFieldRatingInput diff --git a/src/dto/form/form.field.logic.input.ts b/src/dto/form/form.field.logic.input.ts new file mode 100644 index 0000000..0f0423c --- /dev/null +++ b/src/dto/form/form.field.logic.input.ts @@ -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 +} diff --git a/src/dto/form/form.field.logic.model.ts b/src/dto/form/form.field.logic.model.ts new file mode 100644 index 0000000..94d17e1 --- /dev/null +++ b/src/dto/form/form.field.logic.model.ts @@ -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 + } +} diff --git a/src/dto/form/form.field.model.ts b/src/dto/form/form.field.model.ts index 78346e2..5b1012b 100644 --- a/src/dto/form/form.field.model.ts +++ b/src/dto/form/form.field.model.ts @@ -1,8 +1,8 @@ -import { Field, ID, ObjectType } from '@nestjs/graphql'; -import { FormFieldDocument } from '../../schema/form.field.schema'; -import { FormFieldOptionModel } from './form.field.option.model'; -import { FormFieldRatingModel } from './form.field.rating.model'; -import { LogicJumpModel } from './logic.jump.model'; +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { FormFieldEntity } from '../../entity/form.field.entity' +import { FormFieldLogicModel } from './form.field.logic.model' +import { FormFieldOptionModel } from './form.field.option.model' +import { FormFieldRatingModel } from './form.field.rating.model' @ObjectType('FormField') export class FormFieldModel { @@ -28,16 +28,16 @@ export class FormFieldModel { readonly value: string @Field(() => [FormFieldOptionModel]) - readonly options: [FormFieldOptionModel] + readonly options: FormFieldOptionModel[] - @Field(() => LogicJumpModel) - readonly logicJump: LogicJumpModel + @Field(() => [FormFieldLogicModel]) + readonly logic: FormFieldLogicModel[] @Field(() => FormFieldRatingModel, { nullable: true }) readonly rating: FormFieldRatingModel - constructor(document: FormFieldDocument) { - this.id = document.id + constructor(document: FormFieldEntity) { + this.id = document.id.toString() this.title = document.title this.slug = document.slug this.type = document.type @@ -45,7 +45,7 @@ export class FormFieldModel { this.required = document.required this.value = document.value 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 } } diff --git a/src/dto/form/form.field.option.input.ts b/src/dto/form/form.field.option.input.ts index e2377c2..f13315a 100644 --- a/src/dto/form/form.field.option.input.ts +++ b/src/dto/form/form.field.option.input.ts @@ -1,4 +1,4 @@ -import { Field, InputType } from '@nestjs/graphql'; +import { Field, InputType } from '@nestjs/graphql' @InputType() export class FormFieldOptionInput { diff --git a/src/dto/form/form.field.option.model.ts b/src/dto/form/form.field.option.model.ts index a8021dd..8b1f447 100644 --- a/src/dto/form/form.field.option.model.ts +++ b/src/dto/form/form.field.option.model.ts @@ -1,5 +1,5 @@ -import { Field, ObjectType } from '@nestjs/graphql'; -import { FieldOptionDocument } from '../../schema/embedded/field.option'; +import { Field, ObjectType } from '@nestjs/graphql' +import { FormFieldOptionEntity } from '../../entity/form.field.option.entity' @ObjectType('FormFieldOption') export class FormFieldOptionModel { @@ -12,7 +12,7 @@ export class FormFieldOptionModel { @Field() readonly value: string - constructor(option: FieldOptionDocument) { + constructor(option: FormFieldOptionEntity) { this.key = option.key this.title = option.title this.value = option.value diff --git a/src/dto/form/form.field.rating.input.ts b/src/dto/form/form.field.rating.input.ts index ea350b1..9663e92 100644 --- a/src/dto/form/form.field.rating.input.ts +++ b/src/dto/form/form.field.rating.input.ts @@ -1,5 +1,5 @@ -import { Field, InputType } from '@nestjs/graphql'; -import { GraphQLInt } from 'graphql'; +import { Field, InputType } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' @InputType() export class FormFieldRatingInput { diff --git a/src/dto/form/form.field.rating.model.ts b/src/dto/form/form.field.rating.model.ts index 74b4d74..0ea2e65 100644 --- a/src/dto/form/form.field.rating.model.ts +++ b/src/dto/form/form.field.rating.model.ts @@ -1,6 +1,6 @@ -import { Field, ObjectType } from '@nestjs/graphql'; -import { GraphQLInt } from 'graphql'; -import { RatingFieldDocument } from '../../schema/embedded/rating.field'; +import { Field, ObjectType } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { RatingEmbedded } from '../../entity/embedded/rating.embedded' @ObjectType('FormFieldRating') export class FormFieldRatingModel { @@ -10,7 +10,7 @@ export class FormFieldRatingModel { @Field({ nullable: true }) readonly shape: string - constructor(option: RatingFieldDocument) { + constructor(option: RatingEmbedded) { this.steps = option.steps this.shape = option.shape } diff --git a/src/dto/form/form.hook.input.ts b/src/dto/form/form.hook.input.ts index 67efe4d..68c8b74 100644 --- a/src/dto/form/form.hook.input.ts +++ b/src/dto/form/form.hook.input.ts @@ -1,5 +1,4 @@ import { Field, ID, InputType } from '@nestjs/graphql' -import { GraphQLInt } from 'graphql'; @InputType() export class FormHookInput { diff --git a/src/dto/form/form.hook.model.ts b/src/dto/form/form.hook.model.ts index 8cc007e..2335688 100644 --- a/src/dto/form/form.hook.model.ts +++ b/src/dto/form/form.hook.model.ts @@ -1,5 +1,5 @@ -import { Field, ID, ObjectType } from '@nestjs/graphql'; -import { FormHookDocument } from '../../schema/form.hook.schema' +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { FormHookEntity } from '../../entity/form.hook.entity' @ObjectType('FormHook') export class FormHookModel { @@ -15,8 +15,8 @@ export class FormHookModel { @Field({ nullable: true }) readonly format?: string - constructor(hook: FormHookDocument) { - this.id = hook.id + constructor(hook: FormHookEntity) { + this.id = hook.id.toString() this.enabled = hook.enabled this.url = hook.url this.format = hook.format diff --git a/src/dto/form/form.model.ts b/src/dto/form/form.model.ts index ee8acfa..e10ab13 100644 --- a/src/dto/form/form.model.ts +++ b/src/dto/form/form.model.ts @@ -1,5 +1,5 @@ -import { Field, ID, ObjectType } from '@nestjs/graphql'; -import { FormDocument } from '../../schema/form.schema'; +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { FormEntity } from '../../entity/form.entity' @ObjectType('Form') export class FormModel { @@ -21,8 +21,8 @@ export class FormModel { @Field() readonly showFooter: boolean - constructor(form: FormDocument) { - this.id = form.id + constructor(form: FormEntity) { + this.id = form.id.toString() this.title = form.title this.created = form.created this.lastModified = form.lastModified diff --git a/src/dto/form/form.notification.input.ts b/src/dto/form/form.notification.input.ts new file mode 100644 index 0000000..afabd33 --- /dev/null +++ b/src/dto/form/form.notification.input.ts @@ -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 +} diff --git a/src/dto/form/form.notification.model.ts b/src/dto/form/form.notification.model.ts new file mode 100644 index 0000000..62943b9 --- /dev/null +++ b/src/dto/form/form.notification.model.ts @@ -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) { + 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 + } +} diff --git a/src/dto/form/pager.form.model.ts b/src/dto/form/form.pager.model.ts similarity index 66% rename from src/dto/form/pager.form.model.ts rename to src/dto/form/form.pager.model.ts index 7df5818..6c6e919 100644 --- a/src/dto/form/pager.form.model.ts +++ b/src/dto/form/form.pager.model.ts @@ -1,9 +1,9 @@ -import { Field, ObjectType } from '@nestjs/graphql'; -import { GraphQLInt } from 'graphql'; -import { FormModel } from './form.model'; +import { Field, ObjectType } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { FormModel } from './form.model' -@ObjectType('PagerForm') -export class PagerFormModel { +@ObjectType('FormPager') +export class FormPagerModel { @Field(() => [FormModel]) entries: FormModel[] diff --git a/src/dto/form/form.statistic.model.ts b/src/dto/form/form.statistic.model.ts index 6bb5967..552446b 100644 --- a/src/dto/form/form.statistic.model.ts +++ b/src/dto/form/form.statistic.model.ts @@ -1,4 +1,4 @@ -import { ObjectType } from '@nestjs/graphql'; +import { ObjectType } from '@nestjs/graphql' @ObjectType('FormStatistic') export class FormStatisticModel { diff --git a/src/dto/form/form.update.input.ts b/src/dto/form/form.update.input.ts index 69d3dfb..68e4060 100644 --- a/src/dto/form/form.update.input.ts +++ b/src/dto/form/form.update.input.ts @@ -1,10 +1,9 @@ -import { Field, ID, InputType } from '@nestjs/graphql'; -import { DesignInput } from './design.input'; -import { FormFieldInput } from './form.field.input'; +import { Field, ID, InputType } from '@nestjs/graphql' +import { DesignInput } from './design.input' +import { FormFieldInput } from './form.field.input' import { FormHookInput } from './form.hook.input' -import { PageInput } from './page.input'; -import { RespondentNotificationsInput } from './respondent.notifications.input'; -import { SelfNotificationsInput } from './self.notifications.input'; +import { FormNotificationInput } from './form.notification.input' +import { PageInput } from './page.input' @InputType() export class FormUpdateInput { @@ -38,9 +37,6 @@ export class FormUpdateInput { @Field({ nullable: true }) readonly endPage: PageInput - @Field({ nullable: true }) - readonly selfNotifications: SelfNotificationsInput - - @Field({ nullable: true }) - readonly respondentNotifications: RespondentNotificationsInput + @Field(() => [FormNotificationInput], { nullable: true }) + readonly notifications: FormNotificationInput[] } diff --git a/src/dto/form/logic.jump.input.ts b/src/dto/form/logic.jump.input.ts deleted file mode 100644 index fa2618e..0000000 --- a/src/dto/form/logic.jump.input.ts +++ /dev/null @@ -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 -} diff --git a/src/dto/form/logic.jump.model.ts b/src/dto/form/logic.jump.model.ts deleted file mode 100644 index 48ac7f6..0000000 --- a/src/dto/form/logic.jump.model.ts +++ /dev/null @@ -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 - } -} diff --git a/src/dto/form/page.input.ts b/src/dto/form/page.input.ts index 7cb8c0d..8768ea1 100644 --- a/src/dto/form/page.input.ts +++ b/src/dto/form/page.input.ts @@ -1,5 +1,5 @@ -import { Field, InputType } from '@nestjs/graphql'; -import { ButtonInput } from './button.input'; +import { Field, InputType } from '@nestjs/graphql' +import { ButtonInput } from './button.input' @InputType() export class PageInput { diff --git a/src/dto/form/page.model.ts b/src/dto/form/page.model.ts index 3e18a43..baa4735 100644 --- a/src/dto/form/page.model.ts +++ b/src/dto/form/page.model.ts @@ -1,6 +1,6 @@ -import { Field, ObjectType } from '@nestjs/graphql'; -import { FormPage } from '../../schema/form.schema'; -import { ButtonModel } from './button.model'; +import { Field, ObjectType } from '@nestjs/graphql' +import { PageEntity } from '../../entity/page.entity' +import { ButtonModel } from './button.model' @ObjectType('Page') export class PageModel { @@ -19,7 +19,7 @@ export class PageModel { @Field(() => [ButtonModel]) readonly buttons: ButtonModel[] - constructor(page: Partial) { + constructor(page: Partial) { this.show = page.show this.title = page.title this.paragraph = page.paragraph diff --git a/src/dto/form/respondent.notifications.input.ts b/src/dto/form/respondent.notifications.input.ts deleted file mode 100644 index eefe1a9..0000000 --- a/src/dto/form/respondent.notifications.input.ts +++ /dev/null @@ -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 -} diff --git a/src/dto/form/respondent.notifications.model.ts b/src/dto/form/respondent.notifications.model.ts deleted file mode 100644 index 28a6d1b..0000000 --- a/src/dto/form/respondent.notifications.model.ts +++ /dev/null @@ -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) { - super(partial); - - this.toField = partial.toField - this.fromEmail = partial.fromEmail - } -} diff --git a/src/dto/form/self.notifications.input.ts b/src/dto/form/self.notifications.input.ts deleted file mode 100644 index 0075c0c..0000000 --- a/src/dto/form/self.notifications.input.ts +++ /dev/null @@ -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 -} diff --git a/src/dto/form/self.notifications.model.ts b/src/dto/form/self.notifications.model.ts deleted file mode 100644 index 84f1a61..0000000 --- a/src/dto/form/self.notifications.model.ts +++ /dev/null @@ -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) { - super(partial); - - this.fromField = partial.fromField - this.toEmail = partial.toEmail - } -} diff --git a/src/dto/profile/profile.model.ts b/src/dto/profile/profile.model.ts index 4f0d4fb..d8d69f0 100644 --- a/src/dto/profile/profile.model.ts +++ b/src/dto/profile/profile.model.ts @@ -1,13 +1,13 @@ -import { Field, ObjectType } from '@nestjs/graphql'; -import { UserDocument } from '../../schema/user.schema'; -import { UserModel } from '../user/user.model'; +import { Field, ObjectType } from '@nestjs/graphql' +import { UserEntity } from '../../entity/user.entity' +import { UserModel } from '../user/user.model' @ObjectType('Profile') export class ProfileModel extends UserModel { @Field(() => [String]) readonly roles: string[] - constructor(user: UserDocument) { + constructor(user: UserEntity) { super(user) this.roles = user.roles diff --git a/src/dto/profile/profile.update.input.ts b/src/dto/profile/profile.update.input.ts index fa72507..d09e98c 100644 --- a/src/dto/profile/profile.update.input.ts +++ b/src/dto/profile/profile.update.input.ts @@ -1,4 +1,4 @@ -import { Field, ID, InputType } from '@nestjs/graphql'; +import { Field, ID, InputType } from '@nestjs/graphql' @InputType() export class ProfileUpdateInput { diff --git a/src/dto/setting/setting.model.ts b/src/dto/setting/setting.model.ts index 37dcb30..b8ec678 100644 --- a/src/dto/setting/setting.model.ts +++ b/src/dto/setting/setting.model.ts @@ -1,4 +1,4 @@ -import { Field, ID, ObjectType } from '@nestjs/graphql'; +import { Field, ID, ObjectType } from '@nestjs/graphql' @ObjectType('Setting') export class SettingModel { diff --git a/src/dto/setting/pager.setting.model.ts b/src/dto/setting/setting.pager.model.ts similarity index 65% rename from src/dto/setting/pager.setting.model.ts rename to src/dto/setting/setting.pager.model.ts index cafc3f4..7c685de 100644 --- a/src/dto/setting/pager.setting.model.ts +++ b/src/dto/setting/setting.pager.model.ts @@ -1,9 +1,9 @@ -import { Field, ObjectType } from '@nestjs/graphql'; -import { GraphQLInt } from 'graphql'; -import {SettingModel} from './setting.model' +import { Field, ObjectType } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { SettingModel } from './setting.model' -@ObjectType('PagerSetting') -export class PagerSettingModel { +@ObjectType('SettingPager') +export class SettingPagerModel { @Field(() => [SettingModel]) entries: SettingModel[] diff --git a/src/dto/status.model.ts b/src/dto/status.model.ts index 703ae17..9aaf617 100644 --- a/src/dto/status.model.ts +++ b/src/dto/status.model.ts @@ -1,4 +1,4 @@ -import { Field, ObjectType } from '@nestjs/graphql'; +import { Field, ObjectType } from '@nestjs/graphql' @ObjectType('Version') export class StatusModel { diff --git a/src/dto/submission/device.input.ts b/src/dto/submission/device.input.ts index b39de58..40caafb 100644 --- a/src/dto/submission/device.input.ts +++ b/src/dto/submission/device.input.ts @@ -1,4 +1,4 @@ -import { Field, InputType } from '@nestjs/graphql'; +import { Field, InputType } from '@nestjs/graphql' @InputType() export class DeviceInput { @@ -7,4 +7,7 @@ export class DeviceInput { @Field() readonly name: string + + @Field({ nullable: true }) + readonly language: string } diff --git a/src/dto/submission/device.model.ts b/src/dto/submission/device.model.ts index c31cdf7..6080aa6 100644 --- a/src/dto/submission/device.model.ts +++ b/src/dto/submission/device.model.ts @@ -1,5 +1,5 @@ -import { Field, ObjectType } from '@nestjs/graphql'; -import { Device } from '../../schema/submission.schema'; +import { Field, ObjectType } from '@nestjs/graphql' +import { DeviceEmbedded } from '../../entity/embedded/device.embedded' @ObjectType('Device') export class DeviceModel { @@ -9,8 +9,12 @@ export class DeviceModel { @Field() readonly name: string - constructor(device: Device) { + @Field({ nullable: true }) + readonly language: string + + constructor(device: DeviceEmbedded) { this.type = device.type this.name = device.name + this.language = device.language } } diff --git a/src/dto/submission/geo.location.model.ts b/src/dto/submission/geo.location.model.ts index c45d156..ba0c7bf 100644 --- a/src/dto/submission/geo.location.model.ts +++ b/src/dto/submission/geo.location.model.ts @@ -1,5 +1,5 @@ -import { Field, ObjectType } from '@nestjs/graphql'; -import { GeoLocation } from '../../schema/submission.schema'; +import { Field, ObjectType } from '@nestjs/graphql' +import { GeoLocationEmbedded } from '../../entity/embedded/geo.location.embedded' @ObjectType('GeoLocation') export class GeoLocationModel { @@ -9,7 +9,7 @@ export class GeoLocationModel { @Field({ nullable: true }) city?: string - constructor(geo: GeoLocation) { + constructor(geo: GeoLocationEmbedded) { this.country = geo.country this.city = geo.city } diff --git a/src/dto/submission/submission.field.model.ts b/src/dto/submission/submission.field.model.ts index 9f934b7..7659797 100644 --- a/src/dto/submission/submission.field.model.ts +++ b/src/dto/submission/submission.field.model.ts @@ -1,5 +1,5 @@ -import { Field, ID, ObjectType } from '@nestjs/graphql'; -import { SubmissionFieldDocument } from '../../schema/submission.field.schema'; +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { SubmissionFieldEntity } from '../../entity/submission.field.entity' @ObjectType('SubmissionField') export class SubmissionFieldModel { @@ -12,8 +12,8 @@ export class SubmissionFieldModel { @Field() readonly type: string - constructor(field: SubmissionFieldDocument) { - this.id = field.id + constructor(field: SubmissionFieldEntity) { + this.id = field.id.toString() this.value = JSON.stringify(field.fieldValue) this.type = field.fieldType } diff --git a/src/dto/submission/submission.model.ts b/src/dto/submission/submission.model.ts index 2aabb66..21b045e 100644 --- a/src/dto/submission/submission.model.ts +++ b/src/dto/submission/submission.model.ts @@ -1,12 +1,12 @@ -import { Field, ID, ObjectType } from '@nestjs/graphql'; -import { SubmissionDocument } from '../../schema/submission.schema'; -import { DeviceModel } from './device.model'; -import { GeoLocationModel } from './geo.location.model'; +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { SubmissionEntity } from '../../entity/submission.entity' +import { DeviceModel } from './device.model' +import { GeoLocationModel } from './geo.location.model' @ObjectType('Submission') export class SubmissionModel { @Field(() => ID) - readonly id: string + readonly id: number @Field() readonly ipAddr: string @@ -29,7 +29,7 @@ export class SubmissionModel { @Field({ nullable: true }) readonly lastModified?: Date - constructor(submission: SubmissionDocument) { + constructor(submission: SubmissionEntity) { this.id = submission.id this.ipAddr = submission.ipAddr diff --git a/src/dto/submission/pager.submission.model.ts b/src/dto/submission/submission.pager.model.ts similarity index 64% rename from src/dto/submission/pager.submission.model.ts rename to src/dto/submission/submission.pager.model.ts index 1bd964a..27243b2 100644 --- a/src/dto/submission/pager.submission.model.ts +++ b/src/dto/submission/submission.pager.model.ts @@ -1,9 +1,9 @@ -import { Field, ObjectType } from '@nestjs/graphql'; -import { GraphQLInt } from 'graphql'; -import { SubmissionModel } from './submission.model'; +import { Field, ObjectType } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { SubmissionModel } from './submission.model' -@ObjectType('PagerSubmission') -export class PagerSubmissionModel { +@ObjectType('SubmissionPager') +export class SubmissionPagerModel { @Field(() => [SubmissionModel]) entries: SubmissionModel[] diff --git a/src/dto/submission/submission.progress.model.ts b/src/dto/submission/submission.progress.model.ts index 2008a73..8695340 100644 --- a/src/dto/submission/submission.progress.model.ts +++ b/src/dto/submission/submission.progress.model.ts @@ -1,5 +1,5 @@ -import { Field, ID, ObjectType } from '@nestjs/graphql'; -import { SubmissionDocument } from '../../schema/submission.schema'; +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { SubmissionEntity } from '../../entity/submission.entity' @ObjectType('SubmissionProgress') export class SubmissionProgressModel { @@ -18,8 +18,8 @@ export class SubmissionProgressModel { @Field({ nullable: true }) readonly lastModified?: Date - constructor(submission: Partial) { - this.id = submission.id + constructor(submission: Partial) { + this.id = submission.id.toString() this.timeElapsed = submission.timeElapsed this.percentageComplete = submission.percentageComplete diff --git a/src/dto/submission/submission.set.field.input.ts b/src/dto/submission/submission.set.field.input.ts index b14c071..8c1bacb 100644 --- a/src/dto/submission/submission.set.field.input.ts +++ b/src/dto/submission/submission.set.field.input.ts @@ -1,4 +1,4 @@ -import { Field, ID, InputType } from '@nestjs/graphql'; +import { Field, ID, InputType } from '@nestjs/graphql' @InputType() export class SubmissionSetFieldInput { diff --git a/src/dto/submission/submission.start.input.ts b/src/dto/submission/submission.start.input.ts index 67a1621..966d11f 100644 --- a/src/dto/submission/submission.start.input.ts +++ b/src/dto/submission/submission.start.input.ts @@ -1,5 +1,5 @@ -import { Field, InputType } from '@nestjs/graphql'; -import { DeviceInput } from './device.input'; +import { Field, InputType } from '@nestjs/graphql' +import { DeviceInput } from './device.input' @InputType() export class SubmissionStartInput { diff --git a/src/dto/submission/submission.statistic.model.ts b/src/dto/submission/submission.statistic.model.ts index 8ec9208..9c3623b 100644 --- a/src/dto/submission/submission.statistic.model.ts +++ b/src/dto/submission/submission.statistic.model.ts @@ -1,4 +1,4 @@ -import { ObjectType } from '@nestjs/graphql'; +import { ObjectType } from '@nestjs/graphql' @ObjectType('SubmissionStatistic') export class SubmissionStatisticModel { diff --git a/src/dto/user/user.create.input.ts b/src/dto/user/user.create.input.ts index 18f1a42..4ed99a8 100644 --- a/src/dto/user/user.create.input.ts +++ b/src/dto/user/user.create.input.ts @@ -1,5 +1,5 @@ -import { Field, InputType } from '@nestjs/graphql'; -import { IsEmail, IsNotEmpty, MaxLength, MinLength } from 'class-validator'; +import { Field, InputType } from '@nestjs/graphql' +import { IsEmail, IsNotEmpty, MaxLength, MinLength } from 'class-validator' @InputType() export class UserCreateInput { diff --git a/src/dto/user/user.model.ts b/src/dto/user/user.model.ts index 987f9ab..cb2b048 100644 --- a/src/dto/user/user.model.ts +++ b/src/dto/user/user.model.ts @@ -1,5 +1,5 @@ -import { Field, ID, ObjectType } from '@nestjs/graphql'; -import { UserDocument } from '../../schema/user.schema'; +import { Field, ID, ObjectType } from '@nestjs/graphql' +import { UserEntity } from '../../entity/user.entity' @ObjectType('User') export class UserModel { @@ -30,8 +30,8 @@ export class UserModel { @Field({ nullable: true }) readonly lastModified: Date - constructor(user: UserDocument) { - this.id = user.id + constructor(user: UserEntity) { + this.id = user.id.toString() this.username = user.username this.email = user.email diff --git a/src/dto/user/pager.user.model.ts b/src/dto/user/user.pager.model.ts similarity index 66% rename from src/dto/user/pager.user.model.ts rename to src/dto/user/user.pager.model.ts index 3654546..2c58dc9 100644 --- a/src/dto/user/pager.user.model.ts +++ b/src/dto/user/user.pager.model.ts @@ -1,9 +1,9 @@ -import { Field, ObjectType } from '@nestjs/graphql'; -import { GraphQLInt } from 'graphql'; -import { UserModel } from './user.model'; +import { Field, ObjectType } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { UserModel } from './user.model' -@ObjectType('PagerUser') -export class PagerUserModel { +@ObjectType('UserPager') +export class UserPagerModel { @Field(() => [UserModel]) entries: UserModel[] diff --git a/src/dto/user/user.statistic.model.ts b/src/dto/user/user.statistic.model.ts index cdfa572..203c99e 100644 --- a/src/dto/user/user.statistic.model.ts +++ b/src/dto/user/user.statistic.model.ts @@ -1,4 +1,4 @@ -import { ObjectType } from '@nestjs/graphql'; +import { ObjectType } from '@nestjs/graphql' @ObjectType('UserStatistic') export class UserStatisticModel { diff --git a/src/dto/user/user.update.input.ts b/src/dto/user/user.update.input.ts index 94d6c5d..d357807 100644 --- a/src/dto/user/user.update.input.ts +++ b/src/dto/user/user.update.input.ts @@ -1,5 +1,4 @@ -import { Field, ID, InputType } from '@nestjs/graphql'; -import { GraphQLString } from 'graphql'; +import { Field, ID, InputType } from '@nestjs/graphql' @InputType() export class UserUpdateInput { @@ -21,7 +20,7 @@ export class UserUpdateInput { @Field({ nullable: true }) readonly password: string - @Field(() => [GraphQLString], { nullable: true }) + @Field(() => [String], { nullable: true }) readonly roles: string[] @Field({ nullable: true }) diff --git a/src/entity/embedded/analytics.embedded.ts b/src/entity/embedded/analytics.embedded.ts index d20d4b3..11e71fe 100644 --- a/src/entity/embedded/analytics.embedded.ts +++ b/src/entity/embedded/analytics.embedded.ts @@ -1,3 +1,6 @@ +import { Column } from 'typeorm' + export class AnalyticsEmbedded { + @Column({ nullable: true }) readonly gaCode?: string } diff --git a/src/entity/embedded/colors.embedded.ts b/src/entity/embedded/colors.embedded.ts index 1a6e410..9bb52d9 100644 --- a/src/entity/embedded/colors.embedded.ts +++ b/src/entity/embedded/colors.embedded.ts @@ -1,8 +1,21 @@ +import { Column } from 'typeorm' + export class ColorsEmbedded { - readonly background: string - readonly question: string - readonly answer: string - readonly button: string - readonly buttonActive: string - readonly buttonText: string + @Column({ nullable: true }) + public background?: string + + @Column({ nullable: true }) + public question?: 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 } diff --git a/src/entity/embedded/design.embedded.ts b/src/entity/embedded/design.embedded.ts index 4fe2999..042649f 100644 --- a/src/entity/embedded/design.embedded.ts +++ b/src/entity/embedded/design.embedded.ts @@ -1,7 +1,10 @@ -import { ColorsEmbedded } from './form.design.colors.embedded' +import { Column } from 'typeorm' +import { ColorsEmbedded } from './colors.embedded' export class DesignEmbedded { - colors: ColorsEmbedded + @Column(() => ColorsEmbedded) + colors: ColorsEmbedded = new ColorsEmbedded() + @Column({ nullable: true }) font?: string } diff --git a/src/entity/embedded/device.embedded.ts b/src/entity/embedded/device.embedded.ts index 05161b2..989dc2d 100644 --- a/src/entity/embedded/device.embedded.ts +++ b/src/entity/embedded/device.embedded.ts @@ -1,4 +1,12 @@ +import { Column } from 'typeorm' + export class DeviceEmbedded { - readonly type?: string - readonly name?: string + @Column({ nullable: true }) + public language?: string + + @Column({ nullable: true }) + public type?: string + + @Column({ nullable: true }) + public name?: string } diff --git a/src/entity/embedded/geo.location.embedded.ts b/src/entity/embedded/geo.location.embedded.ts index cf25187..9142133 100644 --- a/src/entity/embedded/geo.location.embedded.ts +++ b/src/entity/embedded/geo.location.embedded.ts @@ -1,4 +1,9 @@ +import { Column } from 'typeorm' + export class GeoLocationEmbedded { + @Column({ nullable: true }) readonly country?: string + + @Column({ nullable: true }) readonly city?: string } diff --git a/src/entity/embedded/logic.embedded.ts b/src/entity/embedded/logic.embedded.ts deleted file mode 100644 index f1751cc..0000000 --- a/src/entity/embedded/logic.embedded.ts +++ /dev/null @@ -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 -} diff --git a/src/entity/embedded/rating.embedded.ts b/src/entity/embedded/rating.embedded.ts index b416d92..eb520c4 100644 --- a/src/entity/embedded/rating.embedded.ts +++ b/src/entity/embedded/rating.embedded.ts @@ -1,4 +1,9 @@ +import { Column } from 'typeorm' + export class RatingEmbedded { + @Column({ nullable: true }) readonly steps?: number + + @Column({ nullable: true }) readonly shape?: string } diff --git a/src/entity/form.entity.ts b/src/entity/form.entity.ts index b2ea37d..67b2ebd 100644 --- a/src/entity/form.entity.ts +++ b/src/entity/form.entity.ts @@ -4,17 +4,18 @@ import { Entity, ManyToOne, OneToMany, - PrimaryGeneratedColumn, UpdateDateColumn + PrimaryGeneratedColumn, + UpdateDateColumn } from 'typeorm' import { AnalyticsEmbedded } from './embedded/analytics.embedded' import { DesignEmbedded } from './embedded/design.embedded' import { FormFieldEntity } from './form.field.entity' import { FormHookEntity } from './form.hook.entity' import { FormNotificationEntity } from './form.notification.entity' -import { SubmissionEntity } from './submission.entity' -import { VisitorEntity } from './visitor.entity' import { PageEntity } from './page.entity' +import { SubmissionEntity } from './submission.entity' import { UserEntity } from './user.entity' +import { VisitorEntity } from './visitor.entity' @Entity({ name: 'form' }) export class FormEntity { @@ -28,7 +29,7 @@ export class FormEntity { public language: string @Column(() => AnalyticsEmbedded) - public analytics: AnalyticsEmbedded + public analytics: AnalyticsEmbedded = new AnalyticsEmbedded() @OneToMany(() => VisitorEntity, visitor => visitor.form) public visitors: VisitorEntity[] @@ -36,22 +37,22 @@ export class FormEntity { @OneToMany(() => SubmissionEntity, submission => submission.form) public submissions: SubmissionEntity[] - @OneToMany(() => FormFieldEntity, field => field.form) + @OneToMany(() => FormFieldEntity, field => field.form, { eager: true, orphanedRowAction: 'delete' }) public fields: FormFieldEntity[] - @OneToMany(() => FormHookEntity, field => field.form) + @OneToMany(() => FormHookEntity, field => field.form, { eager: true, orphanedRowAction: 'delete' }) public hooks: FormHookEntity[] - @ManyToOne(() => UserEntity) + @ManyToOne(() => UserEntity, { eager: true }) public admin: UserEntity - @ManyToOne(() => PageEntity) + @ManyToOne(() => PageEntity, { eager: true }) public startPage: PageEntity; - @ManyToOne(() => PageEntity) + @ManyToOne(() => PageEntity, { eager: true }) public endPage: PageEntity; - @OneToMany(() => FormNotificationEntity, notification => notification.form) + @OneToMany(() => FormNotificationEntity, notification => notification.form, { eager: true, orphanedRowAction: 'delete' }) public notifications: FormNotificationEntity[] @Column() @@ -61,7 +62,7 @@ export class FormEntity { public isLive: boolean; @Column(() => DesignEmbedded) - public design: DesignEmbedded; + public design: DesignEmbedded = new DesignEmbedded(); @CreateDateColumn() public created: Date diff --git a/src/entity/form.field.entity.ts b/src/entity/form.field.entity.ts index 7b9ffeb..a014073 100644 --- a/src/entity/form.field.entity.ts +++ b/src/entity/form.field.entity.ts @@ -1,5 +1,4 @@ import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from 'typeorm' -import { LogicEmbedded } from './embedded/logic.embedded' import { RatingEmbedded } from './embedded/rating.embedded' import { FormEntity } from './form.entity' import { FormFieldLogicEntity } from './form.field.logic.entity' @@ -22,13 +21,13 @@ export class FormFieldEntity { @Column({ nullable: true }) public slug?: string - @OneToMany(() => FormFieldLogicEntity, logic => logic.field) + @OneToMany(() => FormFieldLogicEntity, logic => logic.field, { eager: true }) public logic: FormFieldLogicEntity[] @Column(() => RatingEmbedded) public rating: RatingEmbedded = new RatingEmbedded() - @OneToMany(() => FormFieldOptionEntity, option => option.field) + @OneToMany(() => FormFieldOptionEntity, option => option.field, { eager: true }) public options?: FormFieldOptionEntity[] @Column() diff --git a/src/entity/form.field.logic.entity.ts b/src/entity/form.field.logic.entity.ts index 8ace91a..1737a11 100644 --- a/src/entity/form.field.logic.entity.ts +++ b/src/entity/form.field.logic.entity.ts @@ -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' type LogicAction = 'visible' | 'require' | 'disable' | 'jumpTo' diff --git a/src/entity/form.hook.entity.ts b/src/entity/form.hook.entity.ts index 28a4662..877b937 100644 --- a/src/entity/form.hook.entity.ts +++ b/src/entity/form.hook.entity.ts @@ -10,11 +10,11 @@ export class FormHookEntity { public form: FormEntity @Column() - readonly enabled: boolean + public enabled: boolean @Column() - readonly url: string + public url: string @Column({ nullable: true }) - readonly format?: string + public format?: string } diff --git a/src/entity/index.ts b/src/entity/index.ts index 65b4eab..53f3538 100644 --- a/src/entity/index.ts +++ b/src/entity/index.ts @@ -1,10 +1,10 @@ -import { ButtonEntity } from './button.entity' import { FormEntity } from './form.entity' import { FormFieldEntity } from './form.field.entity' import { FormFieldLogicEntity } from './form.field.logic.entity' import { FormFieldOptionEntity } from './form.field.option.entity' import { FormHookEntity } from './form.hook.entity' import { FormNotificationEntity } from './form.notification.entity' +import { PageButtonEntity } from './page.button.entity' import { PageEntity } from './page.entity' import { SubmissionEntity } from './submission.entity' import { SubmissionFieldEntity } from './submission.field.entity' @@ -12,13 +12,13 @@ import { UserEntity } from './user.entity' import { VisitorEntity } from './visitor.entity' export const entities = [ - ButtonEntity, FormEntity, FormFieldEntity, FormFieldLogicEntity, FormFieldOptionEntity, FormHookEntity, FormNotificationEntity, + PageButtonEntity, PageEntity, SubmissionEntity, SubmissionFieldEntity, diff --git a/src/entity/button.entity.ts b/src/entity/page.button.entity.ts similarity index 59% rename from src/entity/button.entity.ts rename to src/entity/page.button.entity.ts index edf30b0..db7c1c7 100644 --- a/src/entity/button.entity.ts +++ b/src/entity/page.button.entity.ts @@ -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' }) -export class ButtonEntity { +@Entity({ name: 'page_button' }) +export class PageButtonEntity { @PrimaryGeneratedColumn() public id: number + @ManyToOne(() => PageEntity, page => page.buttons) + public page: PageEntity + @Column({ nullable: true }) readonly url?: string diff --git a/src/entity/page.entity.ts b/src/entity/page.entity.ts index 18babf5..2aa1a98 100644 --- a/src/entity/page.entity.ts +++ b/src/entity/page.entity.ts @@ -1,5 +1,5 @@ -import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm' -import { ButtonEntity } from './button.entity' +import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm' +import { PageButtonEntity } from './page.button.entity' @Entity({ name: 'page' }) export class PageEntity { @@ -18,5 +18,6 @@ export class PageEntity { @Column({ nullable: true }) readonly buttonText?: string - readonly buttons: ButtonEntity[] + @OneToMany(() => PageButtonEntity, button => button.page) + readonly buttons: PageButtonEntity[] } diff --git a/src/entity/submission.entity.ts b/src/entity/submission.entity.ts index 4974656..0a6ba86 100644 --- a/src/entity/submission.entity.ts +++ b/src/entity/submission.entity.ts @@ -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 { GeoLocationEmbedded } from './embedded/geo.location.embedded' import { FormEntity } from './form.entity' import { SubmissionFieldEntity } from './submission.field.entity' import { UserEntity } from './user.entity' +import { VisitorEntity } from './visitor.entity' @Entity({ name: 'submission' }) export class SubmissionEntity { @PrimaryGeneratedColumn() public id: number - readonly fields: SubmissionFieldEntity[] - readonly form: FormEntity - readonly ipAddr: string - readonly tokenHash: string - readonly geoLocation: GeoLocationEmbedded - readonly device: DeviceEmbedded - readonly timeElapsed: number - readonly percentageComplete: number + @OneToMany(() => SubmissionFieldEntity, field => field.submission, { eager: true }) + public fields: SubmissionFieldEntity[] - readonly user?: UserEntity - readonly created: Date - readonly lastModified: Date + @ManyToOne(() => FormEntity, form => form.submissions, { eager: true }) + public form: FormEntity + + @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 } diff --git a/src/entity/submission.field.entity.ts b/src/entity/submission.field.entity.ts index 440403f..e05303b 100644 --- a/src/entity/submission.field.entity.ts +++ b/src/entity/submission.field.entity.ts @@ -1,13 +1,21 @@ -import { Entity, PrimaryGeneratedColumn } from 'typeorm' -import { FormFieldDocument } from '../schema/form.field.schema' +import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm' import { FormFieldEntity } from './form.field.entity' +import { SubmissionEntity } from './submission.entity' @Entity({ name: 'submission_field' }) export class SubmissionFieldEntity { @PrimaryGeneratedColumn() public id: number - readonly field: FormFieldEntity - readonly fieldType: string - readonly fieldValue: any + @ManyToOne(() => SubmissionEntity, submission => submission.fields) + public submission: SubmissionEntity + + @ManyToOne(() => FormFieldEntity, { eager: true }) + public field: FormFieldEntity + + @Column() + public fieldType: string + + @Column() + public fieldValue: string } diff --git a/src/entity/user.entity.ts b/src/entity/user.entity.ts index 7de0c90..202fe1f 100644 --- a/src/entity/user.entity.ts +++ b/src/entity/user.entity.ts @@ -1,4 +1,4 @@ -import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm' +import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm' import { rolesType } from '../config/roles' @Entity({ name: 'user' }) @@ -6,7 +6,10 @@ export class UserEntity { @PrimaryGeneratedColumn() public id: number + @Column({ nullable: true }) public firstName?: string + + @Column({ nullable: true }) public lastName?: string @Column({ length: 255, unique: true }) @@ -15,15 +18,36 @@ export class UserEntity { @Column({ length: 255, unique: true }) public username: string + @Column() public passwordHash: string + + @Column({ nullable: true }) public salt: string + + @Column() public provider: string + + @Column({ type: 'simple-array' }) public roles: rolesType + + @Column() public language: string + + @Column({ nullable: true }) public resetPasswordToken?: string + + @Column({ nullable: true }) public resetPasswordExpires?: Date + + @Column({ nullable: true }) public token?: string + + @Column({ nullable: true }) public apiKey?: string + + @CreateDateColumn() public created: Date + + @UpdateDateColumn() public lastModified: Date } diff --git a/src/entity/visitor.entity.ts b/src/entity/visitor.entity.ts index f5e13e4..dc2212f 100644 --- a/src/entity/visitor.entity.ts +++ b/src/entity/visitor.entity.ts @@ -1,7 +1,16 @@ -import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm' -import { FormFieldDocument } from '../schema/form.field.schema' +import { + 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 { FormFieldEntity } from './form.field.entity' +import { SubmissionEntity } from './submission.entity' @Entity({ name: 'form_visitor' }) export class VisitorEntity { @@ -11,16 +20,24 @@ export class VisitorEntity { @ManyToOne(() => FormEntity, form => form.visitors) public form: FormEntity - @ManyToOne(() => FormEntity, form => form.visitors) - public submission: FormEntity + @OneToMany(() => SubmissionEntity, submission => submission.visitor) + public submissions: SubmissionEntity[] @Column({ nullable: true }) readonly referrer?: string - readonly timeElapsed: number - readonly isSubmitted: boolean - readonly language: string + @Column() 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 } diff --git a/src/guard/gql.auth.guard.ts b/src/guard/gql.auth.guard.ts index 83f4722..6baea9b 100644 --- a/src/guard/gql.auth.guard.ts +++ b/src/guard/gql.auth.guard.ts @@ -1,7 +1,7 @@ -import { ExecutionContext, Injectable } from '@nestjs/common'; -import { GqlExecutionContext } from '@nestjs/graphql'; -import { AuthGuard } from '@nestjs/passport'; -import { ContextCache } from '../resolver/context.cache'; +import { ExecutionContext, Injectable } from '@nestjs/common' +import { GqlExecutionContext } from '@nestjs/graphql' +import { AuthGuard } from '@nestjs/passport' +import { ContextCache } from '../resolver/context.cache' @Injectable() export class GqlAuthGuard extends AuthGuard('jwt') { diff --git a/src/guard/index.ts b/src/guard/index.ts index 981ac62..cab714b 100644 --- a/src/guard/index.ts +++ b/src/guard/index.ts @@ -1,7 +1,7 @@ -import { APP_GUARD } from '@nestjs/core'; -import { GqlAuthGuard } from './gql.auth.guard'; -import { LocalAuthGuard } from './local.auth.guard'; -import { RolesGuard } from './roles.guard'; +import { APP_GUARD } from '@nestjs/core' +import { GqlAuthGuard } from './gql.auth.guard' +import { LocalAuthGuard } from './local.auth.guard' +import { RolesGuard } from './roles.guard' export const guards = [ { diff --git a/src/guard/local.auth.guard.ts b/src/guard/local.auth.guard.ts index c261766..5062b31 100644 --- a/src/guard/local.auth.guard.ts +++ b/src/guard/local.auth.guard.ts @@ -1,6 +1,6 @@ -import { ExecutionContext, Injectable } from '@nestjs/common'; -import { GqlExecutionContext } from '@nestjs/graphql'; -import { AuthGuard } from '@nestjs/passport'; +import { ExecutionContext, Injectable } from '@nestjs/common' +import { GqlExecutionContext } from '@nestjs/graphql' +import { AuthGuard } from '@nestjs/passport' @Injectable() export class LocalAuthGuard extends AuthGuard('local') { diff --git a/src/guard/roles.guard.ts b/src/guard/roles.guard.ts index e3c5623..d07aab8 100644 --- a/src/guard/roles.guard.ts +++ b/src/guard/roles.guard.ts @@ -1,6 +1,6 @@ -import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; -import { Reflector } from '@nestjs/core'; -import { GqlExecutionContext } from '@nestjs/graphql'; +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common' +import { Reflector } from '@nestjs/core' +import { GqlExecutionContext } from '@nestjs/graphql' @Injectable() export class RolesGuard implements CanActivate { diff --git a/src/main.ts b/src/main.ts index d131a8b..0219594 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,9 +1,9 @@ -import { NestApplicationOptions, ValidationPipe } from '@nestjs/common'; -import { NestFactory } from '@nestjs/core'; -import cors from 'cors'; -import { Logger, PinoLogger } from 'nestjs-pino/dist'; -import { LoggerConfig } from './app.imports'; -import { AppModule } from './app.module'; +import { NestApplicationOptions, ValidationPipe } from '@nestjs/common' +import { NestFactory } from '@nestjs/core' +import cors from 'cors' +import { Logger, PinoLogger } from 'nestjs-pino/dist' +import { LoggerConfig } from './app.imports' +import { AppModule } from './app.module' (async () => { const options: NestApplicationOptions = { diff --git a/src/migrations/1619723437787-initial.ts b/src/migrations/1619723437787-initial.ts index c27a220..ee8ba66 100644 --- a/src/migrations/1619723437787-initial.ts +++ b/src/migrations/1619723437787-initial.ts @@ -1,24 +1,35 @@ -import { MigrationInterface, QueryRunner, Table } from "typeorm" +import { MigrationInterface, QueryRunner } from "typeorm" export class initial1619723437787 implements MigrationInterface { name = 'initial1619723437787' public async up(queryRunner: QueryRunner): Promise { - - if (queryRunner.connection.driver.options.type !== 'sqlite') { - 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 "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_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" ("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_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_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 "submission" ("id" SERIAL NOT NULL, CONSTRAINT "PK_7faa571d0e4a7076e85890c9bd0" PRIMARY KEY ("id"))`); - 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 "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 "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 "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 "submission_field" ("id" SERIAL NOT NULL, CONSTRAINT "PK_5443f5f769fce3107982c16e0b5" PRIMARY KEY ("id"))`); - + 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 "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" 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" 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, "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" 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" 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_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" 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 "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 "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" 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)`); + } 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_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`); @@ -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_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 "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_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_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`); - } 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(`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 "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(`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(`CREATE TABLE "submission_field" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL)`); - 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" 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(`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" 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)`); + + + await queryRunner.query(`ALTER TABLE "form_visitor" ADD "deviceLanguage" character varying`); + await queryRunner.query(`ALTER TABLE "form_visitor" ADD "deviceType" character varying`); + await queryRunner.query(`ALTER TABLE "form_visitor" ADD "deviceName" character varying`); + await queryRunner.query(`ALTER TABLE "submission" ADD "deviceLanguage" character varying`); + await queryRunner.query(`ALTER TABLE "submission" ADD "deviceType" character varying`); + await queryRunner.query(`ALTER TABLE "submission" ADD "deviceName" character varying`); + + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "roles"`); + await queryRunner.query(`ALTER TABLE "user" ADD "roles" text NOT NULL`); } } @@ -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_023d9cf1d97e93facc96c86ca70"`); 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 "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_0876741ce2acdaee4553d7a3bbd"`); 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(`DROP TABLE "submission_field"`); await queryRunner.query(`DROP TABLE "form"`); - await queryRunner.query(`DROP TABLE "user"`); 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 "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_hook"`); await queryRunner.query(`DROP TABLE "form_field"`); await queryRunner.query(`DROP TABLE "form_field_option"`); await queryRunner.query(`DROP TABLE "form_field_logic"`); - await queryRunner.query(`DROP TABLE "button"`); } - } diff --git a/src/resolver/auth/auth.login.resolver.ts b/src/resolver/auth/auth.login.resolver.ts index 8d34ff5..39925eb 100644 --- a/src/resolver/auth/auth.login.resolver.ts +++ b/src/resolver/auth/auth.login.resolver.ts @@ -1,7 +1,7 @@ -import { Injectable } from '@nestjs/common'; -import { Args, Mutation } from '@nestjs/graphql'; -import { AuthJwtModel } from '../../dto/auth/auth.jwt.model'; -import { AuthService } from '../../service/auth/auth.service'; +import { Injectable } from '@nestjs/common' +import { Args, Mutation } from '@nestjs/graphql' +import { AuthJwtModel } from '../../dto/auth/auth.jwt.model' +import { AuthService } from '../../service/auth/auth.service' @Injectable() export class AuthLoginResolver { @@ -12,8 +12,8 @@ export class AuthLoginResolver { @Mutation(() => AuthJwtModel) async authLogin( - @Args({ name: 'username', type: () => String }) username, - @Args({ name: 'password', type: () => String }) password, + @Args({ name: 'username', type: () => String }) username: string, + @Args({ name: 'password', type: () => String }) password: string, ): Promise { const user = await this.auth.validateUser(username, password) diff --git a/src/resolver/auth/auth.register.resolver.ts b/src/resolver/auth/auth.register.resolver.ts index 490df6a..efd40b3 100644 --- a/src/resolver/auth/auth.register.resolver.ts +++ b/src/resolver/auth/auth.register.resolver.ts @@ -1,11 +1,11 @@ -import { Injectable } from '@nestjs/common'; -import { Args, Mutation } from '@nestjs/graphql'; -import { PinoLogger } from 'nestjs-pino/dist'; -import { AuthJwtModel } from '../../dto/auth/auth.jwt.model'; -import { UserCreateInput } from '../../dto/user/user.create.input'; -import { AuthService } from '../../service/auth/auth.service'; -import {SettingService} from '../../service/setting.service' -import { UserCreateService } from '../../service/user/user.create.service'; +import { Injectable } from '@nestjs/common' +import { Args, Mutation } from '@nestjs/graphql' +import { PinoLogger } from 'nestjs-pino/dist' +import { AuthJwtModel } from '../../dto/auth/auth.jwt.model' +import { UserCreateInput } from '../../dto/user/user.create.input' +import { AuthService } from '../../service/auth/auth.service' +import { SettingService } from '../../service/setting.service' +import { UserCreateService } from '../../service/user/user.create.service' @Injectable() export class AuthRegisterResolver { diff --git a/src/resolver/auth/index.ts b/src/resolver/auth/index.ts index 249f26f..a13e31b 100644 --- a/src/resolver/auth/index.ts +++ b/src/resolver/auth/index.ts @@ -1,5 +1,5 @@ -import { AuthLoginResolver } from './auth.login.resolver'; -import { AuthRegisterResolver } from './auth.register.resolver'; +import { AuthLoginResolver } from './auth.login.resolver' +import { AuthRegisterResolver } from './auth.register.resolver' export const authServices = [ AuthRegisterResolver, diff --git a/src/resolver/context.cache.ts b/src/resolver/context.cache.ts index 7bc36bb..eb07369 100644 --- a/src/resolver/context.cache.ts +++ b/src/resolver/context.cache.ts @@ -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 { - private users: { - [id: string]: UserDocument, +type ID = string | number + +export class ContextCache { + private cache: { + [key: string]: any } = {} - private forms: { - [id: string]: FormDocument, - } = {} - - 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 getCacheKey(type: string, id: ID): string { + return `${type}:${id}` } - public async getUser(id: any): Promise { - return this.users[id] + public add(key: string, element: B): void { + this.cache[key] = element } - public addForm(form: FormDocument) { - this.forms[form.id] = form - } + public get(key: string, init?: () => Promise): B | Promise { + if (!this.cache[key] && init) { + const result = init() + void result.then(r => { + this.cache[key] = r + }) - public async getForm(id: any): Promise { - return this.forms[id] - } + return result + } - public addSubmission(submission: SubmissionDocument) { - this.submissions[submission.id] = submission - } - - public async getSubmission(id: any): Promise { - return this.submissions[id] - } - - public addFormField(field: FormFieldDocument) { - this.formFields[field.id] = field - } - - public async getFormField(id: any): Promise { - return this.formFields[id] - } - - public addSubmissionField(field: SubmissionFieldDocument) { - this.submissionFields[field.id] = field - } - - public async getSubmissionField(id: any): Promise { - return this.submissionFields[id] + return this.cache[key] } } diff --git a/src/resolver/form/form.create.mutation.ts b/src/resolver/form/form.create.mutation.ts index a60fe69..b50094b 100644 --- a/src/resolver/form/form.create.mutation.ts +++ b/src/resolver/form/form.create.mutation.ts @@ -1,12 +1,13 @@ -import { Injectable } from '@nestjs/common'; -import { Args, Context, Mutation } from '@nestjs/graphql'; -import { Roles } from '../../decorator/roles.decorator'; -import { User } from '../../decorator/user.decorator'; -import { FormCreateInput } from '../../dto/form/form.create.input'; -import { FormModel } from '../../dto/form/form.model'; -import { UserDocument } from '../../schema/user.schema'; -import { FormCreateService } from '../../service/form/form.create.service'; -import { ContextCache } from '../context.cache'; +import { Injectable } from '@nestjs/common' +import { Args, Context, Mutation } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { FormCreateInput } from '../../dto/form/form.create.input' +import { FormModel } from '../../dto/form/form.model' +import { FormEntity } from '../../entity/form.entity' +import { UserEntity } from '../../entity/user.entity' +import { FormCreateService } from '../../service/form/form.create.service' +import { ContextCache } from '../context.cache' @Injectable() export class FormCreateMutation { @@ -18,13 +19,13 @@ export class FormCreateMutation { @Mutation(() => FormModel) @Roles('admin') async createForm( - @User() user: UserDocument, + @User() user: UserEntity, @Args({ name: 'form', type: () => FormCreateInput }) input: FormCreateInput, @Context('cache') cache: ContextCache, ): Promise { const form = await this.createService.create(user, input) - cache.addForm(form) + cache.add(cache.getCacheKey(FormEntity.name, form.id), form) return new FormModel(form) } diff --git a/src/resolver/form/form.delete.mutation.ts b/src/resolver/form/form.delete.mutation.ts index 3fc0968..cbd68f8 100644 --- a/src/resolver/form/form.delete.mutation.ts +++ b/src/resolver/form/form.delete.mutation.ts @@ -1,11 +1,11 @@ -import { Injectable } from '@nestjs/common'; -import { Args, ID, Mutation } from '@nestjs/graphql'; -import { Roles } from '../../decorator/roles.decorator'; -import { User } from '../../decorator/user.decorator'; -import { DeletedModel } from '../../dto/deleted.model'; -import { UserDocument } from '../../schema/user.schema'; -import { FormDeleteService } from '../../service/form/form.delete.service'; -import { FormService } from '../../service/form/form.service'; +import { Injectable } from '@nestjs/common' +import { Args, ID, Mutation } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { DeletedModel } from '../../dto/deleted.model' +import { UserEntity } from '../../entity/user.entity' +import { FormDeleteService } from '../../service/form/form.delete.service' +import { FormService } from '../../service/form/form.service' @Injectable() export class FormDeleteMutation { @@ -18,9 +18,9 @@ export class FormDeleteMutation { @Mutation(() => DeletedModel) @Roles('admin') async deleteForm( - @User() user: UserDocument, + @User() user: UserEntity, @Args({ name: 'id', type: () => ID}) id: string, - ) { + ): Promise { const form = await this.formService.findById(id) if (!form.isLive && !await this.formService.isAdmin(form, user)) { diff --git a/src/resolver/form/form.query.ts b/src/resolver/form/form.query.ts new file mode 100644 index 0000000..32fdeaa --- /dev/null +++ b/src/resolver/form/form.query.ts @@ -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 { + 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) + } +} diff --git a/src/resolver/form/form.resolver.ts b/src/resolver/form/form.resolver.ts index f7690d6..207394b 100644 --- a/src/resolver/form/form.resolver.ts +++ b/src/resolver/form/form.resolver.ts @@ -1,17 +1,17 @@ -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 { 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 { PageModel } from '../../dto/form/page.model'; -import { RespondentNotificationsModel } from '../../dto/form/respondent.notifications.model'; -import { SelfNotificationsModel } from '../../dto/form/self.notifications.model'; -import { UserModel } from '../../dto/user/user.model'; -import { UserDocument } from '../../schema/user.schema'; -import { FormService } from '../../service/form/form.service'; -import { ContextCache } from '../context.cache'; +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 { @@ -20,41 +20,24 @@ export class FormResolver { ) { } - @Query(() => FormModel) - async getFormById( - @User() user: UserDocument, - @Args('id', {type: () => ID}) id, - @Context('cache') cache: ContextCache, - ) { - const form = await this.formService.findById(id) - - if (!form.isLive && !await this.formService.isAdmin(form, user)) { - throw new Error('invalid form') - } - - cache.addForm(form) - - return new FormModel(form) - } - @ResolveField('fields', () => [FormFieldModel]) async getFields( - @User() user: UserDocument, + @User() user: UserEntity, @Parent() parent: FormModel, @Context('cache') cache: ContextCache, ): Promise { - const form = await cache.getForm(parent.id) + const form = await cache.get(cache.getCacheKey(FormEntity.name, parent.id)) return form.fields.map(field => new FormFieldModel(field)) } @ResolveField('hooks', () => [FormHookModel]) async getHooks( - @User() user: UserDocument, + @User() user: UserEntity, @Parent() parent: FormModel, @Context('cache') cache: ContextCache, ): Promise { - const form = await cache.getForm(parent.id) + const form = await cache.get(cache.getCacheKey(FormEntity.name, parent.id)) return form.hooks.map(hook => new FormHookModel(hook)) } @@ -62,11 +45,11 @@ export class FormResolver { @ResolveField('isLive', () => Boolean) @Roles('admin') async getRoles( - @User() user: UserDocument, + @User() user: UserEntity, @Parent() parent: FormModel, @Context('cache') cache: ContextCache, ): Promise { - const form = await cache.getForm(parent.id) + const form = await cache.get(cache.getCacheKey(FormEntity.name, parent.id)) if (!await this.formService.isAdmin(form, user)) { throw new Error('no access to field') @@ -75,45 +58,29 @@ export class FormResolver { return form.isLive } - @ResolveField('selfNotifications', () => SelfNotificationsModel) + @ResolveField('notifications', () => [FormNotificationModel]) @Roles('admin') - async getSelfNotifications( - @User() user: UserDocument, + async getNotifications( + @User() user: UserEntity, @Parent() parent: FormModel, @Context('cache') cache: ContextCache, - ): Promise { - const form = await cache.getForm(parent.id) + ): Promise { + const form = await cache.get(cache.getCacheKey(FormEntity.name, parent.id)) if (!await this.formService.isAdmin(form, user)) { throw new Error('no access to field') } - return new SelfNotificationsModel(form.selfNotifications) - } - - @ResolveField('respondentNotifications', () => RespondentNotificationsModel) - @Roles('admin') - async getRespondentNotifications( - @User() user: UserDocument, - @Parent() parent: FormModel, - @Context('cache') cache: ContextCache, - ): Promise { - const form = await cache.getForm(parent.id) - - if (!await this.formService.isAdmin(form, user)) { - throw new Error('no access to field') - } - - return new RespondentNotificationsModel(form.respondentNotifications) + return form.notifications.map(notification => new FormNotificationModel(notification)) } @ResolveField('design', () => DesignModel) async getDesign( - @User() user: UserDocument, + @User() user: UserEntity, @Parent() parent: FormModel, @Context('cache') cache: ContextCache, ): Promise { - const form = await cache.getForm(parent.id) + const form = await cache.get(cache.getCacheKey(FormEntity.name, parent.id)) return new DesignModel(form.design) } @@ -123,7 +90,7 @@ export class FormResolver { @Parent() parent: FormModel, @Context('cache') cache: ContextCache, ): Promise { - const form = await cache.getForm(parent.id) + const form = await cache.get(cache.getCacheKey(FormEntity.name, parent.id)) return new PageModel(form.startPage) } @@ -133,7 +100,7 @@ export class FormResolver { @Parent() parent: FormModel, @Context('cache') cache: ContextCache, ): Promise { - const form = await cache.getForm(parent.id) + const form = await cache.get(cache.getCacheKey(FormEntity.name, parent.id)) return new PageModel(form.endPage) } @@ -144,7 +111,7 @@ export class FormResolver { @Parent() parent: FormModel, @Context('cache') cache: ContextCache, ): Promise { - const form = await cache.getForm(parent.id) + const form = await cache.get(cache.getCacheKey(FormEntity.name, parent.id)) if (!form.populated('admin')) { form.populate('admin') diff --git a/src/resolver/form/form.search.resolver.ts b/src/resolver/form/form.search.resolver.ts index 120a78f..45eb832 100644 --- a/src/resolver/form/form.search.resolver.ts +++ b/src/resolver/form/form.search.resolver.ts @@ -1,24 +1,25 @@ -import { Args, Context, Query, Resolver } from '@nestjs/graphql'; -import { GraphQLInt } from 'graphql'; -import { User } from '../../decorator/user.decorator'; -import { FormModel } from '../../dto/form/form.model'; -import { PagerFormModel } from '../../dto/form/pager.form.model'; -import { UserDocument } from '../../schema/user.schema'; -import { FormService } from '../../service/form/form.service'; -import { ContextCache } from '../context.cache'; +import { Args, Context, Query, Resolver } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { User } from '../../decorator/user.decorator' +import { FormModel } from '../../dto/form/form.model' +import { FormPagerModel } from '../../dto/form/form.pager.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(() => PagerFormModel) +@Resolver(() => FormPagerModel) export class FormSearchResolver { constructor( private readonly formService: FormService, ) { } - @Query(() => PagerFormModel) + @Query(() => FormPagerModel) async listForms( - @User() user: UserDocument, - @Args('start', {type: () => GraphQLInt, defaultValue: 0, nullable: true}) start, - @Args('limit', {type: () => GraphQLInt, defaultValue: 50, nullable: true}) limit, + @User() user: UserEntity, + @Args('start', {type: () => GraphQLInt, defaultValue: 0, nullable: true}) start: number, + @Args('limit', {type: () => GraphQLInt, defaultValue: 50, nullable: true}) limit: number, @Context('cache') cache: ContextCache, ) { const [forms, total] = await this.formService.find( @@ -28,9 +29,9 @@ export class FormSearchResolver { user.roles.includes('superuser') ? null : user, ) - forms.forEach(form => cache.addForm(form)) + forms.forEach(form => cache.add(cache.getCacheKey(FormEntity.name, form.id), form)) - return new PagerFormModel( + return new FormPagerModel( forms.map(form => new FormModel(form)), total, limit, diff --git a/src/resolver/form/form.statistic.resolver.ts b/src/resolver/form/form.statistic.resolver.ts index 5857059..a70f8fc 100644 --- a/src/resolver/form/form.statistic.resolver.ts +++ b/src/resolver/form/form.statistic.resolver.ts @@ -1,8 +1,8 @@ -import { Query, ResolveField, Resolver } from '@nestjs/graphql'; -import { GraphQLInt } from 'graphql'; -import { Roles } from '../../decorator/roles.decorator'; -import { FormStatisticModel } from '../../dto/form/form.statistic.model'; -import { FormStatisticService } from '../../service/form/form.statistic.service'; +import { Query, ResolveField, Resolver } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { Roles } from '../../decorator/roles.decorator' +import { FormStatisticModel } from '../../dto/form/form.statistic.model' +import { FormStatisticService } from '../../service/form/form.statistic.service' @Resolver(() => FormStatisticModel) export class FormStatisticResolver { diff --git a/src/resolver/form/form.update.mutation.ts b/src/resolver/form/form.update.mutation.ts index 732dcfc..2dd9f82 100644 --- a/src/resolver/form/form.update.mutation.ts +++ b/src/resolver/form/form.update.mutation.ts @@ -1,13 +1,14 @@ -import { Injectable } from '@nestjs/common'; -import { Args, Context, Mutation } from '@nestjs/graphql'; -import { Roles } from '../../decorator/roles.decorator'; -import { User } from '../../decorator/user.decorator'; -import { FormModel } from '../../dto/form/form.model'; -import { FormUpdateInput } from '../../dto/form/form.update.input'; -import { UserDocument } from '../../schema/user.schema'; -import { FormService } from '../../service/form/form.service'; -import { FormUpdateService } from '../../service/form/form.update.service'; -import { ContextCache } from '../context.cache'; +import { Injectable } from '@nestjs/common' +import { Args, Context, Mutation } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { FormModel } from '../../dto/form/form.model' +import { FormUpdateInput } from '../../dto/form/form.update.input' +import { FormEntity } from '../../entity/form.entity' +import { UserEntity } from '../../entity/user.entity' +import { FormService } from '../../service/form/form.service' +import { FormUpdateService } from '../../service/form/form.update.service' +import { ContextCache } from '../context.cache' @Injectable() export class FormUpdateMutation { @@ -20,7 +21,7 @@ export class FormUpdateMutation { @Mutation(() => FormModel) @Roles('admin') async updateForm( - @User() user: UserDocument, + @User() user: UserEntity, @Args({ name: 'form', type: () => FormUpdateInput }) input: FormUpdateInput, @Context('cache') cache: ContextCache, ): Promise { @@ -32,7 +33,7 @@ export class FormUpdateMutation { await this.updateService.update(form, input) - cache.addForm(form) + cache.add(cache.getCacheKey(FormEntity.name, form.id), form) return new FormModel(form) } diff --git a/src/resolver/form/index.ts b/src/resolver/form/index.ts index 94701fa..fd3c151 100644 --- a/src/resolver/form/index.ts +++ b/src/resolver/form/index.ts @@ -1,9 +1,9 @@ -import { FormCreateMutation } from './form.create.mutation'; -import { FormDeleteMutation } from './form.delete.mutation'; -import { FormResolver } from './form.resolver'; -import { FormSearchResolver } from './form.search.resolver'; -import { FormStatisticResolver } from './form.statistic.resolver'; -import { FormUpdateMutation } from './form.update.mutation'; +import { FormCreateMutation } from './form.create.mutation' +import { FormDeleteMutation } from './form.delete.mutation' +import { FormResolver } from './form.resolver' +import { FormSearchResolver } from './form.search.resolver' +import { FormStatisticResolver } from './form.statistic.resolver' +import { FormUpdateMutation } from './form.update.mutation' export const formResolvers = [ FormCreateMutation, diff --git a/src/resolver/index.ts b/src/resolver/index.ts index c3ab89d..e4c87b7 100644 --- a/src/resolver/index.ts +++ b/src/resolver/index.ts @@ -1,10 +1,10 @@ -import { authServices } from './auth'; -import { formResolvers } from './form'; -import { profileResolvers } from './profile'; -import {settingsResolvers} from './setting' -import { StatusResolver } from './status.resolver'; -import { submissionResolvers } from './submission'; -import { userResolvers } from './user'; +import { authServices } from './auth' +import { formResolvers } from './form' +import { profileResolvers } from './profile' +import { settingsResolvers } from './setting' +import { StatusResolver } from './status.resolver' +import { submissionResolvers } from './submission' +import { userResolvers } from './user' export const resolvers = [ StatusResolver, diff --git a/src/resolver/profile/index.ts b/src/resolver/profile/index.ts index c504594..9c4403b 100644 --- a/src/resolver/profile/index.ts +++ b/src/resolver/profile/index.ts @@ -1,5 +1,5 @@ -import { ProfileResolver } from './profile.resolver'; -import { ProfileUpdateMutation } from './profile.update.mutation'; +import { ProfileResolver } from './profile.resolver' +import { ProfileUpdateMutation } from './profile.update.mutation' export const profileResolvers = [ ProfileResolver, diff --git a/src/resolver/profile/profile.resolver.ts b/src/resolver/profile/profile.resolver.ts index 2ad5796..0c02cd3 100644 --- a/src/resolver/profile/profile.resolver.ts +++ b/src/resolver/profile/profile.resolver.ts @@ -1,18 +1,18 @@ -import { Context, Query } from '@nestjs/graphql'; -import { Roles } from '../../decorator/roles.decorator'; -import { User } from '../../decorator/user.decorator'; -import { ProfileModel } from '../../dto/profile/profile.model'; -import { UserDocument } from '../../schema/user.schema'; -import { ContextCache } from '../context.cache'; +import { Context, Query } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { ProfileModel } from '../../dto/profile/profile.model' +import { UserEntity } from '../../entity/user.entity' +import { ContextCache } from '../context.cache' export class ProfileResolver { @Query(() => ProfileModel) @Roles('user') async me( - @User() user: UserDocument, + @User() user: UserEntity, @Context('cache') cache: ContextCache, ): Promise { - cache.addUser(user) + cache.add(cache.getCacheKey(UserEntity.name, user.id), user) return new ProfileModel(user) } diff --git a/src/resolver/profile/profile.update.mutation.ts b/src/resolver/profile/profile.update.mutation.ts index 80f49a9..aae9e3f 100644 --- a/src/resolver/profile/profile.update.mutation.ts +++ b/src/resolver/profile/profile.update.mutation.ts @@ -1,11 +1,11 @@ -import { Injectable } from '@nestjs/common'; -import { Args, Context, Mutation } from '@nestjs/graphql'; -import { User } from '../../decorator/user.decorator'; -import { ProfileModel } from '../../dto/profile/profile.model'; -import { ProfileUpdateInput } from '../../dto/profile/profile.update.input'; -import { UserDocument } from '../../schema/user.schema'; -import { ProfileUpdateService } from '../../service/profile/profile.update.service'; -import { ContextCache } from '../context.cache'; +import { Injectable } from '@nestjs/common' +import { Args, Context, Mutation } from '@nestjs/graphql' +import { User } from '../../decorator/user.decorator' +import { ProfileModel } from '../../dto/profile/profile.model' +import { ProfileUpdateInput } from '../../dto/profile/profile.update.input' +import { UserEntity } from '../../entity/user.entity' +import { ProfileUpdateService } from '../../service/profile/profile.update.service' +import { ContextCache } from '../context.cache' @Injectable() export class ProfileUpdateMutation { @@ -16,13 +16,13 @@ export class ProfileUpdateMutation { @Mutation(() => ProfileModel) async updateProfile( - @User() user: UserDocument, + @User() user: UserEntity, @Args({ name: 'user', type: () => ProfileUpdateInput }) input: ProfileUpdateInput, @Context('cache') cache: ContextCache, ): Promise { await this.updateService.update(user, input) - cache.addUser(user) + cache.add(cache.getCacheKey(UserEntity.name, user.id), user) return new ProfileModel(user) } diff --git a/src/resolver/setting/index.ts b/src/resolver/setting/index.ts index 50b1b78..80cc7ef 100644 --- a/src/resolver/setting/index.ts +++ b/src/resolver/setting/index.ts @@ -1,5 +1,5 @@ -import {SettingMutation} from './setting.mutation' -import {SettingResolver} from './setting.resolver' +import { SettingMutation } from './setting.mutation' +import { SettingResolver } from './setting.resolver' export const settingsResolvers = [ SettingResolver, diff --git a/src/resolver/setting/setting.mutation.ts b/src/resolver/setting/setting.mutation.ts index 523722a..4f78a62 100644 --- a/src/resolver/setting/setting.mutation.ts +++ b/src/resolver/setting/setting.mutation.ts @@ -1,5 +1,5 @@ -import {Injectable} from '@nestjs/common' -import {Roles} from '../../decorator/roles.decorator' +import { Injectable } from '@nestjs/common' +import { Roles } from '../../decorator/roles.decorator' @Injectable() export class SettingMutation { diff --git a/src/resolver/setting/setting.resolver.ts b/src/resolver/setting/setting.resolver.ts index c95f772..d46bc47 100644 --- a/src/resolver/setting/setting.resolver.ts +++ b/src/resolver/setting/setting.resolver.ts @@ -1,11 +1,11 @@ -import {Injectable} from '@nestjs/common' -import {Args, ID, Query} from '@nestjs/graphql' -import {Roles} from '../../decorator/roles.decorator' -import {User} from '../../decorator/user.decorator' -import {PagerSettingModel} from '../../dto/setting/pager.setting.model' -import {SettingModel} from '../../dto/setting/setting.model' -import {UserDocument} from '../../schema/user.schema' -import {SettingService} from '../../service/setting.service' +import { Injectable } from '@nestjs/common' +import { Args, ID, Query } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { SettingModel } from '../../dto/setting/setting.model' +import { SettingPagerModel } from '../../dto/setting/setting.pager.model' +import { UserEntity } from '../../entity/user.entity' +import { SettingService } from '../../service/setting.service' @Injectable() export class SettingResolver { @@ -14,11 +14,11 @@ export class SettingResolver { ) { } - @Query(() => PagerSettingModel) + @Query(() => SettingPagerModel) @Roles('superuser') - async getSettings(): Promise { + async getSettings(): Promise { // TODO https://github.com/ohmyform/api/issues/3 - return new PagerSettingModel( + return new SettingPagerModel( [], 0, 0, @@ -29,7 +29,7 @@ export class SettingResolver { @Query(() => SettingModel) async getSetting( @Args('key', {type: () => ID}) key: string, - @User() user: UserDocument, + @User() user: UserEntity, ): Promise { if (!this.settingService.isPublicKey(key) && !user.roles.includes('superuser')) { throw new Error(`no access to key ${key}`) diff --git a/src/resolver/status.resolver.ts b/src/resolver/status.resolver.ts index 007f774..ce118f9 100644 --- a/src/resolver/status.resolver.ts +++ b/src/resolver/status.resolver.ts @@ -1,5 +1,5 @@ -import { Query, Resolver } from '@nestjs/graphql'; -import { StatusModel } from '../dto/status.model'; +import { Query, Resolver } from '@nestjs/graphql' +import { StatusModel } from '../dto/status.model' @Resolver(() => StatusModel) export class StatusResolver { diff --git a/src/resolver/submission/index.ts b/src/resolver/submission/index.ts index 741fa26..bcff27f 100644 --- a/src/resolver/submission/index.ts +++ b/src/resolver/submission/index.ts @@ -1,10 +1,10 @@ -import { SubmissionFieldResolver } from './submission.field.resolver'; -import { SubmissionProgressResolver } from './submission.progress.resolver'; -import { SubmissionResolver } from './submission.resolver'; -import { SubmissionSearchResolver } from './submission.search.resolver'; -import { SubmissionSetFieldMutation } from './submission.set.field.mutation'; -import { SubmissionStartMutation } from './submission.start.mutation'; -import { SubmissionStatisticResolver } from './submission.statistic.resolver'; +import { SubmissionFieldResolver } from './submission.field.resolver' +import { SubmissionProgressResolver } from './submission.progress.resolver' +import { SubmissionResolver } from './submission.resolver' +import { SubmissionSearchResolver } from './submission.search.resolver' +import { SubmissionSetFieldMutation } from './submission.set.field.mutation' +import { SubmissionStartMutation } from './submission.start.mutation' +import { SubmissionStatisticResolver } from './submission.statistic.resolver' export const submissionResolvers = [ SubmissionFieldResolver, diff --git a/src/resolver/submission/submission.field.resolver.ts b/src/resolver/submission/submission.field.resolver.ts index 421872d..95ffcc0 100644 --- a/src/resolver/submission/submission.field.resolver.ts +++ b/src/resolver/submission/submission.field.resolver.ts @@ -1,7 +1,8 @@ -import { Context, Parent, ResolveField, Resolver } from '@nestjs/graphql'; -import { FormFieldModel } from '../../dto/form/form.field.model'; -import { SubmissionFieldModel } from '../../dto/submission/submission.field.model'; -import { ContextCache } from '../context.cache'; +import { Context, Parent, ResolveField, Resolver } from '@nestjs/graphql' +import { FormFieldModel } from '../../dto/form/form.field.model' +import { SubmissionFieldModel } from '../../dto/submission/submission.field.model' +import { SubmissionFieldEntity } from '../../entity/submission.field.entity' +import { ContextCache } from '../context.cache' @Resolver(() => SubmissionFieldModel) export class SubmissionFieldResolver { @@ -10,16 +11,12 @@ export class SubmissionFieldResolver { @Parent() parent: SubmissionFieldModel, @Context('cache') cache: ContextCache, ): Promise { - const submissionField = await cache.getSubmissionField(parent.id) + const submissionField = await cache.get(cache.getCacheKey(SubmissionFieldEntity.name, parent.id)) - console.log(submissionField.field) - - const field = await cache.getFormField(submissionField.field) - - if (!field) { + if (!submissionField.field) { return null } - return new FormFieldModel(field) + return new FormFieldModel(submissionField.field) } } diff --git a/src/resolver/submission/submission.progress.resolver.ts b/src/resolver/submission/submission.progress.resolver.ts index 3c94be1..93201f3 100644 --- a/src/resolver/submission/submission.progress.resolver.ts +++ b/src/resolver/submission/submission.progress.resolver.ts @@ -1,5 +1,5 @@ -import { Resolver } from '@nestjs/graphql'; -import { SubmissionProgressModel } from '../../dto/submission/submission.progress.model'; +import { Resolver } from '@nestjs/graphql' +import { SubmissionProgressModel } from '../../dto/submission/submission.progress.model' @Resolver(() => SubmissionProgressModel) export class SubmissionProgressResolver { diff --git a/src/resolver/submission/submission.resolver.ts b/src/resolver/submission/submission.resolver.ts index cbde1f1..979fc81 100644 --- a/src/resolver/submission/submission.resolver.ts +++ b/src/resolver/submission/submission.resolver.ts @@ -1,32 +1,32 @@ -import { Context, Parent, ResolveField, Resolver } from '@nestjs/graphql'; -import { User } from '../../decorator/user.decorator'; -import { SubmissionFieldModel } from '../../dto/submission/submission.field.model'; -import { SubmissionModel } from '../../dto/submission/submission.model'; -import { UserDocument } from '../../schema/user.schema'; -import { ContextCache } from '../context.cache'; +import { Context, Parent, ResolveField, Resolver } from '@nestjs/graphql' +import { User } from '../../decorator/user.decorator' +import { SubmissionFieldModel } from '../../dto/submission/submission.field.model' +import { SubmissionModel } from '../../dto/submission/submission.model' +import { FormEntity } from '../../entity/form.entity' +import { FormFieldEntity } from '../../entity/form.field.entity' +import { SubmissionEntity } from '../../entity/submission.entity' +import { SubmissionFieldEntity } from '../../entity/submission.field.entity' +import { UserEntity } from '../../entity/user.entity' +import { ContextCache } from '../context.cache' @Resolver(() => SubmissionModel) export class SubmissionResolver { @ResolveField('fields', () => [SubmissionFieldModel]) async getFields( - @User() user: UserDocument, + @User() user: UserEntity, @Parent() parent: SubmissionModel, @Context('cache') cache: ContextCache, ): Promise { - const submission = await cache.getSubmission(parent.id) + const submission = await cache.get(cache.getCacheKey(SubmissionEntity.name, parent.id)) - if (!submission.populated('form')) { - submission.populate('form') - await submission.execPopulate() - } + cache.add(cache.getCacheKey(FormEntity.name, submission.form.id), submission.form) - cache.addForm(submission.form) submission.form.fields.forEach(field => { - cache.addFormField(field) + cache.add(cache.getCacheKey(FormFieldEntity.name, field.id), field) }) return submission.fields.map(field => { - cache.addSubmissionField(field) + cache.add(cache.getCacheKey(SubmissionFieldEntity.name, field.id), field) return new SubmissionFieldModel(field) }) } diff --git a/src/resolver/submission/submission.search.resolver.ts b/src/resolver/submission/submission.search.resolver.ts index 5d7093c..393cdde 100644 --- a/src/resolver/submission/submission.search.resolver.ts +++ b/src/resolver/submission/submission.search.resolver.ts @@ -1,14 +1,15 @@ -import { Args, Context, ID, Query, Resolver } from '@nestjs/graphql'; -import { GraphQLInt } from 'graphql'; -import { User } from '../../decorator/user.decorator'; -import { PagerSubmissionModel } from '../../dto/submission/pager.submission.model'; -import { SubmissionModel } from '../../dto/submission/submission.model'; -import { UserDocument } from '../../schema/user.schema'; -import { FormService } from '../../service/form/form.service'; -import { SubmissionService } from '../../service/submission/submission.service'; -import { ContextCache } from '../context.cache'; +import { Args, Context, ID, Query, Resolver } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { User } from '../../decorator/user.decorator' +import { SubmissionModel } from '../../dto/submission/submission.model' +import { SubmissionPagerModel } from '../../dto/submission/submission.pager.model' +import { SubmissionEntity } from '../../entity/submission.entity' +import { UserEntity } from '../../entity/user.entity' +import { FormService } from '../../service/form/form.service' +import { SubmissionService } from '../../service/submission/submission.service' +import { ContextCache } from '../context.cache' -@Resolver(() => PagerSubmissionModel) +@Resolver(() => SubmissionPagerModel) export class SubmissionSearchResolver { constructor( private readonly formService: FormService, @@ -16,14 +17,14 @@ export class SubmissionSearchResolver { ) { } - @Query(() => PagerSubmissionModel) + @Query(() => SubmissionPagerModel) async listSubmissions( - @User() user: UserDocument, + @User() user: UserEntity, @Args('form', {type: () => ID}) id: string, - @Args('start', {type: () => GraphQLInt, defaultValue: 0, nullable: true}) start, - @Args('limit', {type: () => GraphQLInt, defaultValue: 50, nullable: true}) limit, + @Args('start', {type: () => GraphQLInt, defaultValue: 0, nullable: true}) start: number, + @Args('limit', {type: () => GraphQLInt, defaultValue: 50, nullable: true}) limit: number, @Context('cache') cache: ContextCache, - ): Promise { + ): Promise { const form = await this.formService.findById(id) const [submissions, total] = await this.submissionService.find( @@ -33,9 +34,9 @@ export class SubmissionSearchResolver { {}, ) - submissions.forEach(submission => cache.addSubmission(submission)) + submissions.forEach(submission => cache.add(cache.getCacheKey(SubmissionEntity.name, submission.id), submission)) - return new PagerSubmissionModel( + return new SubmissionPagerModel( submissions.map(submission => new SubmissionModel(submission)), total, limit, diff --git a/src/resolver/submission/submission.set.field.mutation.ts b/src/resolver/submission/submission.set.field.mutation.ts index 8f3f583..3f937f2 100644 --- a/src/resolver/submission/submission.set.field.mutation.ts +++ b/src/resolver/submission/submission.set.field.mutation.ts @@ -1,12 +1,13 @@ -import { Injectable } from '@nestjs/common'; -import { Args, Context, ID, Mutation } from '@nestjs/graphql'; -import { User } from '../../decorator/user.decorator'; -import { SubmissionProgressModel } from '../../dto/submission/submission.progress.model'; -import { SubmissionSetFieldInput } from '../../dto/submission/submission.set.field.input'; -import { UserDocument } from '../../schema/user.schema'; -import { SubmissionService } from '../../service/submission/submission.service'; -import { SubmissionSetFieldService } from '../../service/submission/submission.set.field.service'; -import { ContextCache } from '../context.cache'; +import { Injectable } from '@nestjs/common' +import { Args, Context, ID, Mutation } from '@nestjs/graphql' +import { User } from '../../decorator/user.decorator' +import { SubmissionProgressModel } from '../../dto/submission/submission.progress.model' +import { SubmissionSetFieldInput } from '../../dto/submission/submission.set.field.input' +import { SubmissionEntity } from '../../entity/submission.entity' +import { UserEntity } from '../../entity/user.entity' +import { SubmissionService } from '../../service/submission/submission.service' +import { SubmissionSetFieldService } from '../../service/submission/submission.set.field.service' +import { ContextCache } from '../context.cache' @Injectable() export class SubmissionSetFieldMutation { @@ -18,7 +19,7 @@ export class SubmissionSetFieldMutation { @Mutation(() => SubmissionProgressModel) async submissionSetField( - @User() user: UserDocument, + @User() user: UserEntity, @Args({ name: 'submission', type: () => ID }) id: string, @Args({ name: 'field', type: () => SubmissionSetFieldInput }) input: SubmissionSetFieldInput, @Context('cache') cache: ContextCache, @@ -31,7 +32,7 @@ export class SubmissionSetFieldMutation { await this.setFieldService.saveField(submission, input) - cache.addSubmission(submission) + cache.add(cache.getCacheKey(SubmissionEntity.name, submission.id), submission) return new SubmissionProgressModel(submission) } diff --git a/src/resolver/submission/submission.start.mutation.ts b/src/resolver/submission/submission.start.mutation.ts index fb499da..af03ba0 100644 --- a/src/resolver/submission/submission.start.mutation.ts +++ b/src/resolver/submission/submission.start.mutation.ts @@ -1,12 +1,13 @@ -import { Injectable } from '@nestjs/common'; -import { Args, Context, ID, Mutation } from '@nestjs/graphql'; -import { User } from '../../decorator/user.decorator'; -import { SubmissionProgressModel } from '../../dto/submission/submission.progress.model'; -import { SubmissionStartInput } from '../../dto/submission/submission.start.input'; -import { UserDocument } from '../../schema/user.schema'; -import { FormService } from '../../service/form/form.service'; -import { SubmissionStartService } from '../../service/submission/submission.start.service'; -import { ContextCache } from '../context.cache'; +import { Injectable } from '@nestjs/common' +import { Args, Context, ID, Mutation } from '@nestjs/graphql' +import { User } from '../../decorator/user.decorator' +import { SubmissionProgressModel } from '../../dto/submission/submission.progress.model' +import { SubmissionStartInput } from '../../dto/submission/submission.start.input' +import { SubmissionEntity } from '../../entity/submission.entity' +import { UserEntity } from '../../entity/user.entity' +import { FormService } from '../../service/form/form.service' +import { SubmissionStartService } from '../../service/submission/submission.start.service' +import { ContextCache } from '../context.cache' @Injectable() export class SubmissionStartMutation { @@ -18,7 +19,7 @@ export class SubmissionStartMutation { @Mutation(() => SubmissionProgressModel) async submissionStart( - @User() user: UserDocument, + @User() user: UserEntity, @Args({ name: 'form', type: () => ID }) id: string, @Args({ name: 'submission', type: () => SubmissionStartInput }) input: SubmissionStartInput, @Context('cache') cache: ContextCache, @@ -27,7 +28,7 @@ export class SubmissionStartMutation { const submission = await this.startService.start(form, input, user) - cache.addSubmission(submission) + cache.add(cache.getCacheKey(SubmissionEntity.name, submission.id), submission) return new SubmissionProgressModel(submission) } diff --git a/src/resolver/submission/submission.statistic.resolver.ts b/src/resolver/submission/submission.statistic.resolver.ts index 72a9ca0..8e0a886 100644 --- a/src/resolver/submission/submission.statistic.resolver.ts +++ b/src/resolver/submission/submission.statistic.resolver.ts @@ -1,8 +1,8 @@ -import { Query, ResolveField, Resolver } from '@nestjs/graphql'; -import { GraphQLInt } from 'graphql'; -import { Roles } from '../../decorator/roles.decorator'; -import { SubmissionStatisticModel } from '../../dto/submission/submission.statistic.model'; -import { SubmissionStatisticService } from '../../service/submission/submission.statistic.service'; +import { Query, ResolveField, Resolver } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { Roles } from '../../decorator/roles.decorator' +import { SubmissionStatisticModel } from '../../dto/submission/submission.statistic.model' +import { SubmissionStatisticService } from '../../service/submission/submission.statistic.service' @Resolver(() => SubmissionStatisticModel) export class SubmissionStatisticResolver { diff --git a/src/resolver/user/index.ts b/src/resolver/user/index.ts index 0d6ef2a..f3bcdda 100644 --- a/src/resolver/user/index.ts +++ b/src/resolver/user/index.ts @@ -1,8 +1,8 @@ -import { UserDeleteMutation } from './user.delete.mutation'; -import { UserResolver } from './user.resolver'; -import { UserSearchResolver } from './user.search.resolver'; -import { UserStatisticResolver } from './user.statistic.resolver'; -import { UserUpdateMutation } from './user.update.mutation'; +import { UserDeleteMutation } from './user.delete.mutation' +import { UserResolver } from './user.resolver' +import { UserSearchResolver } from './user.search.resolver' +import { UserStatisticResolver } from './user.statistic.resolver' +import { UserUpdateMutation } from './user.update.mutation' export const userResolvers = [ UserDeleteMutation, diff --git a/src/resolver/user/user.delete.mutation.ts b/src/resolver/user/user.delete.mutation.ts index 16d4b93..ce186df 100644 --- a/src/resolver/user/user.delete.mutation.ts +++ b/src/resolver/user/user.delete.mutation.ts @@ -1,10 +1,10 @@ -import { Injectable } from '@nestjs/common'; -import { Args, ID, Mutation } from '@nestjs/graphql'; -import { Roles } from '../../decorator/roles.decorator'; -import { User } from '../../decorator/user.decorator'; -import { DeletedModel } from '../../dto/deleted.model'; -import { UserDocument } from '../../schema/user.schema'; -import { UserDeleteService } from '../../service/user/user.delete.service'; +import { Injectable } from '@nestjs/common' +import { Args, ID, Mutation } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { DeletedModel } from '../../dto/deleted.model' +import { UserEntity } from '../../entity/user.entity' +import { UserDeleteService } from '../../service/user/user.delete.service' @Injectable() export class UserDeleteMutation { @@ -16,10 +16,10 @@ export class UserDeleteMutation { @Mutation(() => DeletedModel) @Roles('admin') async deleteUser( - @User() auth: UserDocument, + @User() auth: UserEntity, @Args({ name: 'id', type: () => ID}) id: string, ): Promise { - if (auth.id === id) { + if (auth.id.toString() === id) { throw new Error('cannot delete your own user') } diff --git a/src/resolver/user/user.resolver.ts b/src/resolver/user/user.resolver.ts index 1672f66..11575a8 100644 --- a/src/resolver/user/user.resolver.ts +++ b/src/resolver/user/user.resolver.ts @@ -1,10 +1,10 @@ -import { Args, Context, ID, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql'; -import { Roles } from '../../decorator/roles.decorator'; -import { User } from '../../decorator/user.decorator'; -import { UserModel } from '../../dto/user/user.model'; -import { UserDocument } from '../../schema/user.schema'; -import { UserService } from '../../service/user/user.service'; -import { ContextCache } from '../context.cache'; +import { Args, Context, ID, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { UserModel } from '../../dto/user/user.model' +import { UserEntity } from '../../entity/user.entity' +import { UserService } from '../../service/user/user.service' +import { ContextCache } from '../context.cache' @Resolver(() => UserModel) export class UserResolver { @@ -15,13 +15,13 @@ export class UserResolver { @Query(() => UserModel) @Roles('admin') - async getUserById( + public async getUserById( @Args('id', {type: () => ID}) id, @Context('cache') cache: ContextCache, - ) { + ): Promise { const user = await this.userService.findById(id) - cache.addUser(user) + cache.add(cache.getCacheKey(UserEntity.name, user.id), user) return new UserModel(user) } @@ -29,18 +29,18 @@ export class UserResolver { @ResolveField('roles', () => [String]) @Roles('user') async getRoles( - @User() user: UserDocument, + @User() user: UserEntity, @Parent() parent: UserModel, @Context('cache') cache: ContextCache, ): Promise { return await this.returnFieldForSuperuser( - await cache.getUser(parent.id), + await cache.get(cache.getCacheKey(UserEntity.name, parent.id)), user, c => c.roles ) } - async returnFieldForSuperuser(parent: UserDocument, user: UserDocument, callback: (user: UserDocument) => T): Promise { + async returnFieldForSuperuser(parent: UserEntity, user: UserEntity, callback: (user: UserEntity) => T): Promise { if (user.id !== parent.id && !await this.userService.isSuperuser(user)) { throw new Error('No access to roles') } diff --git a/src/resolver/user/user.search.resolver.ts b/src/resolver/user/user.search.resolver.ts index 3012d98..ce4b9d4 100644 --- a/src/resolver/user/user.search.resolver.ts +++ b/src/resolver/user/user.search.resolver.ts @@ -1,30 +1,31 @@ -import { Args, Context, Query, Resolver } from '@nestjs/graphql'; -import { GraphQLInt } from 'graphql'; -import { Roles } from '../../decorator/roles.decorator'; -import { PagerUserModel } from '../../dto/user/pager.user.model'; -import { UserModel } from '../../dto/user/user.model'; -import { UserService } from '../../service/user/user.service'; -import { ContextCache } from '../context.cache'; +import { Args, Context, Query, Resolver } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { Roles } from '../../decorator/roles.decorator' +import { UserModel } from '../../dto/user/user.model' +import { UserPagerModel } from '../../dto/user/user.pager.model' +import { UserEntity } from '../../entity/user.entity' +import { UserService } from '../../service/user/user.service' +import { ContextCache } from '../context.cache' -@Resolver(() => PagerUserModel) +@Resolver(() => UserPagerModel) export class UserSearchResolver { constructor( private readonly userService: UserService, ) { } - @Query(() => PagerUserModel) + @Query(() => UserPagerModel) @Roles('superuser') async listUsers( - @Args('start', {type: () => GraphQLInt, defaultValue: 0, nullable: true}) start, - @Args('limit', {type: () => GraphQLInt, defaultValue: 50, nullable: true}) limit, + @Args('start', {type: () => GraphQLInt, defaultValue: 0, nullable: true}) start: number, + @Args('limit', {type: () => GraphQLInt, defaultValue: 50, nullable: true}) limit: number, @Context('cache') cache: ContextCache, - ): Promise { + ): Promise { const [entities, total] = await this.userService.find(start, limit) - return new PagerUserModel( + return new UserPagerModel( entities.map(entity => { - cache.addUser(entity) + cache.add(cache.getCacheKey(UserEntity.name, entity.id), entity) return new UserModel(entity) }), total, diff --git a/src/resolver/user/user.statistic.resolver.ts b/src/resolver/user/user.statistic.resolver.ts index 1bd19b0..de0e4a3 100644 --- a/src/resolver/user/user.statistic.resolver.ts +++ b/src/resolver/user/user.statistic.resolver.ts @@ -1,8 +1,8 @@ -import { Query, ResolveField, Resolver } from '@nestjs/graphql'; -import { GraphQLInt } from 'graphql'; -import { Roles } from '../../decorator/roles.decorator'; -import { UserStatisticModel } from '../../dto/user/user.statistic.model'; -import { UserStatisticService } from '../../service/user/user.statistic.service'; +import { Query, ResolveField, Resolver } from '@nestjs/graphql' +import { GraphQLInt } from 'graphql' +import { Roles } from '../../decorator/roles.decorator' +import { UserStatisticModel } from '../../dto/user/user.statistic.model' +import { UserStatisticService } from '../../service/user/user.statistic.service' @Resolver(() => UserStatisticModel) export class UserStatisticResolver { diff --git a/src/resolver/user/user.update.mutation.ts b/src/resolver/user/user.update.mutation.ts index 0304e80..da07eb4 100644 --- a/src/resolver/user/user.update.mutation.ts +++ b/src/resolver/user/user.update.mutation.ts @@ -1,13 +1,13 @@ -import { Injectable } from '@nestjs/common'; -import { Args, Context, Mutation } from '@nestjs/graphql'; -import { Roles } from '../../decorator/roles.decorator'; -import { User } from '../../decorator/user.decorator'; -import { UserModel } from '../../dto/user/user.model'; -import { UserUpdateInput } from '../../dto/user/user.update.input'; -import { UserDocument } from '../../schema/user.schema'; -import { UserService } from '../../service/user/user.service'; -import { UserUpdateService } from '../../service/user/user.update.service'; -import { ContextCache } from '../context.cache'; +import { Injectable } from '@nestjs/common' +import { Args, Context, Mutation } from '@nestjs/graphql' +import { Roles } from '../../decorator/roles.decorator' +import { User } from '../../decorator/user.decorator' +import { UserModel } from '../../dto/user/user.model' +import { UserUpdateInput } from '../../dto/user/user.update.input' +import { UserEntity } from '../../entity/user.entity' +import { UserService } from '../../service/user/user.service' +import { UserUpdateService } from '../../service/user/user.update.service' +import { ContextCache } from '../context.cache' @Injectable() export class UserUpdateMutation { @@ -20,11 +20,11 @@ export class UserUpdateMutation { @Mutation(() => UserModel) @Roles('superuser') async updateUser( - @User() auth: UserDocument, + @User() auth: UserEntity, @Args({ name: 'user', type: () => UserUpdateInput }) input: UserUpdateInput, @Context('cache') cache: ContextCache, ): Promise { - if (auth.id === input.id) { + if (auth.id.toString() === input.id) { throw new Error('cannot update your own user') } @@ -32,7 +32,7 @@ export class UserUpdateMutation { await this.updateService.update(user, input) - cache.addUser(user) + cache.add(cache.getCacheKey(UserEntity.name, user.id), user) return new UserModel(user) } diff --git a/src/schema/button.schema.ts b/src/schema/button.schema.ts deleted file mode 100644 index b2f62f8..0000000 --- a/src/schema/button.schema.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Document, Schema } from 'mongoose'; -import { matchType } from '../config/fields'; - -export interface ButtonDocument extends Document{ - readonly url?: string - readonly action?: string - readonly text?: string - readonly bgColor?: string - readonly activeColor?: string - readonly color?: string -} - -export const ButtonSchema = new Schema({ - url: { - type: String, - match: matchType.url, - }, - action: { - type: String, - }, - text: { - type: String, - }, - bgColor: { - type: String, - match: matchType.color, - default: '#fff', - }, - activeColor: { - type: String, - match: matchType.color, - default: '#40a9ff', - }, - color: { - type: String, - match: matchType.color, - default: '#666' - }, -}) diff --git a/src/schema/embedded/field.option.ts b/src/schema/embedded/field.option.ts deleted file mode 100644 index 0fb0997..0000000 --- a/src/schema/embedded/field.option.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Document, SchemaDefinition } from 'mongoose'; - -export interface FieldOptionDocument extends Document { - readonly key?: string - readonly title?: string - readonly value: string -} - -export const FieldOption: SchemaDefinition = { - option_id: { - alias: 'key', - type: String, - }, - option_title: { - alias: 'title', - type: String, - }, - option_value: { - alias: 'value', - type: String, - trim: true, - }, -} diff --git a/src/schema/embedded/logic.jump.ts b/src/schema/embedded/logic.jump.ts deleted file mode 100644 index c34ecf0..0000000 --- a/src/schema/embedded/logic.jump.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Document, Schema, SchemaDefinition } from 'mongoose'; -import { FormFieldSchemaName } from '../form.field.schema'; - -export interface LogicJumpDocument extends Document { - readonly expressionString?: string - readonly fieldA?: string - readonly valueB?: string - readonly jumpTo?: string - readonly enabled?: boolean -} - -export const LogicJump: SchemaDefinition = { - expressionString: { - type: String, - enum: [ - 'field == static', - 'field != static', - 'field > static', - 'field >= static', - 'field <= static', - 'field < static', - 'field contains static', - 'field !contains static', - 'field begins static', - 'field !begins static', - 'field ends static', - 'field !ends static', - ], - }, - fieldA: { - type: Schema.Types.ObjectId, - ref: FormFieldSchemaName - }, - valueB: { - type: String, - }, - jumpTo: { - type: Schema.Types.ObjectId, - ref: FormFieldSchemaName - }, - enabled: { - type: Boolean, - default: false, - }, -} diff --git a/src/schema/embedded/rating.field.ts b/src/schema/embedded/rating.field.ts deleted file mode 100644 index a61b131..0000000 --- a/src/schema/embedded/rating.field.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Document, SchemaDefinition } from 'mongoose'; - -export interface RatingFieldDocument extends Document { - readonly steps?: number - readonly shape?: string -} - -export const RatingField: SchemaDefinition = { - steps: { - type: Number, - min: 1, - max: 10, - }, - shape: { - type: String, - enum: [ - 'Heart', - 'Star', - 'thumbs-up', - 'thumbs-down', - 'Circle', - 'Square', - 'Check Circle', - 'Smile Outlined', - 'Hourglass', - 'bell', - 'Paper Plane', - 'Comment', - 'Trash', - ], - }, -} diff --git a/src/schema/form.field.schema.ts b/src/schema/form.field.schema.ts deleted file mode 100644 index 1e023bd..0000000 --- a/src/schema/form.field.schema.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Document, Schema } from 'mongoose'; -import { fieldTypes, matchType } from '../config/fields' -import { FieldOption } from './embedded/field.option'; -import { LogicJump } from './embedded/logic.jump'; -import { RatingField } from './embedded/rating.field'; - -export const FormFieldSchemaName = 'FormField' - -export interface FormFieldDocument extends Document { - title: string - description: string - slug?: string - logicJump: any - rating: any - options: any - required: boolean - disabled: boolean - type: string - value: any -} - -export const FormFieldSchema = new Schema({ - title: { - type: String, - trim: true, - }, - description: { - type: String, - default: '', - }, - slug: { - type: String, - required: false, - match: matchType.slug, - trim: true, - }, - logicJump: { - type: LogicJump, - }, - ratingOptions: { - alias: 'rating', - type: RatingField, - }, - fieldOptions: { - alias: 'options', - type: [FieldOption], - }, - required: { - type: Boolean, - default: true, - }, - disabled: { - type: Boolean, - default: false, - }, - fieldType: { - alias: 'type', - type: String, - enum: fieldTypes, - }, - fieldValue: { - alias: 'value', - type: Schema.Types.Mixed, - default: '', - }, -}) - -export const FormFieldDefinition = { - name: FormFieldSchemaName, - schema: FormFieldSchema, -} - diff --git a/src/schema/form.hook.schema.ts b/src/schema/form.hook.schema.ts deleted file mode 100644 index c436e71..0000000 --- a/src/schema/form.hook.schema.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Document, Schema } from 'mongoose'; -import { fieldTypes, matchType } from '../config/fields' -import { FieldOption } from './embedded/field.option'; -import { LogicJump } from './embedded/logic.jump'; -import { RatingField } from './embedded/rating.field'; - -export const FormHookSchemaName = 'FormHook' - -export interface FormHookDocument extends Document { - readonly enabled: boolean - readonly url?: string - readonly format?: string -} - -export const FormHookSchema = new Schema({ - enabled: { - type: Boolean, - default: true, - }, - url: { - type: String, - match: matchType.url, - trim: true, - default: '', - }, - format: { - type: String, - }, -}) - -export const FormHookDefinition = { - name: FormHookSchemaName, - schema: FormHookSchema, -} - diff --git a/src/schema/form.schema.ts b/src/schema/form.schema.ts deleted file mode 100644 index 72ecc48..0000000 --- a/src/schema/form.schema.ts +++ /dev/null @@ -1,259 +0,0 @@ -import { Document, Schema } from 'mongoose'; -import { matchType } from '../config/fields'; -import { defaultLanguage, languages } from '../config/languages'; -import { ButtonDocument, ButtonSchema } from './button.schema'; -import { FormFieldDocument, FormFieldSchema } from './form.field.schema'; -import { FormHookDocument, FormHookSchema } from './form.hook.schema' -import { UserDocument, UserSchemaName } from './user.schema'; -import { VisitorDataDocument, VisitorDataSchema } from './visitor.data.schema'; - -export const FormSchemaName = 'Form' - -export interface FormPage { - readonly show: boolean - readonly title?: string - readonly paragraph?: string - readonly buttonText?: string - readonly buttons: [ButtonDocument] -} - -export interface Notifications { - readonly subject?: string - readonly htmlTemplate?: string - readonly enabled: boolean -} - -export interface SelfNotifications extends Notifications{ - readonly fromField?: string - readonly toEmail?: string -} - -export interface RespondentNotifications extends Notifications{ - readonly toField?: string - readonly fromEmail?: string -} - -export interface Colors { - readonly backgroundColor: string - readonly questionColor: string - readonly answerColor: string - readonly buttonColor: string - readonly buttonActiveColor: string - readonly buttonTextColor: string -} - -export interface Design { - readonly colors: Colors - - readonly font?: string -} - -export interface FormDocument extends Document { - readonly title: string - readonly language: string - - readonly analytics: { - readonly gaCode?: string - // TODO extract to separate documents! - readonly visitors: [VisitorDataDocument] - } - - readonly fields: [FormFieldDocument] - readonly hooks: [FormHookDocument] - - readonly admin: UserDocument - - readonly startPage: FormPage; - readonly endPage: FormPage; - - readonly selfNotifications: SelfNotifications; - readonly respondentNotifications: RespondentNotifications; - - readonly showFooter: boolean; - readonly isLive: boolean; - readonly design: Design; - - - readonly created: Date - readonly lastModified: Date -} - -export const FormSchema = new Schema({ - title: { - trim: true, - type: String, - required: true, - }, - created: { - type: Date, - }, - lastModified: { - type: Date, - }, - language: { - type: String, - enum: languages, - default: defaultLanguage, - required: true, - }, - showFooter: { - type: Boolean, - default: true, - }, - isLive: { - type: Boolean, - default: true, - }, - analytics: { - gaCode: { - type: String, - }, - visitors: { - type: [VisitorDataSchema], - }, - }, - form_fields: { - alias: 'fields', - type: [FormFieldSchema], - default: [], - }, - hooks: { - type: [FormHookSchema], - default: [], - }, - admin: { - type: Schema.Types.ObjectId, - ref: UserSchemaName, - }, - startPage: { - showStart: { - alias: 'startPage.show', - type: Boolean, - default: false - }, - introTitle: { - alias: 'startPage.title', - type: String, - default: 'Welcome to Form', - }, - introParagraph: { - alias: 'startPage.paragraph', - type: String, - default: 'Start', - }, - buttons: { - type: [ButtonSchema], - }, - }, - endPage: { - showEnd: { - alias: 'endPage.show', - type: Boolean, - default: false, - }, - title: { - type: String, - default: 'Thank you for filling out the form', - }, - paragraph: { - type: String, - }, - buttonText: { - type: String, - default: 'Go back to Form' - }, - buttons: { - type: [ButtonSchema], - }, - }, - selfNotifications: { - fromField: { - type: String, - }, - toEmails: { - alias: 'selfNotifications.toEmail', - type: String, - }, - subject: { - type: String, - }, - htmlTemplate: { - type: String, - }, - enabled: { - type: Boolean, - default: false - }, - }, - respondentNotifications: { - toField: { - type: String, - }, - fromEmails: { - alias: 'respondentNotifications.fromEmail', - type: String, - match: matchType.email, - }, - subject: { - type: String, - default: 'OhMyForm: Thank you for filling out this OhMyForm', - }, - htmlTemplate: { - type: String, - default: 'Hello,

We’ve received your submission.

Thank you & have a nice day!', - }, - enabled: { - type: Boolean, - default: false, - }, - }, - design: { - colors: { - backgroundColor: { - type: String, - match: matchType.color, - default: '#fff' - }, - questionColor: { - type: String, - match: matchType.color, - default: '#333' - }, - answerColor: { - type: String, - match: matchType.color, - default: '#333' - }, - buttonColor: { - type: String, - match: matchType.color, - default: '#fff' - }, - buttonActiveColor: { - type: String, - match: matchType.color, - default: '#40a9ff' - }, - buttonTextColor: { - type: String, - match: matchType.color, - default: '#666' - }, - }, - - font: { - type: String, - }, - }, -}, { - timestamps: { - createdAt: 'created', - updatedAt: 'lastModified', - } -}) - -export const FormDefinition = { - name: FormSchemaName, - schema: FormSchema, -} - diff --git a/src/schema/index.ts b/src/schema/index.ts deleted file mode 100644 index faedf8e..0000000 --- a/src/schema/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { FormFieldDefinition } from './form.field.schema'; -import { FormHookDefinition } from './form.hook.schema' -import { FormDefinition } from './form.schema'; -import { SubmissionFieldDefinition } from './submission.field.schema'; -import { SubmissionDefinition } from './submission.schema'; -import { UserDefinition } from './user.schema'; - -export const schema = [ - FormDefinition, - FormFieldDefinition, - FormHookDefinition, - SubmissionDefinition, - SubmissionFieldDefinition, - UserDefinition, -] diff --git a/src/schema/submission.field.schema.ts b/src/schema/submission.field.schema.ts deleted file mode 100644 index 990c81b..0000000 --- a/src/schema/submission.field.schema.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Document, Schema } from 'mongoose'; -import { fieldTypes } from '../config/fields'; -import { FormFieldDocument, FormFieldSchemaName } from './form.field.schema'; - -export const SubmissionFieldSchemaName = 'SubmissionField' - -export interface SubmissionFieldDocument extends Document { - readonly field: FormFieldDocument - readonly fieldType: string - readonly fieldValue: any -} - -export const SubmissionFieldSchema = new Schema({ - field: { - type: Schema.Types.ObjectId, - ref: FormFieldSchemaName - }, - fieldType: { - type: String, - enum: fieldTypes, - }, - fieldValue: { - type: Schema.Types.Mixed, - default: '', - }, -}) - -export const SubmissionFieldDefinition = { - name: SubmissionFieldSchemaName, - schema: SubmissionFieldSchema, -} - diff --git a/src/schema/submission.schema.ts b/src/schema/submission.schema.ts deleted file mode 100644 index 89f3ce4..0000000 --- a/src/schema/submission.schema.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Document, Schema } from 'mongoose'; -import { FormDocument, FormSchemaName } from './form.schema'; -import { SubmissionFieldDocument, SubmissionFieldSchema } from './submission.field.schema'; -import { UserDocument, UserSchemaName } from './user.schema'; - -export const SubmissionSchemaName = 'Submission' - -export interface GeoLocation { - readonly country?: string - readonly city?: string -} - -export interface Device { - readonly type?: string - readonly name?: string -} - -export interface SubmissionDocument extends Document { - readonly fields: SubmissionFieldDocument[] - readonly form: FormDocument - readonly ipAddr: string - readonly tokenHash: string - readonly geoLocation: GeoLocation - readonly device: Device - readonly timeElapsed: number - readonly percentageComplete: number - - readonly user?: UserDocument - readonly created: Date - readonly lastModified: Date -} - -export const SubmissionSchema = new Schema({ - fields: { - type: [SubmissionFieldSchema], - default: [], - }, - form: { - type: Schema.Types.ObjectId, - ref: FormSchemaName, - required: true - }, - user: { - type: Schema.Types.ObjectId, - ref: UserSchemaName, - }, - ipAddr: { - type: String - }, - tokenHash: { - type: String - }, - geoLocation: { - country: { - type: String - }, - city: { - type: String - } - }, - device: { - type: { - type: String - }, - name: { - type: String - } - }, - timeElapsed: { - type: Number, - default: 0, - }, - percentageComplete: { - type: Number, - default: 0, - }, -}, { - timestamps: { - createdAt: 'created', - updatedAt: 'lastModified', - } -}) - -export const SubmissionDefinition = { - name: SubmissionSchemaName, - schema: SubmissionSchema, -} - diff --git a/src/schema/user.schema.ts b/src/schema/user.schema.ts deleted file mode 100644 index 66d3edc..0000000 --- a/src/schema/user.schema.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { Document, Schema } from 'mongoose'; -import { defaultLanguage, languages } from '../config/languages'; -import { roles, rolesType } from '../config/roles'; - -export const UserSchemaName = 'User' - -export interface UserDocument extends Document { - readonly firstName?: string - readonly lastName?: string - readonly email: string - readonly username: string - readonly passwordHash: string - readonly salt: string - readonly provider: string - readonly roles: rolesType - readonly language: string - readonly resetPasswordToken?: string - readonly resetPasswordExpires?: Date - readonly token?: string - readonly apiKey?: string - readonly created: Date - readonly lastModified: Date -} - -export const UserSchema = new Schema({ - firstName: { - type: String, - trim: true, - default: '', - }, - lastName: { - type: String, - trim: true, - default: '', - }, - email: { - type: String, - trim: true, - lowercase: true, - unique: true, - match: /^(([^<>()\[\]\\.,;:\s@']+(\.[^<>()\[\]\\.,;:\s@']+)*)|('.+'))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, - required: true, - }, - username: { - type: String, - unique: true, - lowercase: true, - match: /^[a-zA-Z0-9\-]+$/, - required: true, - }, - passwordHash: { - type: String, - default: '', - }, - salt: { - type: String, - }, - provider: { - type: String, - default: 'local' - }, - roles: { - type: [{ - type: String, - enum: roles, - }], - default: ['user'], - }, - language: { - type: String, - enum: languages, - default: defaultLanguage, - }, - resetPasswordToken: { - type: String, - }, - resetPasswordExpires: { - type: Date, - }, - token: { - type: String, - }, - apiKey: { - type: String, - unique: true, - index: true, - sparse: true - }, -}, { - timestamps: { - createdAt: 'created', - updatedAt: 'lastModified', - } -}) - -export const UserDefinition = { - name: UserSchemaName, - schema: UserSchema, -} diff --git a/src/schema/visitor.data.schema.ts b/src/schema/visitor.data.schema.ts deleted file mode 100644 index cf654eb..0000000 --- a/src/schema/visitor.data.schema.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Document, Schema } from 'mongoose'; -import { defaultLanguage, languages } from '../config/languages'; -import { FormFieldDocument, FormFieldSchemaName } from './form.field.schema'; - -export interface VisitorDataDocument extends Document { - readonly introParagraph?: string - readonly referrer?: string - readonly filledOutFields: [FormFieldDocument] - readonly timeElapsed: number - readonly isSubmitted: boolean - readonly language: string - readonly ipAddr: string - readonly deviceType: string - readonly userAgent: string -} - -export const VisitorDataSchema = new Schema({ - introParagraph: { - type: String, - }, - referrer: { - type: String, - }, - filledOutFields: { - type: [{ - type: Schema.Types.ObjectId, - ref: FormFieldSchemaName, - }], - }, - timeElapsed: { - type: Number, - }, - isSubmitted: { - type: Boolean, - }, - language: { - type: String, - enum: languages, - default: defaultLanguage, - }, - ipAddr: { - type: String, - }, - deviceType: { - type: String, - enum: ['desktop', 'phone', 'tablet', 'other'], - default: 'other', - }, - userAgent: { - type: String, - }, -}) diff --git a/src/service/auth/auth.service.ts b/src/service/auth/auth.service.ts index 1c3a2d2..127ccba 100644 --- a/src/service/auth/auth.service.ts +++ b/src/service/auth/auth.service.ts @@ -1,10 +1,10 @@ -import { Injectable } from '@nestjs/common'; -import { JwtService } from '@nestjs/jwt'; -import { PinoLogger } from 'nestjs-pino/dist'; -import { AuthJwtModel } from '../../dto/auth/auth.jwt.model'; -import { UserDocument } from '../../schema/user.schema'; -import { UserService } from '../user/user.service'; -import { PasswordService } from './password.service'; +import { Injectable } from '@nestjs/common' +import { JwtService } from '@nestjs/jwt' +import { PinoLogger } from 'nestjs-pino/dist' +import { AuthJwtModel } from '../../dto/auth/auth.jwt.model' +import { UserEntity } from '../../entity/user.entity' +import { UserService } from '../user/user.service' +import { PasswordService } from './password.service' @Injectable() export class AuthService { @@ -15,7 +15,7 @@ export class AuthService { private logger: PinoLogger, ) {} - async validateUser(username: string, password: string): Promise { + async validateUser(username: string, password: string): Promise { // TODO only allow login for verified users! try { @@ -30,7 +30,7 @@ export class AuthService { return null; } - async login(user: UserDocument): Promise { + async login(user: UserEntity): Promise { return new AuthJwtModel({ accessToken: this.jwtService.sign({ username: user.username, diff --git a/src/service/auth/index.ts b/src/service/auth/index.ts index 00b8d57..840bbfc 100644 --- a/src/service/auth/index.ts +++ b/src/service/auth/index.ts @@ -1,7 +1,7 @@ -import { AuthService } from './auth.service'; -import { JwtStrategy } from './jwt.strategy'; -import { LocalStrategy } from './local.strategy'; -import { PasswordService } from './password.service'; +import { AuthService } from './auth.service' +import { JwtStrategy } from './jwt.strategy' +import { LocalStrategy } from './local.strategy' +import { PasswordService } from './password.service' export const authServices = [ AuthService, diff --git a/src/service/auth/jwt.strategy.ts b/src/service/auth/jwt.strategy.ts index e939984..88593e3 100644 --- a/src/service/auth/jwt.strategy.ts +++ b/src/service/auth/jwt.strategy.ts @@ -1,9 +1,9 @@ -import { Injectable } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import { PassportStrategy } from '@nestjs/passport'; -import { ExtractJwt, Strategy } from 'passport-jwt'; -import { UserDocument } from '../../schema/user.schema'; -import { UserService } from '../user/user.service'; +import { Injectable } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' +import { PassportStrategy } from '@nestjs/passport' +import { ExtractJwt, Strategy } from 'passport-jwt' +import { UserEntity } from '../../entity/user.entity' +import { UserService } from '../user/user.service' @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { @@ -18,7 +18,7 @@ export class JwtStrategy extends PassportStrategy(Strategy) { }); } - async validate(payload: any): Promise { + async validate(payload: any): Promise { try { return await this.userService.findById(payload.sub) } catch (e) { diff --git a/src/service/auth/local.strategy.ts b/src/service/auth/local.strategy.ts index 135d8da..cd8cfbe 100644 --- a/src/service/auth/local.strategy.ts +++ b/src/service/auth/local.strategy.ts @@ -1,7 +1,7 @@ -import { Injectable, UnauthorizedException } from '@nestjs/common'; -import { PassportStrategy } from '@nestjs/passport'; -import { Strategy } from 'passport-local'; -import { AuthService } from './auth.service'; +import { Injectable, UnauthorizedException } from '@nestjs/common' +import { PassportStrategy } from '@nestjs/passport' +import { Strategy } from 'passport-local' +import { AuthService } from './auth.service' @Injectable() export class LocalStrategy extends PassportStrategy(Strategy) { diff --git a/src/service/auth/password.service.ts b/src/service/auth/password.service.ts index fbd3d55..9d61101 100644 --- a/src/service/auth/password.service.ts +++ b/src/service/auth/password.service.ts @@ -1,6 +1,6 @@ -import { Injectable } from '@nestjs/common'; -import * as bcrypt from 'bcrypt'; -import * as crypto from 'crypto'; +import { Injectable } from '@nestjs/common' +import * as bcrypt from 'bcrypt' +import * as crypto from 'crypto' @Injectable() export class PasswordService { diff --git a/src/service/form/form.create.service.ts b/src/service/form/form.create.service.ts index 9fb08c4..db742ae 100644 --- a/src/service/form/form.create.service.ts +++ b/src/service/form/form.create.service.ts @@ -1,22 +1,29 @@ -import { Injectable } from '@nestjs/common'; -import { InjectModel } from '@nestjs/mongoose'; -import { Model } from 'mongoose'; -import { FormCreateInput } from '../../dto/form/form.create.input'; -import { FormDocument, FormSchemaName } from '../../schema/form.schema'; -import { UserDocument } from '../../schema/user.schema'; +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { FormCreateInput } from '../../dto/form/form.create.input' +import { FormEntity } from '../../entity/form.entity' +import { UserEntity } from '../../entity/user.entity' @Injectable() export class FormCreateService { constructor( - @InjectModel(FormSchemaName) private readonly formModel: Model, + @InjectRepository(FormEntity) + private readonly formRepository: Repository ) { } - async create(admin: UserDocument, input: FormCreateInput): Promise { - return await this.formModel.create({ - admin, - ...input, - }) + async create(admin: UserEntity, input: FormCreateInput): Promise { + const form = new FormEntity() + + form.title = input.title + form.isLive = input.isLive + form.showFooter = input.showFooter + form.language = input.language + + form.admin = admin + + return await this.formRepository.save(form) } } diff --git a/src/service/form/form.delete.service.ts b/src/service/form/form.delete.service.ts index 83b2dd4..2c17acb 100644 --- a/src/service/form/form.delete.service.ts +++ b/src/service/form/form.delete.service.ts @@ -1,21 +1,26 @@ -import { Injectable } from '@nestjs/common'; -import { InjectModel } from '@nestjs/mongoose'; -import { Model } from 'mongoose'; -import { FormDocument, FormSchemaName } from '../../schema/form.schema'; -import { SubmissionDocument, SubmissionSchemaName } from '../../schema/submission.schema'; +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { FormEntity } from '../../entity/form.entity' +import { SubmissionEntity } from '../../entity/submission.entity' @Injectable() export class FormDeleteService { constructor( - @InjectModel(FormSchemaName) private formModel: Model, - @InjectModel(SubmissionSchemaName) private readonly submissionModel: Model, + @InjectRepository(FormEntity) + private readonly formRepository: Repository, + @InjectRepository(SubmissionEntity) + private readonly submissionRepository: Repository, ) { } async delete(id: string): Promise { - const form = await this.formModel.findByIdAndDelete(id).exec() - await this.submissionModel.deleteMany({ - form - }).exec() + await this.submissionRepository.createQueryBuilder('s') + .delete() + .where('s.form = :form', { form: id }) + + await this.formRepository.createQueryBuilder('f') + .delete() + .where('f.id = :form', { form: id }) } } diff --git a/src/service/form/form.service.ts b/src/service/form/form.service.ts index b1e4f1e..28d9e58 100644 --- a/src/service/form/form.service.ts +++ b/src/service/form/form.service.ts @@ -1,46 +1,42 @@ -import { Injectable } from '@nestjs/common'; -import { InjectModel } from '@nestjs/mongoose'; -import { FilterQuery, Model, Types } from 'mongoose'; -import { FormDocument, FormSchemaName } from '../../schema/form.schema'; -import { UserDocument } from '../../schema/user.schema'; +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { FormEntity } from '../../entity/form.entity' +import { UserEntity } from '../../entity/user.entity' @Injectable() export class FormService { constructor( - @InjectModel(FormSchemaName) private formModel: Model, + @InjectRepository(FormEntity) + private readonly formRepository: Repository, ) { } - async isAdmin(form: FormDocument, user: UserDocument): Promise { + async isAdmin(form: FormEntity, user: UserEntity): Promise { if (user.roles.includes('superuser')) { return true } - return Types.ObjectId(form.admin.id).equals(Types.ObjectId(user.id)) + return form.admin.id === user.id } - async find(start: number, limit: number, sort: any = {}, user?: UserDocument): Promise<[FormDocument[], number]> { - let conditions: FilterQuery + async find(start: number, limit: number, sort: any = {}, user?: UserEntity): Promise<[FormEntity[], number]> { + const qb = this.formRepository.createQueryBuilder('f') if (user) { - conditions = { - admin: user - } + qb.where('f.admin = :user', { user: user.id }) } - return [ - await this.formModel - .find(conditions) - .sort(sort) - .skip(start) - .limit(limit), - await this.formModel - .countDocuments(conditions) - ] + // TODO readd sort + + qb.skip(start) + qb.take(limit) + + return await qb.getManyAndCount() } - async findById(id: string): Promise { - const form = await this.formModel.findById(id); + async findById(id: string): Promise { + const form = await this.formRepository.findOne(id); if (!form) { throw new Error('no form found') diff --git a/src/service/form/form.statistic.service.ts b/src/service/form/form.statistic.service.ts index f7020fe..278df26 100644 --- a/src/service/form/form.statistic.service.ts +++ b/src/service/form/form.statistic.service.ts @@ -1,14 +1,15 @@ -import { InjectModel } from '@nestjs/mongoose'; -import { Model } from 'mongoose'; -import { FormDocument, FormSchemaName } from '../../schema/form.schema'; +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { FormEntity } from '../../entity/form.entity' export class FormStatisticService { constructor( - @InjectModel(FormSchemaName) private formModel: Model, + @InjectRepository(FormEntity) + private readonly formRepository: Repository ) { } async getTotal(): Promise { - return await this.formModel.estimatedDocumentCount(); + return await this.formRepository.count(); } } diff --git a/src/service/form/form.update.service.ts b/src/service/form/form.update.service.ts index 1682d1b..cf86ad2 100644 --- a/src/service/form/form.update.service.ts +++ b/src/service/form/form.update.service.ts @@ -1,97 +1,100 @@ -import { Injectable } from '@nestjs/common'; -import { InjectModel } from '@nestjs/mongoose'; -import { Model } from 'mongoose'; -import { FormUpdateInput } from '../../dto/form/form.update.input'; -import { FormFieldDocument, FormFieldSchemaName } from '../../schema/form.field.schema'; -import { FormHookDocument, FormHookSchemaName } from '../../schema/form.hook.schema' -import { FormDocument, FormSchemaName } from '../../schema/form.schema'; +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { FormUpdateInput } from '../../dto/form/form.update.input' +import { FormEntity } from '../../entity/form.entity' +import { FormFieldEntity } from '../../entity/form.field.entity' +import { FormHookEntity } from '../../entity/form.hook.entity' @Injectable() export class FormUpdateService { constructor( - @InjectModel(FormSchemaName) private readonly formModel: Model, - @InjectModel(FormFieldSchemaName) private readonly formFieldModel: Model, - @InjectModel(FormHookSchemaName) private readonly formHookModel: Model, + @InjectRepository(FormEntity) + private readonly formRepository: Repository, + @InjectRepository(FormFieldEntity) + private readonly formFieldRepository: Repository, + @InjectRepository(FormHookEntity) + private readonly formHookRepository: Repository, ) { } - async update(form: FormDocument, input: FormUpdateInput): Promise { + async update(form: FormEntity, input: FormUpdateInput): Promise { if (input.language !== undefined) { - form.set('language', input.language) + form.language = input.language } if (input.title !== undefined) { - form.set('title', input.title) + form.title = input.title } if (input.showFooter !== undefined) { - form.set('showFooter', input.showFooter) + form.showFooter = input.showFooter } if (input.isLive !== undefined) { - form.set('isLive', input.isLive) + form.isLive = input.isLive } const fieldMapping = {} if (input.fields !== undefined) { - const nextFields = await Promise.all(input.fields.map(async (nextField) => { + form.fields = await Promise.all(input.fields.map(async (nextField) => { let field = form.fields.find(field => field.id.toString() === nextField.id) if (!field) { - field = new this.formFieldModel({ - type: nextField.type, - }) + field = new FormFieldEntity() + field.type = nextField.type } // ability for other fields to apply mapping fieldMapping[nextField.id] = field.id.toString() - field.set('title', nextField.title) - field.set('description', nextField.description) - field.set('required', nextField.required) - field.set('value', nextField.value) + field.title = nextField.title + field.description = nextField.description + field.required = nextField.required + field.value = nextField.value if (nextField.slug !== undefined) { - field.set('slug', nextField.slug) + field.slug = nextField.slug } - if (nextField.logicJump !== undefined) { - field.set('logicJump', nextField.logicJump) + if (nextField.logic !== undefined) { + // TODO prepare logic entries + // field.logicJump = nextField.logicJump } if (nextField.options !== undefined) { - field.set('options', nextField.options) + // TODO prepare options + // field.options = nextField.options } if (nextField.rating !== undefined) { - field.set('rating', nextField.rating) + field.rating = nextField.rating } return field })) - form.set('fields', nextFields) } if (input.hooks !== undefined) { - const nextHooks = input.hooks.map((nextHook) => { + form.hooks = input.hooks.map((nextHook) => { let hook = form.hooks && form.hooks.find(hook => hook.id.toString() === nextHook.id) if (!hook) { - hook = new this.formHookModel({}) + hook = new FormHookEntity() } // ability for other fields to apply mapping - hook.set('url', nextHook.url) + hook.url = nextHook.url + hook.enabled = nextHook.enabled if (nextHook.format !== undefined) { - hook.set('format', nextHook.format) + hook.format = nextHook.format } return hook }) - form.set('hooks', nextHooks) } const extractField = (id) => { @@ -103,9 +106,33 @@ export class FormUpdateService { } if (input.design !== undefined) { - form.set('design', input.design) + if (input.design.font !== undefined) { + form.design.font = input.design.font + } + + if (input.design.colors !== undefined) { + if (input.design.colors.answer !== undefined) { + form.design.colors.answer = input.design.colors.answer + } + if (input.design.colors.buttonText !== undefined) { + form.design.colors.buttonText = input.design.colors.buttonText + } + if (input.design.colors.background !== undefined) { + form.design.colors.background = input.design.colors.background + } + if (input.design.colors.button !== undefined) { + form.design.colors.button = input.design.colors.button + } + if (input.design.colors.buttonActive !== undefined) { + form.design.colors.buttonActive = input.design.colors.buttonActive + } + if (input.design.colors.question !== undefined) { + form.design.colors.question = input.design.colors.question + } + } } + /* if (input.selfNotifications !== undefined) { form.set('selfNotifications', { ...input.selfNotifications, @@ -119,16 +146,19 @@ export class FormUpdateService { toField: extractField(input.respondentNotifications.toField) }) } + */ if (input.startPage !== undefined) { - form.set('startPage', input.startPage) + // TODO fix start page + // form.set('startPage', input.startPage) } if (input.endPage !== undefined) { - form.set('endPage', input.endPage) + // TODO fix end page + // form.set('endPage', input.endPage) } - await form.save() + await this.formRepository.save(form) return form } diff --git a/src/service/form/index.ts b/src/service/form/index.ts index 6e30391..bbbe668 100644 --- a/src/service/form/index.ts +++ b/src/service/form/index.ts @@ -1,8 +1,8 @@ -import { FormCreateService } from './form.create.service'; -import { FormDeleteService } from './form.delete.service'; -import { FormService } from './form.service'; -import { FormStatisticService } from './form.statistic.service'; -import { FormUpdateService } from './form.update.service'; +import { FormCreateService } from './form.create.service' +import { FormDeleteService } from './form.delete.service' +import { FormService } from './form.service' +import { FormStatisticService } from './form.statistic.service' +import { FormUpdateService } from './form.update.service' export const formServices = [ FormCreateService, diff --git a/src/service/index.ts b/src/service/index.ts index cfe0694..0f23912 100644 --- a/src/service/index.ts +++ b/src/service/index.ts @@ -1,16 +1,16 @@ -import { ConfigService } from '@nestjs/config'; -import { RedisPubSub } from 'graphql-redis-subscriptions'; -import { PubSub, PubSubEngine } from 'graphql-subscriptions'; -import Redis from 'ioredis'; -import { PinoLogger } from 'nestjs-pino/dist'; -import { authServices } from './auth'; -import { formServices } from './form'; -import { InstallationMetricsService } from './installation.metrics.service'; -import { MailService } from './mail.service'; -import { profileServices } from './profile'; -import {SettingService} from './setting.service' -import { submissionServices } from './submission'; -import { userServices } from './user'; +import { ConfigService } from '@nestjs/config' +import { RedisPubSub } from 'graphql-redis-subscriptions' +import { PubSub, PubSubEngine } from 'graphql-subscriptions' +import Redis from 'ioredis' +import { PinoLogger } from 'nestjs-pino/dist' +import { authServices } from './auth' +import { formServices } from './form' +import { InstallationMetricsService } from './installation.metrics.service' +import { MailService } from './mail.service' +import { profileServices } from './profile' +import { SettingService } from './setting.service' +import { submissionServices } from './submission' +import { userServices } from './user' export const services = [ ...userServices, diff --git a/src/service/installation.metrics.service.ts b/src/service/installation.metrics.service.ts index 8a5aaa5..02cb9bb 100644 --- a/src/service/installation.metrics.service.ts +++ b/src/service/installation.metrics.service.ts @@ -1,7 +1,7 @@ -import { Injectable, OnApplicationBootstrap } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import MatomoTracker from 'matomo-tracker'; -import { PinoLogger } from 'nestjs-pino/dist'; +import { Injectable, OnApplicationBootstrap } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' +import MatomoTracker from 'matomo-tracker' +import { PinoLogger } from 'nestjs-pino/dist' @Injectable() export class InstallationMetricsService implements OnApplicationBootstrap { diff --git a/src/service/mail.service.ts b/src/service/mail.service.ts index 871b0c3..a086c3c 100644 --- a/src/service/mail.service.ts +++ b/src/service/mail.service.ts @@ -1,13 +1,13 @@ -import { MailerService } from '@nestjs-modules/mailer'; -import { Injectable } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import fs from 'fs'; -import handlebars from 'handlebars'; -import htmlToText from 'html-to-text'; -import mjml2html from 'mjml'; -import { PinoLogger } from 'nestjs-pino/dist'; -import { join } from 'path'; -import { defaultLanguage } from '../config/languages'; +import { MailerService } from '@nestjs-modules/mailer' +import { Injectable } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' +import fs from 'fs' +import handlebars from 'handlebars' +import htmlToText from 'html-to-text' +import mjml2html from 'mjml' +import { PinoLogger } from 'nestjs-pino/dist' +import { join } from 'path' +import { defaultLanguage } from '../config/languages' @Injectable() export class MailService { diff --git a/src/service/profile/index.ts b/src/service/profile/index.ts index fb9089a..40840d7 100644 --- a/src/service/profile/index.ts +++ b/src/service/profile/index.ts @@ -1,4 +1,4 @@ -import { ProfileUpdateService } from './profile.update.service'; +import { ProfileUpdateService } from './profile.update.service' export const profileServices = [ ProfileUpdateService, diff --git a/src/service/profile/profile.update.service.ts b/src/service/profile/profile.update.service.ts index 60673e1..bd573a3 100644 --- a/src/service/profile/profile.update.service.ts +++ b/src/service/profile/profile.update.service.ts @@ -1,38 +1,53 @@ -import { Injectable } from '@nestjs/common'; -import { ProfileUpdateInput } from '../../dto/profile/profile.update.input'; -import { UserDocument } from '../../schema/user.schema'; +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { ProfileUpdateInput } from '../../dto/profile/profile.update.input' +import { UserEntity } from '../../entity/user.entity' +import { PasswordService } from '../auth/password.service' @Injectable() export class ProfileUpdateService { - async update(user: UserDocument, input: ProfileUpdateInput): Promise { + constructor( + @InjectRepository(UserEntity) + private readonly userRepository: Repository, + private readonly passwordService: PasswordService, + ) { + } + + async update(user: UserEntity, input: ProfileUpdateInput): Promise { if (input.firstName !== undefined) { - user.set('firstName', input.firstName) + user.firstName = input.firstName } if (input.lastName !== undefined) { - user.set('lastName', input.lastName) + user.lastName = input.lastName } - if (input.email !== undefined) { - user.set('email', input.email) + if (input.email !== undefined && user.email !== input.email) { + user.email = input.email // TODO request email verification + + if (undefined !== await this.userRepository.findOne({ email: input.email })) { + throw new Error('email already in use') + } } - if (input.username !== undefined) { - user.set('username', input.username) + if (input.username !== undefined && user.username !== input.username) { + user.username = input.username + + if (undefined !== await this.userRepository.findOne({ username: input.username })) { + throw new Error('username already in use') + } } if (input.language !== undefined) { - user.set('language', input.language) + user.language = input.language } if (input.password !== undefined) { - // user.set('language', input.language) - // TODO password handling + user.passwordHash = await this.passwordService.hash(input.password) } - await user.save() - - return user + return await this.userRepository.save(user) } } diff --git a/src/service/setting.service.ts b/src/service/setting.service.ts index 2ddb63a..887861f 100644 --- a/src/service/setting.service.ts +++ b/src/service/setting.service.ts @@ -1,6 +1,6 @@ -import {Injectable} from '@nestjs/common' -import {ConfigService} from '@nestjs/config' -import {SettingModel} from '../dto/setting/setting.model' +import { Injectable } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' +import { SettingModel } from '../dto/setting/setting.model' @Injectable() export class SettingService { diff --git a/src/service/submission/index.ts b/src/service/submission/index.ts index 969a734..75e7668 100644 --- a/src/service/submission/index.ts +++ b/src/service/submission/index.ts @@ -1,9 +1,9 @@ -import { SubmissionService } from './submission.service'; -import { SubmissionSetFieldService } from './submission.set.field.service'; -import { SubmissionStartService } from './submission.start.service'; -import { SubmissionStatisticService } from './submission.statistic.service'; -import { SubmissionTokenService } from './submission.token.service'; import { SubmissionHookService } from './submission.hook.service' +import { SubmissionService } from './submission.service' +import { SubmissionSetFieldService } from './submission.set.field.service' +import { SubmissionStartService } from './submission.start.service' +import { SubmissionStatisticService } from './submission.statistic.service' +import { SubmissionTokenService } from './submission.token.service' export const submissionServices = [ SubmissionService, diff --git a/src/service/submission/submission.hook.service.ts b/src/service/submission/submission.hook.service.ts index 371af3d..2ba5cb5 100644 --- a/src/service/submission/submission.hook.service.ts +++ b/src/service/submission/submission.hook.service.ts @@ -1,9 +1,7 @@ import { HttpService, Injectable } from '@nestjs/common' -import fs from "fs" -import { PinoLogger } from 'nestjs-pino/dist' -import { FormDocument } from '../../schema/form.schema' import handlebars from 'handlebars' -import { SubmissionDocument } from '../../schema/submission.schema' +import { PinoLogger } from 'nestjs-pino/dist' +import { SubmissionEntity } from '../../entity/submission.entity' @Injectable() export class SubmissionHookService { @@ -13,12 +11,7 @@ export class SubmissionHookService { ) { } - public async process(submission: SubmissionDocument): Promise { - if (!submission.populated('form')) { - submission.populate('form') - await submission.execPopulate() - } - + public async process(submission: SubmissionEntity): Promise { await Promise.all(submission.form.hooks.map(async (hook) => { if (!hook.enabled) { return @@ -39,7 +32,7 @@ export class SubmissionHookService { })) } - private async format(submission: SubmissionDocument, format?: string): Promise { + private async format(submission: SubmissionEntity, format?: string): Promise { const fields = {} submission.form.fields.forEach((field) => { fields[field.id] = field @@ -51,15 +44,10 @@ export class SubmissionHookService { created: submission.created, lastModified: submission.lastModified, fields: submission.fields.map((submissionField) => { - const formField = submission.form.fields.find(formField => formField.id.toString() === submissionField.field) || { - id: submissionField.field, - slug: null - } - return { - field: formField.id, - slug: formField.slug || null, - ...submissionField.fieldValue + field: submissionField.field.id, + slug: submissionField.field.slug || null, + value: submissionField.field.value } }) } diff --git a/src/service/submission/submission.service.ts b/src/service/submission/submission.service.ts index 307186d..e4ea96d 100644 --- a/src/service/submission/submission.service.ts +++ b/src/service/submission/submission.service.ts @@ -1,38 +1,36 @@ -import { InjectModel } from '@nestjs/mongoose'; -import { FilterQuery, Model } from 'mongoose'; -import { FormDocument } from '../../schema/form.schema'; -import { SubmissionDocument, SubmissionSchemaName } from '../../schema/submission.schema'; -import { SubmissionTokenService } from './submission.token.service'; +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { FormEntity } from '../../entity/form.entity' +import { SubmissionEntity } from '../../entity/submission.entity' +import { SubmissionTokenService } from './submission.token.service' export class SubmissionService { constructor( - @InjectModel(SubmissionSchemaName) private readonly submissionModel: Model, + @InjectRepository(SubmissionEntity) + private readonly submissionRepository: Repository, private readonly tokenService: SubmissionTokenService ) { } - async isOwner(submission: SubmissionDocument, token: string): Promise { + async isOwner(submission: SubmissionEntity, token: string): Promise { return await this.tokenService.verify(token, submission.tokenHash) } - async find(form: FormDocument, start: number, limit: number, sort: any = {}): Promise<[SubmissionDocument[], number]> { - const conditions: FilterQuery = { - form - } + async find(form: FormEntity, start: number, limit: number, sort: any = {}): Promise<[SubmissionEntity[], number]> { + const qb = this.submissionRepository.createQueryBuilder('s') - return [ - await this.submissionModel - .find(conditions) - .sort(sort) - .skip(start) - .limit(limit), - await this.submissionModel - .countDocuments(conditions) - ] + qb.where('s.form = :form', { form: form.id }) + + // TODO readd sort + + qb.skip(start) + qb.take(limit) + + return await qb.getManyAndCount() } - async findById(id: string): Promise { - const submission = await this.submissionModel.findById(id); + async findById(id: string): Promise { + const submission = await this.submissionRepository.findOne(id); if (!submission) { throw new Error('no form found') diff --git a/src/service/submission/submission.set.field.service.ts b/src/service/submission/submission.set.field.service.ts index 443353b..89c5ef9 100644 --- a/src/service/submission/submission.set.field.service.ts +++ b/src/service/submission/submission.set.field.service.ts @@ -1,54 +1,50 @@ -import { Injectable } from '@nestjs/common'; -import { InjectModel } from '@nestjs/mongoose'; -import dayjs from 'dayjs'; -import { Model } from 'mongoose'; +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import dayjs from 'dayjs' import { PinoLogger } from 'nestjs-pino/dist' -import { SubmissionSetFieldInput } from '../../dto/submission/submission.set.field.input'; -import { SubmissionFieldDocument, SubmissionFieldSchemaName } from '../../schema/submission.field.schema'; -import { SubmissionDocument, SubmissionSchemaName } from '../../schema/submission.schema'; +import { Repository } from 'typeorm' +import { SubmissionSetFieldInput } from '../../dto/submission/submission.set.field.input' +import { SubmissionEntity } from '../../entity/submission.entity' +import { SubmissionFieldEntity } from '../../entity/submission.field.entity' import { SubmissionHookService } from './submission.hook.service' @Injectable() export class SubmissionSetFieldService { constructor( - @InjectModel(SubmissionSchemaName) private readonly submissionModel: Model, - @InjectModel(SubmissionFieldSchemaName) private readonly submissionFieldModel: Model, + @InjectRepository(SubmissionEntity) + private readonly submissionRepository: Repository, + @InjectRepository(SubmissionFieldEntity) + private readonly submissionFieldRepository: Repository, private readonly webHook: SubmissionHookService, private readonly logger: PinoLogger, ) { } - async saveField(submission: SubmissionDocument, input: SubmissionSetFieldInput) { - const existing = submission.fields.find(field => field.field.toString() === input.field) + async saveField(submission: SubmissionEntity, input: SubmissionSetFieldInput): Promise { + let field = submission.fields.find(field => field.field.id.toString() === input.field) - const data = JSON.parse(input.data) + if (field) { + field.fieldValue = input.data - if (existing) { - existing.set('fieldValue', data) + await this.submissionFieldRepository.save(field) } else { - if (!submission.populated('form')) { - submission.populate('form') - await submission.execPopulate() - } + field = new SubmissionFieldEntity() - const field = submission.form.fields.find(field => field.id.toString() === input.field) + field.submission = submission + field.field = submission.form.fields.find(field => field.id.toString() === input.field) + field.fieldType = field.field.type + field.fieldValue = input.data - const newField = new this.submissionFieldModel({ - field, - fieldType: field.type, - fieldValue: data - }) + field = await this.submissionFieldRepository.save(field) - submission.set('percentageComplete', (1 + submission.fields.length) / submission.form.fields.length) - submission.set('timeElapsed', dayjs().diff(dayjs(submission.created), 'second')) + submission.fields.push(field) - submission.set('fields', [ - ...submission.fields, - newField, - ]) + submission.percentageComplete = (submission.fields.length) / submission.form.fields.length } - await submission.save() + submission.timeElapsed = dayjs().diff(dayjs(submission.created), 'second') + + await this.submissionRepository.save(submission) if (submission.percentageComplete === 1) { this.webHook.process(submission).catch(e => { diff --git a/src/service/submission/submission.start.service.ts b/src/service/submission/submission.start.service.ts index 11361c3..149c28d 100644 --- a/src/service/submission/submission.start.service.ts +++ b/src/service/submission/submission.start.service.ts @@ -1,35 +1,37 @@ -import { Injectable } from '@nestjs/common'; -import { InjectModel } from '@nestjs/mongoose'; -import { Model } from 'mongoose'; -import { SubmissionStartInput } from '../../dto/submission/submission.start.input'; -import { FormDocument } from '../../schema/form.schema'; -import { SubmissionDocument, SubmissionSchemaName } from '../../schema/submission.schema'; -import { UserDocument } from '../../schema/user.schema'; -import { SubmissionTokenService } from './submission.token.service'; +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { SubmissionStartInput } from '../../dto/submission/submission.start.input' +import { FormEntity } from '../../entity/form.entity' +import { SubmissionEntity } from '../../entity/submission.entity' +import { UserEntity } from '../../entity/user.entity' +import { SubmissionTokenService } from './submission.token.service' @Injectable() export class SubmissionStartService { constructor( - @InjectModel(SubmissionSchemaName) private submissionModel: Model, + @InjectRepository(SubmissionEntity) + private readonly submissionRepository: Repository, private readonly tokenService: SubmissionTokenService ) { } async start( - form: FormDocument, + form: FormEntity, input: SubmissionStartInput, - user?: UserDocument, - ): Promise { - const data: any = { - form, - device: input.device, - tokenHash: await this.tokenService.hash(input.token) - } + user?: UserEntity, + ): Promise { + const submission = new SubmissionEntity() - if (user) { - data.user = user - } + submission.form = form + submission.user = user - return await this.submissionModel.create(data) + submission.device.language = input.device.language + submission.device.name = input.device.name + submission.device.type = input.device.type + + submission.tokenHash = await this.tokenService.hash(input.token) + + return await this.submissionRepository.save(submission) } } diff --git a/src/service/submission/submission.statistic.service.ts b/src/service/submission/submission.statistic.service.ts index e3f70af..4388d63 100644 --- a/src/service/submission/submission.statistic.service.ts +++ b/src/service/submission/submission.statistic.service.ts @@ -1,14 +1,15 @@ -import { InjectModel } from '@nestjs/mongoose'; -import { Model } from 'mongoose'; -import { SubmissionDocument, SubmissionSchemaName } from '../../schema/submission.schema'; +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { SubmissionEntity } from '../../entity/submission.entity' export class SubmissionStatisticService { constructor( - @InjectModel(SubmissionSchemaName) private readonly submissionModel: Model, + @InjectRepository(SubmissionEntity) + private readonly submissionRepository: Repository, ) { } async getTotal(): Promise { - return await this.submissionModel.estimatedDocumentCount(); + return await this.submissionRepository.count(); } } diff --git a/src/service/submission/submission.token.service.ts b/src/service/submission/submission.token.service.ts index 871b4ae..4a7687c 100644 --- a/src/service/submission/submission.token.service.ts +++ b/src/service/submission/submission.token.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common' @Injectable() export class SubmissionTokenService { diff --git a/src/service/user/boot.service.ts b/src/service/user/boot.service.ts index bd9bc59..11a5fc6 100644 --- a/src/service/user/boot.service.ts +++ b/src/service/user/boot.service.ts @@ -1,8 +1,8 @@ -import { Injectable, OnApplicationBootstrap } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import { PinoLogger } from 'nestjs-pino/dist'; -import { UserCreateService } from './user.create.service'; -import { UserService } from './user.service'; +import { Injectable, OnApplicationBootstrap } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' +import { PinoLogger } from 'nestjs-pino/dist' +import { UserCreateService } from './user.create.service' +import { UserService } from './user.service' @Injectable() export class BootService implements OnApplicationBootstrap { @@ -41,17 +41,17 @@ export class BootService implements OnApplicationBootstrap { return } catch (e) {} - const user = await this.createService.create({ - username, - email, - password, - }) - - user.set('roles', ['user', 'admin', 'superuser']) try { - await user.save() + await this.createService.create({ + username, + email, + password, + }, ['user', 'admin', 'superuser']) } catch (e) { - this.logger.error('could not create admin user') + this.logger.error({ + error: e, + }, 'could not create admin user') + return } this.logger.info('new root user created') diff --git a/src/service/user/index.ts b/src/service/user/index.ts index 1ee2da9..a215ed1 100644 --- a/src/service/user/index.ts +++ b/src/service/user/index.ts @@ -1,9 +1,9 @@ -import { BootService } from './boot.service'; -import { UserCreateService } from './user.create.service'; -import { UserDeleteService } from './user.delete.service'; -import { UserService } from './user.service'; -import { UserStatisticService } from './user.statistic.service'; -import { UserUpdateService } from './user.update.service'; +import { BootService } from './boot.service' +import { UserCreateService } from './user.create.service' +import { UserDeleteService } from './user.delete.service' +import { UserService } from './user.service' +import { UserStatisticService } from './user.statistic.service' +import { UserUpdateService } from './user.update.service' export const userServices = [ BootService, diff --git a/src/service/user/user.create.service.ts b/src/service/user/user.create.service.ts index db89e28..7caa5a8 100644 --- a/src/service/user/user.create.service.ts +++ b/src/service/user/user.create.service.ts @@ -1,18 +1,19 @@ -import { Injectable } from '@nestjs/common'; -import { InjectModel } from '@nestjs/mongoose'; -import { Model } from 'mongoose'; -import { PinoLogger } from 'nestjs-pino/dist'; -import {rolesType} from '../../config/roles' -import { UserCreateInput } from '../../dto/user/user.create.input'; -import { UserDocument, UserSchemaName } from '../../schema/user.schema'; -import { PasswordService } from '../auth/password.service'; -import { MailService } from '../mail.service'; -import {SettingService} from '../setting.service' +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { PinoLogger } from 'nestjs-pino/dist' +import { Repository } from 'typeorm' +import { rolesType } from '../../config/roles' +import { UserCreateInput } from '../../dto/user/user.create.input' +import { UserEntity } from '../../entity/user.entity' +import { PasswordService } from '../auth/password.service' +import { MailService } from '../mail.service' +import { SettingService } from '../setting.service' @Injectable() export class UserCreateService { constructor( - @InjectModel(UserSchemaName) private userModel: Model, + @InjectRepository(UserEntity) + private readonly userRepository: Repository, private readonly mailerService: MailService, private readonly logger: PinoLogger, private readonly passwordService: PasswordService, @@ -33,25 +34,33 @@ export class UserCreateService { return ['user'] } - async create(user: UserCreateInput): Promise { - // TODO check for uniqueness of email & username! + async create(input: UserCreateInput, roles?: rolesType): Promise { + if (undefined !== await this.userRepository.findOne({ username: input.username })) { + throw new Error('username already in use') + } + if (undefined !== await this.userRepository.findOne({ email: input.email })) { + throw new Error('email already in use') + } - const entry = new this.userModel({ - ...user, - roles: await this.getDefaultRoles(), - passwordHash: await this.passwordService.hash(user.password), - }) + let user = new UserEntity() - await entry.save({ - validateBeforeSave: true, - }) + user.provider = 'local' + user.username = input.username + user.email = input.email + user.firstName = input.firstName + user.lastName = input.lastName + user.language = input.language ?? 'en' + user.roles = roles ? roles : await this.getDefaultRoles() + user.passwordHash = await this.passwordService.hash(input.password) + + user = await this.userRepository.save(user) const sent = await this.mailerService.send( - entry.email, + user.email, 'user/created', { - username: entry.username, + username: user.username, confirm: 'https://www.google.com', // TODO confirm url } ) @@ -61,6 +70,6 @@ export class UserCreateService { this.logger.warn('failed to send email for user creation') } - return entry + return user } } diff --git a/src/service/user/user.delete.service.ts b/src/service/user/user.delete.service.ts index e501cf0..1b82771 100644 --- a/src/service/user/user.delete.service.ts +++ b/src/service/user/user.delete.service.ts @@ -1,16 +1,17 @@ -import { Injectable } from '@nestjs/common'; -import { InjectModel } from '@nestjs/mongoose'; -import { Model } from 'mongoose'; -import { UserDocument, UserSchemaName } from '../../schema/user.schema'; +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { UserEntity } from '../../entity/user.entity' @Injectable() export class UserDeleteService { constructor( - @InjectModel(UserSchemaName) private userModel: Model, + @InjectRepository(UserEntity) + private readonly userRepository: Repository, ) { } async delete(id: string): Promise { - await this.userModel.findByIdAndDelete(id).exec() + await this.userRepository.delete(id) } } diff --git a/src/service/user/user.service.ts b/src/service/user/user.service.ts index 829d7c5..f03400b 100644 --- a/src/service/user/user.service.ts +++ b/src/service/user/user.service.ts @@ -1,33 +1,33 @@ -import { Injectable } from '@nestjs/common'; -import { InjectModel } from '@nestjs/mongoose'; -import { Model } from 'mongoose'; -import { UserDocument, UserSchemaName } from '../../schema/user.schema'; +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { UserEntity } from '../../entity/user.entity' @Injectable() export class UserService { constructor( - @InjectModel(UserSchemaName) private userModel: Model, + @InjectRepository(UserEntity) + private readonly userRepository: Repository, ) { } - async isSuperuser(user: UserDocument): Promise { + async isSuperuser(user: UserEntity): Promise { return user.roles.includes('superuser') } - async find(start: number, limit: number, sort: any = {}): Promise<[UserDocument[], number]> { - return [ - await this.userModel - .find() - .sort(sort) - .skip(start) - .limit(limit), - await this.userModel - .countDocuments() - ] + async find(start: number, limit: number, sort: any = {}): Promise<[UserEntity[], number]> { + const qb = this.userRepository.createQueryBuilder('u') + + // TODO readd sort + + qb.skip(start) + qb.take(limit) + + return await qb.getManyAndCount() } - async findById(id: string): Promise { - const user = await this.userModel.findById(id); + async findById(id: string): Promise { + const user = await this.userRepository.findOne(id); if (!user) { throw new Error('no user found') @@ -36,10 +36,10 @@ export class UserService { return user } - async findByUsername(username: string): Promise { - const user = await this.userModel.findOne({ + async findByUsername(username: string): Promise { + const user = await this.userRepository.findOne({ username, - }).exec() + }) if (!user) { throw new Error('no user found') @@ -48,10 +48,10 @@ export class UserService { return user } - async findByEmail(email: string): Promise { - const user = await this.userModel.findOne({ + async findByEmail(email: string): Promise { + const user = await this.userRepository.findOne({ email, - }).exec() + }) if (!user) { throw new Error('no user found') diff --git a/src/service/user/user.statistic.service.ts b/src/service/user/user.statistic.service.ts index 507c203..b7444a4 100644 --- a/src/service/user/user.statistic.service.ts +++ b/src/service/user/user.statistic.service.ts @@ -1,14 +1,15 @@ -import { InjectModel } from '@nestjs/mongoose'; -import { Model } from 'mongoose'; -import { UserDocument, UserSchemaName } from '../../schema/user.schema'; +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { UserEntity } from '../../entity/user.entity' export class UserStatisticService { constructor( - @InjectModel(UserSchemaName) private userModel: Model, + @InjectRepository(UserEntity) + private readonly userRepository: Repository, ) { } async getTotal(): Promise { - return await this.userModel.estimatedDocumentCount(); + return await this.userRepository.count(); } } diff --git a/src/service/user/user.update.service.ts b/src/service/user/user.update.service.ts index 487fe3a..39e3711 100644 --- a/src/service/user/user.update.service.ts +++ b/src/service/user/user.update.service.ts @@ -1,40 +1,49 @@ -import { Injectable } from '@nestjs/common'; -import { UserUpdateInput } from '../../dto/user/user.update.input'; -import { UserDocument } from '../../schema/user.schema'; +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { UserUpdateInput } from '../../dto/user/user.update.input' +import { UserEntity } from '../../entity/user.entity' +import { PasswordService } from '../auth/password.service' @Injectable() export class UserUpdateService { - async update(user: UserDocument, input: UserUpdateInput): Promise { + constructor( + @InjectRepository(UserEntity) + private readonly userRepository: Repository, + private readonly passwordService: PasswordService, + ) { + } + + async update(user: UserEntity, input: UserUpdateInput): Promise { if (input.firstName !== undefined) { - user.set('firstName', input.firstName) + user.firstName = input.firstName } if (input.lastName !== undefined) { - user.set('lastName', input.lastName) + user.lastName = input.lastName } if (input.email !== undefined) { - user.set('email', input.email) + user.email = input.email } if (input.username !== undefined) { - user.set('username', input.username) + user.username = input.username } if (input.roles !== undefined) { - user.set('roles', input.roles) + user.roles = input.roles as any } if (input.language !== undefined) { - user.set('language', input.language) + user.language = input.language } if (input.password !== undefined) { - // user.set('language', input.language) - // TODO password handling + user.passwordHash = await this.passwordService.hash(input.password) } - await user.save() + await this.userRepository.save(user) return user } diff --git a/yarn.lock b/yarn.lock index 1a92559..a6157ad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -101,6 +101,25 @@ make-fetch-happen "^8.0.0" pretty-format "^26.0.0" +"@apollo/gateway@^0.27.1": + version "0.27.1" + resolved "https://registry.yarnpkg.com/@apollo/gateway/-/gateway-0.27.1.tgz#d76295e84cf4317de75e87a02e5172ddf245e72a" + integrity sha512-qXOtVYzwTFaDbLKYs3v7bQfCmepUq/QQUh8C7rRR3uBewv0NwWs+t7RpTvRkumusyz+KpoXDvneZB2Wo6MTI0Q== + dependencies: + "@apollo/federation" "^0.23.2" + "@apollo/query-planner" "^0.1.4" + "@types/node-fetch" "2.5.10" + apollo-graphql "^0.9.2" + apollo-reporting-protobuf "^0.6.0" + apollo-server-caching "^0.6.0" + apollo-server-core "^2.23.0" + apollo-server-env "^3.0.0" + apollo-server-errors "^2.5.0" + apollo-server-types "^0.7.0" + loglevel "^1.6.1" + make-fetch-happen "^8.0.0" + pretty-format "^26.0.0" + "@apollo/protobufjs@^1.0.3": version "1.0.5" resolved "https://registry.yarnpkg.com/@apollo/protobufjs/-/protobufjs-1.0.5.tgz#a78b726147efc0795e74c8cb8a11aafc6e02f773" @@ -128,6 +147,15 @@ chalk "^4.1.0" pretty-format "^26.0.0" +"@apollo/query-planner@^0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@apollo/query-planner/-/query-planner-0.1.4.tgz#f00fb89547cb03be9b91c399611a460693e0a2f7" + integrity sha512-d/kWRBVdQlssMPlprOYc31Wq64TAc9ITah+61rJXHiQmZIN6CefwEdY6QnSa84TimEQE9gjgWz7Q96i8cuV49A== + dependencies: + chalk "^4.1.0" + deep-equal "^2.0.5" + pretty-format "^26.0.0" + "@apollographql/apollo-tools@^0.4.3": version "0.4.8" resolved "https://registry.yarnpkg.com/@apollographql/apollo-tools/-/apollo-tools-0.4.8.tgz#d81da89ee880c2345eb86bddb92b35291f6135ed" @@ -1650,11 +1678,6 @@ resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-0.4.1.tgz#e7fe038f0bdda7b8f858fa79ca8516b8f9069b1a" integrity sha512-JXrw2LMangSU3vnaXWXVX47GRG1FbbNh4aVBbidDjxT3zlghsoNQY6qyWtT001MCl8lJGo8I6i6+DurBRRxl/Q== -"@nestjs/mongoose@^7.2.4": - version "7.2.4" - resolved "https://registry.yarnpkg.com/@nestjs/mongoose/-/mongoose-7.2.4.tgz#60a50532a244279703344368d74ecd802aeda4a4" - integrity sha512-NTE/IwijFUEJytPHLoHRYe0X5p16W1Awf8tm6I3mWsIUuBnSDfMyN0fy30uVaM/exYvCkMwEsAVpeSeKVPMHxg== - "@nestjs/passport@^7.1.5": version "7.1.5" resolved "https://registry.yarnpkg.com/@nestjs/passport/-/passport-7.1.5.tgz#b32fc0492008d73ebae4327fbc0012a738a83664" @@ -1895,13 +1918,6 @@ "@types/connect" "*" "@types/node" "*" -"@types/bson@*": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/bson/-/bson-4.0.2.tgz#7accb85942fc39bbdb7515d4de437c04f698115f" - integrity sha512-+uWmsejEHfmSjyyM/LkrP0orfE2m5Mx9Xel4tXNeqi1ldK5XMQcDsFkBmLDtuyKUbxj2jGDo0H240fbCRJZo7Q== - dependencies: - "@types/node" "*" - "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" @@ -1998,7 +2014,7 @@ "@types/qs" "*" "@types/serve-static" "*" -"@types/express@4.17.11", "@types/express@^4.17.11": +"@types/express@4.17.11": version "4.17.11" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.11.tgz#debe3caa6f8e5fcda96b47bd54e2f40c4ee59545" integrity sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg== @@ -2142,30 +2158,6 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256" integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg== -"@types/mongodb@*": - version "3.5.26" - resolved "https://registry.yarnpkg.com/@types/mongodb/-/mongodb-3.5.26.tgz#aa10315925ba10cdc7931ef280c0ff6f54fd37f3" - integrity sha512-p0X2VJgIBNHfNBdZdzzG8eQ/3bf6mQoXDT0UhVyVEdSzXEa1+2pFcwGvEZp72sjztyBwfRKlgrXMjCVavLcuGg== - dependencies: - "@types/bson" "*" - "@types/node" "*" - -"@types/mongodb@^3.5.27": - version "3.6.12" - resolved "https://registry.yarnpkg.com/@types/mongodb/-/mongodb-3.6.12.tgz#727960d34f35054d2f2ce68909e16094f742d935" - integrity sha512-49aEzQD5VdHPxyd5dRyQdqEveAg9LanwrH8RQipnMuulwzKmODXIZRp0umtxi1eBUfEusRkoy8AVOMr+kVuFog== - dependencies: - "@types/bson" "*" - "@types/node" "*" - -"@types/mongoose@^5.10.5": - version "5.10.5" - resolved "https://registry.yarnpkg.com/@types/mongoose/-/mongoose-5.10.5.tgz#0f4fb0440e8cf0213caec1e5c7b163dbd9847c56" - integrity sha512-37QMIA954T3n+HSksSNLlxZsqF8fMJu5S4dyPBod6gRxGtsXlQ9jUtL8BE8Seimv99u79eLXI3bggoCnSQ/fxQ== - dependencies: - "@types/mongodb" "*" - "@types/node" "*" - "@types/node-fetch@2.5.10": version "2.5.10" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.10.tgz#9b4d4a0425562f9fcea70b12cb3fcdd946ca8132" @@ -2739,11 +2731,6 @@ ansi-colors@4.1.1, ansi-colors@^4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== -ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - integrity sha1-06ioOzGapneTZisT52HHkRQiMG4= - ansi-escapes@^4.2.1: version "4.3.1" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" @@ -3067,6 +3054,11 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= +array-filter@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" + integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM= + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -3187,6 +3179,13 @@ atomic-sleep@^1.0.0: resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== +available-typed-arrays@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5" + integrity sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ== + dependencies: + array-filter "^1.0.0" + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -3377,14 +3376,6 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9" integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ== -bl@^2.2.0, bl@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.1.tgz#8c11a7b730655c5d56898cdc871224f40fd901d5" - integrity sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g== - dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" - bl@^4.0.3, bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -3401,16 +3392,6 @@ block-stream@*: dependencies: inherits "~2.0.0" -bluebird@3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" - integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA== - -bluebird@^3.3.3: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - body-parser@1.19.0, body-parser@^1.18.3: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" @@ -3513,11 +3494,6 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -bson@^1.1.4: - version "1.1.5" - resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.5.tgz#2aaae98fcdf6750c0848b0cba1ddec3c73060a34" - integrity sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg== - buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" @@ -3607,6 +3583,14 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -3642,11 +3626,6 @@ camelcase@5.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== -camelcase@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" - integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= - camelcase@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" @@ -3696,7 +3675,7 @@ chalk@3.0.0, chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^1.0.0, chalk@^1.1.1: +chalk@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= @@ -3887,13 +3866,6 @@ cli-boxes@^1.0.0: resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= -cli-cursor@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - integrity sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc= - dependencies: - restore-cursor "^1.0.1" - cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -3933,25 +3905,11 @@ cli-table3@0.5.1: optionalDependencies: colors "^1.1.2" -cli-width@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" - integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== - cli-width@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== -cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -4392,13 +4350,6 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: dependencies: ms "2.0.0" -debug@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" @@ -4435,7 +4386,7 @@ decamelize-keys@^1.1.0: decamelize "^1.1.0" map-obj "^1.0.0" -decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.2.0: +decamelize@^1.1.0, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -4450,6 +4401,27 @@ decode-uri-component@^0.2.0: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= +deep-equal@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.0.5.tgz#55cd2fe326d83f9cbf7261ef0e060b3f724c5cb9" + integrity sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw== + dependencies: + call-bind "^1.0.0" + es-get-iterator "^1.1.1" + get-intrinsic "^1.0.1" + is-arguments "^1.0.4" + is-date-object "^1.0.2" + is-regex "^1.1.1" + isarray "^2.0.5" + object-is "^1.1.4" + object-keys "^1.1.1" + object.assign "^4.1.2" + regexp.prototype.flags "^1.3.0" + side-channel "^1.0.3" + which-boxed-primitive "^1.0.1" + which-collection "^1.0.1" + which-typed-array "^1.1.2" + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -4728,7 +4700,7 @@ dotenv-expand@5.1.0: resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== -dotenv@8.2.0, dotenv@^8.0.0, dotenv@^8.2.0: +dotenv@8.2.0, dotenv@^8.2.0: version "8.2.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== @@ -4870,6 +4842,42 @@ es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstrac string.prototype.trimend "^1.0.1" string.prototype.trimstart "^1.0.1" +es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: + version "1.18.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0.tgz#ab80b359eecb7ede4c298000390bc5ac3ec7b5a4" + integrity sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.2" + is-callable "^1.2.3" + is-negative-zero "^2.0.1" + is-regex "^1.1.2" + is-string "^1.0.5" + object-inspect "^1.9.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.0" + +es-get-iterator@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.2.tgz#9234c54aba713486d7ebde0220864af5e2b283f7" + integrity sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.0" + has-symbols "^1.0.1" + is-arguments "^1.1.0" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.5" + isarray "^2.0.5" + es-module-lexer@^0.4.0: version "0.4.1" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.4.1.tgz#dda8c6a14d8f340a24e34331e0fab0cb50438e0e" @@ -5184,11 +5192,6 @@ execa@^4.0.2: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - integrity sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g= - exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -5428,14 +5431,6 @@ figlet@^1.1.1: resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.5.0.tgz#2db4d00a584e5155a96080632db919213c3e003c" integrity sha512-ZQJM4aifMpz6H19AW1VqvZ7l4pOE9p7i/3LyxgO2kp+PO/VcDYNqIHEMtkccqIhTXMKci4kjueJr/iCQEaT/Ww== -figures@^1.3.5: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4= - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - figures@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" @@ -5492,14 +5487,6 @@ finalhandler@~1.1.2: statuses "~1.5.0" unpipe "~1.0.0" -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" @@ -5564,6 +5551,11 @@ for-in@^1.0.2: resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -5772,16 +5764,20 @@ gensync@^1.0.0-beta.1: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -6061,6 +6057,11 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -6076,6 +6077,11 @@ has-symbols@^1.0.0, has-symbols@^1.0.1: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -6445,25 +6451,6 @@ inquirer@7.3.3: strip-ansi "^6.0.0" through "^2.3.6" -inquirer@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" - integrity sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34= - dependencies: - ansi-escapes "^1.1.0" - ansi-regex "^2.0.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" - cli-width "^2.0.0" - figures "^1.3.5" - lodash "^4.3.0" - readline2 "^1.0.1" - run-async "^0.1.0" - rx-lite "^3.1.2" - string-width "^1.0.1" - strip-ansi "^3.0.0" - through "^2.3.6" - inquirer@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.0.0.tgz#957a46db1abcf0fdd2ab82deb7470e90afc7d0ac" @@ -6488,11 +6475,6 @@ interpret@^1.0.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= - ioredis@^4.17.3: version "4.17.3" resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.17.3.tgz#9938c60e4ca685f75326337177bdc2e73ae9c9dc" @@ -6548,11 +6530,23 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" +is-arguments@^1.0.4, is-arguments@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" + integrity sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg== + dependencies: + call-bind "^1.0.0" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-bigint@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.1.tgz#6923051dfcbc764278540b9ce0e6b3213aa5ebc2" + integrity sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg== + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -6560,6 +6554,13 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" +is-boolean-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.0.tgz#e2aaad3a3a8fca34c28f6eee135b156ed2587ff0" + integrity sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA== + dependencies: + call-bind "^1.0.0" + is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -6570,6 +6571,11 @@ is-callable@^1.1.4, is-callable@^1.2.0: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb" integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw== +is-callable@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" + integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== + is-ci@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" @@ -6598,7 +6604,7 @@ is-data-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-date-object@^1.0.1: +is-date-object@^1.0.1, is-date-object@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== @@ -6690,6 +6696,21 @@ is-lambda@^1.0.1: resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= +is-map@^2.0.1, is-map@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" + integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== + +is-negative-zero@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" + integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== + +is-number-object@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" + integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -6741,6 +6762,19 @@ is-regex@^1.0.3, is-regex@^1.1.0: dependencies: has-symbols "^1.0.1" +is-regex@^1.1.1, is-regex@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251" + integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg== + dependencies: + call-bind "^1.0.2" + has-symbols "^1.0.1" + +is-set@^2.0.1, is-set@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" + integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== + is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -6763,13 +6797,24 @@ is-subdir@^1.1.1: dependencies: better-path-resolve "1.0.0" -is-symbol@^1.0.2: +is-symbol@^1.0.2, is-symbol@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== dependencies: has-symbols "^1.0.1" +is-typed-array@^1.1.3: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.5.tgz#f32e6e096455e329eb7b423862456aa213f0eb4e" + integrity sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug== + dependencies: + available-typed-arrays "^1.0.2" + call-bind "^1.0.2" + es-abstract "^1.18.0-next.2" + foreach "^2.0.5" + has-symbols "^1.0.1" + is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -6780,10 +6825,15 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= +is-weakmap@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" + integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== + +is-weakset@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.1.tgz#e9a0af88dbd751589f5e50d80f4c98b780884f83" + integrity sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw== is-windows@^1.0.0, is-windows@^1.0.2: version "1.0.2" @@ -6807,6 +6857,11 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -7501,16 +7556,6 @@ jws@^3.2.2: jwa "^1.4.1" safe-buffer "^5.0.1" -kareem@2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.1.tgz#def12d9c941017fabfb00f873af95e9c99e1be87" - integrity sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw== - -kareem@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.2.tgz#78c4508894985b8d38a0dc15e1a8e11078f2ca93" - integrity sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ== - kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -7540,13 +7585,6 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= - dependencies: - invert-kv "^1.0.0" - leven@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" @@ -7618,17 +7656,6 @@ list-stylesheets@^1.2.9: cheerio "^0.22.0" pick-util "^1.1.3" -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" @@ -7676,11 +7703,6 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash.assign@^4.0.3, lodash.assign@^4.0.6: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" - integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= - lodash.assignin@^4.0.9: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" @@ -7826,7 +7848,7 @@ lodash@4.17.21, lodash@4.x, lodash@^4.15.0, lodash@^4.17.21, lodash@^4.7.0: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -lodash@^4.17.15, lodash@^4.17.19, lodash@^4.3.0: +lodash@^4.17.15, lodash@^4.17.19: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== @@ -8019,11 +8041,6 @@ memfs@^3.1.2: dependencies: fs-monkey "1.0.1" -memory-pager@^1.0.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" - integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== - mensch@^0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/mensch/-/mensch-0.3.4.tgz#770f91b46cb16ea5b204ee735768c3f0c491fecd" @@ -8093,19 +8110,6 @@ micromatch@^4.0.0, micromatch@^4.0.2: braces "^3.0.1" picomatch "^2.0.5" -migrate-mongoose@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/migrate-mongoose/-/migrate-mongoose-4.0.0.tgz#a78a1eaff2b65c0483b2b9a817c36683adf220ac" - integrity sha512-Zf4Jk+CvBZUrZx4q/vvYr2pRGYAo7RO4BJx/3aTAR9VhNa34/iV0Rhqj87Tflk0n14SgwZpqvixyJzEpmSAikg== - dependencies: - bluebird "^3.3.3" - colors "^1.1.2" - dotenv "^8.0.0" - inquirer "^0.12.0" - mkdirp "^0.5.1" - mongoose "^5.6.3" - yargs "^4.8.1" - mime-db@1.44.0: version "1.44.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" @@ -8597,104 +8601,6 @@ mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4: dependencies: minimist "^1.2.5" -mongodb@3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.6.0.tgz#babd7172ec717e2ed3f85e079b3f1aa29dce4724" - integrity sha512-/XWWub1mHZVoqEsUppE0GV7u9kanLvHxho6EvBxQbShXTKYF9trhZC2NzbulRGeG7xMJHD8IOWRcdKx5LPjAjQ== - dependencies: - bl "^2.2.0" - bson "^1.1.4" - denque "^1.4.1" - require_optional "^1.0.1" - safe-buffer "^5.1.2" - optionalDependencies: - saslprep "^1.0.0" - -mongodb@3.6.6: - version "3.6.6" - resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.6.6.tgz#92e3658f45424c34add3003e3046c1535c534449" - integrity sha512-WlirMiuV1UPbej5JeCMqE93JRfZ/ZzqE7nJTwP85XzjAF4rRSeq2bGCb1cjfoHLOF06+HxADaPGqT0g3SbVT1w== - dependencies: - bl "^2.2.1" - bson "^1.1.4" - denque "^1.4.1" - optional-require "^1.0.2" - safe-buffer "^5.1.2" - optionalDependencies: - saslprep "^1.0.0" - -mongoose-legacy-pluralize@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz#3ba9f91fa507b5186d399fb40854bff18fb563e4" - integrity sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ== - -mongoose@^5.12.6: - version "5.12.6" - resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-5.12.6.tgz#bbbea1bff149f2ee72cf0efc844a31a92f0546a6" - integrity sha512-lNkToNqcfDyHNArPjd/aODTJp/cDhFEZE9Xtj0yBz+Z2t1h6RRDxzxIV0NW12SAnjIh50U1yW6c3rLPqn17lSw== - dependencies: - "@types/mongodb" "^3.5.27" - bson "^1.1.4" - kareem "2.3.2" - mongodb "3.6.6" - mongoose-legacy-pluralize "1.0.2" - mpath "0.8.3" - mquery "3.2.5" - ms "2.1.2" - regexp-clone "1.0.0" - safe-buffer "5.2.1" - sift "13.5.2" - sliced "1.0.1" - -mongoose@^5.6.3: - version "5.10.2" - resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-5.10.2.tgz#3a6770affa8c05c4198515616fd555a5c9bc74d6" - integrity sha512-VO5eZawEMFh2gx9XPg9ZafzFg5eIVs4R7PW6kK1MFqBq34YD7GomkalYWVt02HctvTPDI1mkXsm52LXNZR1NxA== - dependencies: - bson "^1.1.4" - kareem "2.3.1" - mongodb "3.6.0" - mongoose-legacy-pluralize "1.0.2" - mpath "0.7.0" - mquery "3.2.2" - ms "2.1.2" - regexp-clone "1.0.0" - safe-buffer "5.2.1" - sift "7.0.1" - sliced "1.0.1" - -mpath@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.7.0.tgz#20e8102e276b71709d6e07e9f8d4d0f641afbfb8" - integrity sha512-Aiq04hILxhz1L+f7sjGyn7IxYzWm1zLNNXcfhDtx04kZ2Gk7uvFdgZ8ts1cWa/6d0TQmag2yR8zSGZUmp0tFNg== - -mpath@0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.8.3.tgz#828ac0d187f7f42674839d74921970979abbdd8f" - integrity sha512-eb9rRvhDltXVNL6Fxd2zM9D4vKBxjVVQNLNijlj7uoXUy19zNDsIif5zR+pWmPCWNKwAtqyo4JveQm4nfD5+eA== - -mquery@3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/mquery/-/mquery-3.2.2.tgz#e1383a3951852ce23e37f619a9b350f1fb3664e7" - integrity sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q== - dependencies: - bluebird "3.5.1" - debug "3.1.0" - regexp-clone "^1.0.0" - safe-buffer "5.1.2" - sliced "1.0.1" - -mquery@3.2.5: - version "3.2.5" - resolved "https://registry.yarnpkg.com/mquery/-/mquery-3.2.5.tgz#8f2305632e4bb197f68f60c0cffa21aaf4060c51" - integrity sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A== - dependencies: - bluebird "3.5.1" - debug "3.1.0" - regexp-clone "^1.0.0" - safe-buffer "5.1.2" - sliced "1.0.1" - mri@1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" @@ -8729,11 +8635,6 @@ multer@1.4.2: type-is "^1.6.4" xtend "^4.0.0" -mute-stream@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" - integrity sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA= - mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" @@ -9091,6 +8992,19 @@ object-inspect@^1.7.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== +object-inspect@^1.9.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.2.tgz#b6385a3e2b7cae0b5eafcf90cddf85d128767f30" + integrity sha512-gz58rdPpadwztRrPjZE9DZLOABUpTGdcANUgOwBFO1C+HZZhePoP83M65WGDmbpwFYJSWqavbl4SgDn4k8RYTA== + +object-is@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -9118,6 +9032,16 @@ object.assign@^4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" +object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + object.getownpropertydescriptors@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" @@ -9157,11 +9081,6 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k= - onetime@^5.1.0: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" @@ -9185,11 +9104,6 @@ optimism@^0.15.0: "@wry/context" "^0.6.0" "@wry/trie" "^0.3.0" -optional-require@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/optional-require/-/optional-require-1.0.3.tgz#275b8e9df1dc6a17ad155369c2422a440f89cb07" - integrity sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA== - optional@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/optional/-/optional-0.1.4.tgz#cdb1a9bedc737d2025f690ceeb50e049444fd5b3" @@ -9274,13 +9188,6 @@ os-homedir@^1.0.0: resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= -os-locale@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" - integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= - dependencies: - lcid "^1.0.0" - os-name@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/os-name/-/os-name-4.0.0.tgz#6c05c09c41c15848ea74658d12c9606f0f286599" @@ -9523,13 +9430,6 @@ passport@^0.4.1: passport-strategy "1.x.x" pause "0.0.1" -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= - dependencies: - pinkie-promise "^2.0.0" - path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -9570,15 +9470,6 @@ path-to-regexp@3.2.0: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-3.2.0.tgz#fa7877ecbc495c601907562222453c43cc204a5f" integrity sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA== -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" @@ -9674,18 +9565,6 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - pino-http@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/pino-http/-/pino-http-5.2.0.tgz#d51da7981ab6ea7ca9f17c4db24a427e4ba9c546" @@ -10137,14 +10016,6 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - read-pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" @@ -10162,15 +10033,6 @@ read-pkg-up@^7.0.1: read-pkg "^5.2.0" type-fest "^0.8.1" -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - read-pkg@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" @@ -10210,7 +10072,7 @@ readable-stream@1.1.x: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@^2.3.5: +readable-stream@^2.0.6, readable-stream@^2.2.2: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -10246,15 +10108,6 @@ readdirp@~3.5.0: dependencies: picomatch "^2.2.1" -readline2@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" - integrity sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - mute-stream "0.0.5" - rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -10310,10 +10163,13 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp-clone@1.0.0, regexp-clone@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63" - integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw== +regexp.prototype.flags@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" + integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" regexpp@^3.0.0, regexpp@^3.1.0: version "3.1.0" @@ -10431,24 +10287,11 @@ require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= - require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -require_optional@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e" - integrity sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g== - dependencies: - resolve-from "^2.0.0" - semver "^5.1.0" - requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -10466,11 +10309,6 @@ resolve-from@5.0.0, resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve-from@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" - integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" @@ -10496,14 +10334,6 @@ resolve@^1.15.1, resolve@^1.18.1: is-core-module "^2.2.0" path-parse "^1.0.6" -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - integrity sha1-NGYfRohjJ/7SmRR5FSJS35LapUE= - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" @@ -10551,13 +10381,6 @@ rsvp@^4.8.4: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== -run-async@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" - integrity sha1-yK1KXhEGYeQCp9IbUw4AnyX444k= - dependencies: - once "^1.3.0" - run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -10568,11 +10391,6 @@ run-parallel@^1.1.9: resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== -rx-lite@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" - integrity sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI= - rxjs@6.6.3: version "6.6.3" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" @@ -10599,7 +10417,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -10631,13 +10449,6 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -saslprep@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" - integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== - dependencies: - sparse-bitfield "^3.0.3" - sax@>=0.6.0, sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -10668,7 +10479,7 @@ schema-utils@^3.0.0: ajv "^6.12.5" ajv-keywords "^3.5.2" -"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -10817,15 +10628,14 @@ shimmer@^1.2.0: resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== -sift@13.5.2: - version "13.5.2" - resolved "https://registry.yarnpkg.com/sift/-/sift-13.5.2.tgz#24a715e13c617b086166cd04917d204a591c9da6" - integrity sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA== - -sift@7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/sift/-/sift-7.0.1.tgz#47d62c50b159d316f1372f8b53f9c10cd21a4b08" - integrity sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g== +side-channel@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" sigmund@^1.0.1: version "1.0.1" @@ -10861,11 +10671,6 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -sliced@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" - integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= - slick@^1.12.2: version "1.12.2" resolved "https://registry.yarnpkg.com/slick/-/slick-1.12.2.tgz#bd048ddb74de7d1ca6915faa4a57570b3550c2d7" @@ -10991,13 +10796,6 @@ sourcemap-codec@^1.4.4: resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== -sparse-bitfield@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" - integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE= - dependencies: - memory-pager "^1.0.2" - spawndamnit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/spawndamnit/-/spawndamnit-2.0.0.tgz#9f762ac5c3476abb994b42ad592b5ad22bb4b0ad" @@ -11192,6 +10990,14 @@ string.prototype.trimend@^1.0.1: define-properties "^1.1.3" es-abstract "^1.17.5" +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + string.prototype.trimstart@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" @@ -11200,6 +11006,14 @@ string.prototype.trimstart@^1.0.1: define-properties "^1.1.3" es-abstract "^1.17.5" +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -11240,13 +11054,6 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= - dependencies: - is-utf8 "^0.2.0" - strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -11885,6 +11692,16 @@ uglify-js@^3.5.1: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.4.tgz#592588bb9f47ae03b24916e2471218d914955574" integrity sha512-kv7fCkIXyQIilD5/yQy8O+uagsYIOt5cZvs890W40/e/rvjMSzJw81o9Bg0tkURxzZBROtDQhW2LFjOGoK3RZw== +unbox-primitive@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" @@ -12207,10 +12024,26 @@ whatwg-url@^8.5.0: tr46 "^2.0.2" webidl-conversions "^6.1.0" -which-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" - integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= +which-boxed-primitive@^1.0.1, which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-collection@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" + integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + dependencies: + is-map "^2.0.1" + is-set "^2.0.1" + is-weakmap "^2.0.1" + is-weakset "^2.0.1" which-module@^2.0.0: version "2.0.0" @@ -12225,6 +12058,19 @@ which-pm@2.0.0: load-yaml-file "^0.2.0" path-exists "^4.0.0" +which-typed-array@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.4.tgz#8fcb7d3ee5adf2d771066fba7cf37e32fe8711ff" + integrity sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA== + dependencies: + available-typed-arrays "^1.0.2" + call-bind "^1.0.0" + es-abstract "^1.18.0-next.1" + foreach "^2.0.5" + function-bind "^1.1.1" + has-symbols "^1.0.1" + is-typed-array "^1.1.3" + which@1, which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -12253,11 +12099,6 @@ widest-line@^2.0.0: dependencies: string-width "^2.1.1" -window-size@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" - integrity sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU= - windows-release@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-4.0.0.tgz#4725ec70217d1bf6e02c7772413b29cdde9ec377" @@ -12285,14 +12126,6 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -12386,11 +12219,6 @@ xtend@^4.0.0: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -y18n@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= - y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" @@ -12443,14 +12271,6 @@ yargs-parser@^18.1.2, yargs-parser@^18.1.3: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" - integrity sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ= - dependencies: - camelcase "^3.0.0" - lodash.assign "^4.0.6" - yargs@^15.1.0, yargs@^15.3.1, yargs@^15.4.1: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" @@ -12481,26 +12301,6 @@ yargs@^16.0.0, yargs@^16.1.0, yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^4.8.1: - version "4.8.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" - integrity sha1-wMQpJMpKqmsObaFznfshZDn53cA= - dependencies: - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - lodash.assign "^4.0.3" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^1.0.1" - which-module "^1.0.0" - window-size "^0.2.0" - y18n "^3.2.1" - yargs-parser "^2.4.1" - yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"