diff --git a/.eslintrc.js b/.eslintrc.js index 1aba513..9b9f349 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -24,6 +24,7 @@ module.exports = { jest: true, }, rules: { + '@typescript-eslint/no-unsafe-return': 'warn', '@typescript-eslint/no-unsafe-call': 'warn', '@typescript-eslint/no-unsafe-argument': 'warn', '@typescript-eslint/no-unsafe-assignment': 'warn', diff --git a/CHANGELOG.md b/CHANGELOG.md index 75f9e58..906dd20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - logic backend components - forms now have multiple notification - layout for forms -- mariadb / mysql support +- mariadb / mysql support (fixes https://github.com/ohmyform/ohmyform/issues/143) - user confirmation tokens - email verification diff --git a/src/app.imports.ts b/src/app.imports.ts index e127cc7..133c767 100644 --- a/src/app.imports.ts +++ b/src/app.imports.ts @@ -64,7 +64,7 @@ export const imports = [ JwtModule.registerAsync({ imports: [ConfigModule], inject: [ConfigService], - useFactory: async (configService: ConfigService): Promise => ({ + useFactory: (configService: ConfigService): JwtModuleOptions => ({ secret: configService.get('SECRET_KEY'), signOptions: { expiresIn: '4h', @@ -154,7 +154,7 @@ export const imports = [ MailerModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], - useFactory: async (configService: ConfigService) => ({ + useFactory: (configService: ConfigService) => ({ transport: configService.get('MAILER_URI', 'smtp://localhost:1025'), defaults: { from: configService.get('MAILER_FROM', 'OhMyForm '), diff --git a/src/cli.ts b/src/cli.ts index 3bd068b..9a9e261 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -5,7 +5,7 @@ const bootstrap = new BootstrapConsole({ module: AppModule, useDecorators: true, }); -bootstrap.init().then(async (app) => { +void bootstrap.init().then(async (app) => { try { await app.init(); await bootstrap.boot(); diff --git a/src/command/user.command.ts b/src/command/user.command.ts index 861714a..ad2c373 100644 --- a/src/command/user.command.ts +++ b/src/command/user.command.ts @@ -59,7 +59,7 @@ export class UserCommand { @Command({ command: 'activate ', }) - async activate(username: string): Promise { + activate(username: string): void { console.log(`activate user ${username}`) } } diff --git a/src/config/fields.ts b/src/config/fields.ts index 0169fb7..2d18f50 100644 --- a/src/config/fields.ts +++ b/src/config/fields.ts @@ -17,7 +17,8 @@ export const fieldTypes = [ export const matchType = { color: /^#([A-F0-9]{6}|[A-F0-9]{3})$/i, - url: /((([A-Z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/i, + // eslint-disable-next-line max-len + url: /((([A-Z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/i, email: /.+@.+\..+/, slug: /^[a-z0-9_]+$/, } diff --git a/src/dto/form/form.field.model.ts b/src/dto/form/form.field.model.ts index 5b1012b..59c0fea 100644 --- a/src/dto/form/form.field.model.ts +++ b/src/dto/form/form.field.model.ts @@ -44,8 +44,8 @@ export class FormFieldModel { this.description = document.description this.required = document.required this.value = document.value - this.options = document.options ? document.options.map(option => new FormFieldOptionModel(option)) : [] - this.logic = document.logic ? document.logic.map(logic => new FormFieldLogicModel(logic)) : [] + this.options = document.options?.map(option => new FormFieldOptionModel(option)) || [] + this.logic = document.logic?.map(logic => new FormFieldLogicModel(logic)) || [] this.rating = document.rating ? new FormFieldRatingModel(document.rating) : null } } diff --git a/src/main.ts b/src/main.ts index 0f88766..45d6aea 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,7 +4,7 @@ import cors from 'cors' import { Logger } from 'nestjs-pino' import { AppModule } from './app.module' -(async () => { +void (async () => { const options: NestApplicationOptions = { bufferLogs: true, } diff --git a/src/resolver/auth/auth.register.resolver.ts b/src/resolver/auth/auth.register.resolver.ts index 23e74cc..2abdbd5 100644 --- a/src/resolver/auth/auth.register.resolver.ts +++ b/src/resolver/auth/auth.register.resolver.ts @@ -22,7 +22,7 @@ export class AuthRegisterResolver { async authRegister( @Args({ name: 'user' }) data: UserCreateInput, ): Promise { - if (await this.settingService.isTrue('SIGNUP_DISABLED')) { + if (this.settingService.isTrue('SIGNUP_DISABLED')) { throw new Error('signup disabled') } diff --git a/src/resolver/form/form.statistic.resolver.ts b/src/resolver/form/form.statistic.resolver.ts index a70f8fc..2cbc102 100644 --- a/src/resolver/form/form.statistic.resolver.ts +++ b/src/resolver/form/form.statistic.resolver.ts @@ -12,7 +12,7 @@ export class FormStatisticResolver { } @Query(() => FormStatisticModel) - async getFormStatistic(): Promise { + getFormStatistic(): FormStatisticModel { return new FormStatisticModel() } diff --git a/src/resolver/setting/setting.resolver.ts b/src/resolver/setting/setting.resolver.ts index 3554881..7abf806 100644 --- a/src/resolver/setting/setting.resolver.ts +++ b/src/resolver/setting/setting.resolver.ts @@ -16,7 +16,7 @@ export class SettingResolver { @Query(() => SettingPagerModel) @Roles('superuser') - async getSettings(): Promise { + getSettings(): SettingPagerModel { // TODO https://github.com/ohmyform/api/issues/3 return new SettingPagerModel( [], diff --git a/src/resolver/status.resolver.ts b/src/resolver/status.resolver.ts index 5cbafce..3c332cb 100644 --- a/src/resolver/status.resolver.ts +++ b/src/resolver/status.resolver.ts @@ -4,7 +4,7 @@ import { StatusModel } from '../dto/status.model' @Resolver(() => StatusModel) export class StatusResolver { @Query(() => StatusModel) - async status(): Promise { + status(): StatusModel { return new StatusModel({ version: process.env.version || 'dev', }) diff --git a/src/resolver/submission/submission.field.resolver.ts b/src/resolver/submission/submission.field.resolver.ts index a52bc0f..dbaa15f 100644 --- a/src/resolver/submission/submission.field.resolver.ts +++ b/src/resolver/submission/submission.field.resolver.ts @@ -18,9 +18,16 @@ export class SubmissionFieldResolver { @Parent() parent: SubmissionFieldModel, @Context('cache') cache: ContextCache, ): Promise { - const submissionField = await cache.get(cache.getCacheKey(SubmissionFieldEntity.name, parent.id)) + const submissionField = await cache.get( + cache.getCacheKey(SubmissionFieldEntity.name, parent.id) + ) - const field = await cache.get(cache.getCacheKey(FormFieldEntity.name, submissionField.fieldId), () => this.formFieldService.findById(submissionField.fieldId, submissionField.field)) + const field = await cache.get( + cache.getCacheKey( + FormFieldEntity.name, + submissionField.fieldId), + () => this.formFieldService.findById(submissionField.fieldId, submissionField.field) + ) if (!field) { return null diff --git a/src/resolver/submission/submission.resolver.ts b/src/resolver/submission/submission.resolver.ts index a0766e7..f4bc0d9 100644 --- a/src/resolver/submission/submission.resolver.ts +++ b/src/resolver/submission/submission.resolver.ts @@ -15,7 +15,9 @@ export class SubmissionResolver { @Parent() parent: SubmissionModel, @Context('cache') cache: ContextCache, ): Promise { - const submission = await cache.get(cache.getCacheKey(SubmissionEntity.name, parent.id)) + const submission = await cache.get( + cache.getCacheKey(SubmissionEntity.name, parent.id) + ) return submission.fields.map(field => { cache.add(cache.getCacheKey(SubmissionFieldEntity.name, field.id), field) diff --git a/src/resolver/submission/submission.search.resolver.ts b/src/resolver/submission/submission.search.resolver.ts index 393cdde..50ec908 100644 --- a/src/resolver/submission/submission.search.resolver.ts +++ b/src/resolver/submission/submission.search.resolver.ts @@ -34,7 +34,9 @@ export class SubmissionSearchResolver { {}, ) - submissions.forEach(submission => cache.add(cache.getCacheKey(SubmissionEntity.name, submission.id), submission)) + submissions.forEach(submission => { + cache.add(cache.getCacheKey(SubmissionEntity.name, submission.id), submission) + }) return new SubmissionPagerModel( submissions.map(submission => new SubmissionModel(submission)), diff --git a/src/resolver/submission/submission.statistic.resolver.ts b/src/resolver/submission/submission.statistic.resolver.ts index 8e0a886..7349d26 100644 --- a/src/resolver/submission/submission.statistic.resolver.ts +++ b/src/resolver/submission/submission.statistic.resolver.ts @@ -13,7 +13,7 @@ export class SubmissionStatisticResolver { @Query(() => SubmissionStatisticModel) - async getSubmissionStatistic(): Promise { + getSubmissionStatistic(): SubmissionStatisticModel { return new SubmissionStatisticModel() } diff --git a/src/resolver/user/user.resolver.ts b/src/resolver/user/user.resolver.ts index b488af2..ba4d2aa 100644 --- a/src/resolver/user/user.resolver.ts +++ b/src/resolver/user/user.resolver.ts @@ -16,7 +16,7 @@ export class UserResolver { @Query(() => UserModel) @Roles('admin') public async getUserById( - @Args('id', {type: () => ID}) id, + @Args('id', {type: () => ID}) id: string, @Context('cache') cache: ContextCache, ): Promise { const user = await this.userService.findById(id) @@ -33,18 +33,18 @@ export class UserResolver { @Parent() parent: UserModel, @Context('cache') cache: ContextCache, ): Promise { - return await this.returnFieldForSuperuser( + return this.returnFieldForSuperuser( await cache.get(cache.getCacheKey(UserEntity.name, parent.id)), user, c => c.roles ) } - async returnFieldForSuperuser( + returnFieldForSuperuser( parent: UserEntity, user: UserEntity, callback: (user: UserEntity) => T - ): Promise { + ): T { if (user.id !== parent.id && !this.userService.isSuperuser(user)) { throw new Error('No access to roles') } diff --git a/src/resolver/user/user.statistic.resolver.ts b/src/resolver/user/user.statistic.resolver.ts index de0e4a3..fc56186 100644 --- a/src/resolver/user/user.statistic.resolver.ts +++ b/src/resolver/user/user.statistic.resolver.ts @@ -1,5 +1,4 @@ -import { Query, ResolveField, Resolver } from '@nestjs/graphql' -import { GraphQLInt } from 'graphql' +import { Int, Query, ResolveField, Resolver } from '@nestjs/graphql' import { Roles } from '../../decorator/roles.decorator' import { UserStatisticModel } from '../../dto/user/user.statistic.model' import { UserStatisticService } from '../../service/user/user.statistic.service' @@ -12,11 +11,11 @@ export class UserStatisticResolver { } @Query(() => UserStatisticModel) - async getUserStatistic(): Promise { + getUserStatistic(): UserStatisticModel { return new UserStatisticModel() } - @ResolveField('total', () => GraphQLInt) + @ResolveField('total', () => Int) @Roles('admin') getTotal(): Promise { return this.statisticService.getTotal() diff --git a/src/service/auth/auth.service.ts b/src/service/auth/auth.service.ts index 3dce7bc..138e0e0 100644 --- a/src/service/auth/auth.service.ts +++ b/src/service/auth/auth.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@nestjs/common' import { JwtService } from '@nestjs/jwt' import { PinoLogger } from 'nestjs-pino' +import { serializeError } from 'serialize-error' import { AuthJwtModel } from '../../dto/auth/auth.jwt.model' import { UserEntity } from '../../entity/user.entity' import { UserService } from '../user/user.service' @@ -26,7 +27,10 @@ export class AuthService { return user; } } catch (e) { - this.logger.error(`failed to verify user? ${e.message}`) + this.logger.error({ + error: serializeError(e), + username, + },'failed to verify user') } return null;