add user confirmation, add validation for submission data
This commit is contained in:
parent
29a74ea9c9
commit
1f413c2949
@ -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',
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -64,7 +64,7 @@ export const imports = [
|
||||
JwtModule.registerAsync({
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
useFactory: async (configService: ConfigService): Promise<JwtModuleOptions> => ({
|
||||
useFactory: (configService: ConfigService): JwtModuleOptions => ({
|
||||
secret: configService.get<string>('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<string>('MAILER_URI', 'smtp://localhost:1025'),
|
||||
defaults: {
|
||||
from: configService.get<string>('MAILER_FROM', 'OhMyForm <no-reply@localhost>'),
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -59,7 +59,7 @@ export class UserCommand {
|
||||
@Command({
|
||||
command: 'activate <username>',
|
||||
})
|
||||
async activate(username: string): Promise<void> {
|
||||
activate(username: string): void {
|
||||
console.log(`activate user ${username}`)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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_]+$/,
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ export class AuthRegisterResolver {
|
||||
async authRegister(
|
||||
@Args({ name: 'user' }) data: UserCreateInput,
|
||||
): Promise<AuthJwtModel> {
|
||||
if (await this.settingService.isTrue('SIGNUP_DISABLED')) {
|
||||
if (this.settingService.isTrue('SIGNUP_DISABLED')) {
|
||||
throw new Error('signup disabled')
|
||||
}
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ export class FormStatisticResolver {
|
||||
}
|
||||
|
||||
@Query(() => FormStatisticModel)
|
||||
async getFormStatistic(): Promise<FormStatisticModel> {
|
||||
getFormStatistic(): FormStatisticModel {
|
||||
return new FormStatisticModel()
|
||||
}
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ export class SettingResolver {
|
||||
|
||||
@Query(() => SettingPagerModel)
|
||||
@Roles('superuser')
|
||||
async getSettings(): Promise<SettingPagerModel> {
|
||||
getSettings(): SettingPagerModel {
|
||||
// TODO https://github.com/ohmyform/api/issues/3
|
||||
return new SettingPagerModel(
|
||||
[],
|
||||
|
||||
@ -4,7 +4,7 @@ import { StatusModel } from '../dto/status.model'
|
||||
@Resolver(() => StatusModel)
|
||||
export class StatusResolver {
|
||||
@Query(() => StatusModel)
|
||||
async status(): Promise<StatusModel> {
|
||||
status(): StatusModel {
|
||||
return new StatusModel({
|
||||
version: process.env.version || 'dev',
|
||||
})
|
||||
|
||||
@ -18,9 +18,16 @@ export class SubmissionFieldResolver {
|
||||
@Parent() parent: SubmissionFieldModel,
|
||||
@Context('cache') cache: ContextCache,
|
||||
): Promise<FormFieldModel> {
|
||||
const submissionField = await cache.get<SubmissionFieldEntity>(cache.getCacheKey(SubmissionFieldEntity.name, parent.id))
|
||||
const submissionField = await cache.get<SubmissionFieldEntity>(
|
||||
cache.getCacheKey(SubmissionFieldEntity.name, parent.id)
|
||||
)
|
||||
|
||||
const field = await cache.get<FormFieldEntity>(cache.getCacheKey(FormFieldEntity.name, submissionField.fieldId), () => this.formFieldService.findById(submissionField.fieldId, submissionField.field))
|
||||
const field = await cache.get<FormFieldEntity>(
|
||||
cache.getCacheKey(
|
||||
FormFieldEntity.name,
|
||||
submissionField.fieldId),
|
||||
() => this.formFieldService.findById(submissionField.fieldId, submissionField.field)
|
||||
)
|
||||
|
||||
if (!field) {
|
||||
return null
|
||||
|
||||
@ -15,7 +15,9 @@ export class SubmissionResolver {
|
||||
@Parent() parent: SubmissionModel,
|
||||
@Context('cache') cache: ContextCache,
|
||||
): Promise<SubmissionFieldModel[]> {
|
||||
const submission = await cache.get<SubmissionEntity>(cache.getCacheKey(SubmissionEntity.name, parent.id))
|
||||
const submission = await cache.get<SubmissionEntity>(
|
||||
cache.getCacheKey(SubmissionEntity.name, parent.id)
|
||||
)
|
||||
|
||||
return submission.fields.map(field => {
|
||||
cache.add(cache.getCacheKey(SubmissionFieldEntity.name, field.id), field)
|
||||
|
||||
@ -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)),
|
||||
|
||||
@ -13,7 +13,7 @@ export class SubmissionStatisticResolver {
|
||||
|
||||
|
||||
@Query(() => SubmissionStatisticModel)
|
||||
async getSubmissionStatistic(): Promise<SubmissionStatisticModel> {
|
||||
getSubmissionStatistic(): SubmissionStatisticModel {
|
||||
return new SubmissionStatisticModel()
|
||||
}
|
||||
|
||||
|
||||
@ -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<UserModel> {
|
||||
const user = await this.userService.findById(id)
|
||||
@ -33,18 +33,18 @@ export class UserResolver {
|
||||
@Parent() parent: UserModel,
|
||||
@Context('cache') cache: ContextCache,
|
||||
): Promise<string[]> {
|
||||
return await this.returnFieldForSuperuser(
|
||||
return this.returnFieldForSuperuser(
|
||||
await cache.get<UserEntity>(cache.getCacheKey(UserEntity.name, parent.id)),
|
||||
user,
|
||||
c => c.roles
|
||||
)
|
||||
}
|
||||
|
||||
async returnFieldForSuperuser<T>(
|
||||
returnFieldForSuperuser<T>(
|
||||
parent: UserEntity,
|
||||
user: UserEntity,
|
||||
callback: (user: UserEntity) => T
|
||||
): Promise<T> {
|
||||
): T {
|
||||
if (user.id !== parent.id && !this.userService.isSuperuser(user)) {
|
||||
throw new Error('No access to roles')
|
||||
}
|
||||
|
||||
@ -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<UserStatisticModel> {
|
||||
getUserStatistic(): UserStatisticModel {
|
||||
return new UserStatisticModel()
|
||||
}
|
||||
|
||||
@ResolveField('total', () => GraphQLInt)
|
||||
@ResolveField('total', () => Int)
|
||||
@Roles('admin')
|
||||
getTotal(): Promise<number> {
|
||||
return this.statisticService.getTotal()
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user