ability to load submission by id if token is present and cleanup structure

This commit is contained in:
Michael Schramm 2022-01-02 22:31:03 +01:00
parent 3840bb585c
commit 8e87ca5eed
28 changed files with 195 additions and 102 deletions

View File

@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- user confirmation tokens - user confirmation tokens
- email verification - email verification
- idx for fields and logic to have stable order - idx for fields and logic to have stable order
- ability to load submission by id if token is present
### Changed ### Changed

View File

@ -4,7 +4,7 @@ import { AuthJwtModel } from '../../dto/auth/auth.jwt.model'
import { AuthService } from '../../service/auth/auth.service' import { AuthService } from '../../service/auth/auth.service'
@Injectable() @Injectable()
export class AuthLoginResolver { export class AuthLoginMutation {
constructor( constructor(
private readonly auth: AuthService private readonly auth: AuthService
) { ) {

View File

@ -8,7 +8,7 @@ import { SettingService } from '../../service/setting.service'
import { UserCreateService } from '../../service/user/user.create.service' import { UserCreateService } from '../../service/user/user.create.service'
@Injectable() @Injectable()
export class AuthRegisterResolver { export class AuthRegisterMutation {
constructor( constructor(
private readonly createUser: UserCreateService, private readonly createUser: UserCreateService,
private readonly settingService: SettingService, private readonly settingService: SettingService,

View File

@ -1,7 +1,7 @@
import { AuthLoginResolver } from './auth.login.resolver' import { AuthLoginMutation } from './auth.login.mutation'
import { AuthRegisterResolver } from './auth.register.resolver' import { AuthRegisterMutation } from './auth.register.mutation'
export const authServices = [ export const authServices = [
AuthRegisterResolver, AuthRegisterMutation,
AuthLoginResolver, AuthLoginMutation,
] ]

View File

@ -1,5 +1,5 @@
import { Args, Context, Query, Resolver } from '@nestjs/graphql' import { Injectable } from '@nestjs/common'
import { GraphQLInt } from 'graphql' import { Args, Context, Int, Query } from '@nestjs/graphql'
import { Roles } from '../../decorator/roles.decorator' import { Roles } from '../../decorator/roles.decorator'
import { User } from '../../decorator/user.decorator' import { User } from '../../decorator/user.decorator'
import { FormModel } from '../../dto/form/form.model' import { FormModel } from '../../dto/form/form.model'
@ -9,8 +9,8 @@ import { UserEntity } from '../../entity/user.entity'
import { FormService } from '../../service/form/form.service' import { FormService } from '../../service/form/form.service'
import { ContextCache } from '../context.cache' import { ContextCache } from '../context.cache'
@Resolver(() => FormPagerModel) @Injectable()
export class FormSearchResolver { export class FormListQuery {
constructor( constructor(
private readonly formService: FormService, private readonly formService: FormService,
) { ) {
@ -20,8 +20,8 @@ export class FormSearchResolver {
@Roles('user') @Roles('user')
async listForms( async listForms(
@User() user: UserEntity, @User() user: UserEntity,
@Args('start', {type: () => GraphQLInt, defaultValue: 0, nullable: true}) start: number, @Args('start', {type: () => Int, defaultValue: 0, nullable: true}) start: number,
@Args('limit', {type: () => GraphQLInt, defaultValue: 50, nullable: true}) limit: number, @Args('limit', {type: () => Int, defaultValue: 50, nullable: true}) limit: number,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,
): Promise<FormPagerModel> { ): Promise<FormPagerModel> {
const [forms, total] = await this.formService.find( const [forms, total] = await this.formService.find(

View File

@ -1,4 +1,5 @@
import { Args, Context, ID, Query, Resolver } from '@nestjs/graphql' import { Injectable } from '@nestjs/common'
import { Args, Context, ID, Query } from '@nestjs/graphql'
import { User } from '../../decorator/user.decorator' import { User } from '../../decorator/user.decorator'
import { FormModel } from '../../dto/form/form.model' import { FormModel } from '../../dto/form/form.model'
import { FormEntity } from '../../entity/form.entity' import { FormEntity } from '../../entity/form.entity'
@ -6,7 +7,7 @@ import { UserEntity } from '../../entity/user.entity'
import { FormService } from '../../service/form/form.service' import { FormService } from '../../service/form/form.service'
import { ContextCache } from '../context.cache' import { ContextCache } from '../context.cache'
@Resolver(() => FormModel) @Injectable()
export class FormQuery { export class FormQuery {
constructor( constructor(
private readonly formService: FormService, private readonly formService: FormService,

View File

@ -20,19 +20,19 @@ export class FormResolver {
) { ) {
} }
@ResolveField('fields', () => [FormFieldModel]) @ResolveField(() => [FormFieldModel])
async getFields( async fields(
@User() user: UserEntity, @User() user: UserEntity,
@Parent() parent: FormModel, @Parent() parent: FormModel,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,
): Promise<FormFieldModel[]> { ): Promise<FormFieldModel[]> {
const form = await cache.get<FormEntity>(cache.getCacheKey(FormEntity.name, parent.id)) const form = await cache.get<FormEntity>(cache.getCacheKey(FormEntity.name, parent.id))
return form.fields?.map(field => new FormFieldModel(field)) || [] return form.fields?.map(field => new FormFieldModel(field)).sort((a,b) => a.idx - b.idx) || []
} }
@ResolveField('hooks', () => [FormHookModel]) @ResolveField(() => [FormHookModel])
async getHooks( async hooks(
@User() user: UserEntity, @User() user: UserEntity,
@Parent() parent: FormModel, @Parent() parent: FormModel,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,
@ -42,9 +42,9 @@ export class FormResolver {
return form.hooks?.map(hook => new FormHookModel(hook)) || [] return form.hooks?.map(hook => new FormHookModel(hook)) || []
} }
@ResolveField('isLive', () => Boolean) @ResolveField(() => Boolean)
@Roles('admin') @Roles('admin')
async getRoles( async isLive(
@User() user: UserEntity, @User() user: UserEntity,
@Parent() parent: FormModel, @Parent() parent: FormModel,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,
@ -58,9 +58,9 @@ export class FormResolver {
return form.isLive return form.isLive
} }
@ResolveField('notifications', () => [FormNotificationModel]) @ResolveField(() => [FormNotificationModel])
@Roles('admin') @Roles('admin')
async getNotifications( async notifications(
@User() user: UserEntity, @User() user: UserEntity,
@Parent() parent: FormModel, @Parent() parent: FormModel,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,
@ -74,8 +74,8 @@ export class FormResolver {
return form.notifications?.map(notification => new FormNotificationModel(notification)) || [] return form.notifications?.map(notification => new FormNotificationModel(notification)) || []
} }
@ResolveField('design', () => DesignModel) @ResolveField(() => DesignModel)
async getDesign( async design(
@User() user: UserEntity, @User() user: UserEntity,
@Parent() parent: FormModel, @Parent() parent: FormModel,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,
@ -85,8 +85,8 @@ export class FormResolver {
return new DesignModel(form.design) return new DesignModel(form.design)
} }
@ResolveField('startPage', () => PageModel) @ResolveField(() => PageModel)
async getStartPage( async startPage(
@Parent() parent: FormModel, @Parent() parent: FormModel,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,
): Promise<PageModel> { ): Promise<PageModel> {
@ -95,8 +95,8 @@ export class FormResolver {
return new PageModel(form.startPage) return new PageModel(form.startPage)
} }
@ResolveField('endPage', () => PageModel) @ResolveField(() => PageModel)
async getEndPage( async endPage(
@Parent() parent: FormModel, @Parent() parent: FormModel,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,
): Promise<PageModel> { ): Promise<PageModel> {
@ -105,9 +105,9 @@ export class FormResolver {
return new PageModel(form.endPage) return new PageModel(form.endPage)
} }
@ResolveField('admin', () => UserModel, { nullable: true }) @ResolveField(() => UserModel, { nullable: true })
@Roles('admin') @Roles('admin')
async getAdmin( async admin(
@Parent() parent: FormModel, @Parent() parent: FormModel,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,
): Promise<UserModel> { ): Promise<UserModel> {

View File

@ -0,0 +1,11 @@
import { Injectable } from '@nestjs/common'
import { Query } from '@nestjs/graphql'
import { FormStatisticModel } from '../../dto/form/form.statistic.model'
@Injectable()
export class FormStatisticQuery {
@Query(() => FormStatisticModel)
getFormStatistic(): FormStatisticModel {
return new FormStatisticModel()
}
}

View File

@ -1,5 +1,4 @@
import { Query, ResolveField, Resolver } from '@nestjs/graphql' import { Int, ResolveField, Resolver } from '@nestjs/graphql'
import { GraphQLInt } from 'graphql'
import { Roles } from '../../decorator/roles.decorator' import { Roles } from '../../decorator/roles.decorator'
import { FormStatisticModel } from '../../dto/form/form.statistic.model' import { FormStatisticModel } from '../../dto/form/form.statistic.model'
import { FormStatisticService } from '../../service/form/form.statistic.service' import { FormStatisticService } from '../../service/form/form.statistic.service'
@ -11,14 +10,9 @@ export class FormStatisticResolver {
) { ) {
} }
@Query(() => FormStatisticModel) @ResolveField(() => Int)
getFormStatistic(): FormStatisticModel {
return new FormStatisticModel()
}
@ResolveField('total', () => GraphQLInt)
@Roles('admin') @Roles('admin')
getTotal(): Promise<number> { total(): Promise<number> {
return this.statisticService.getTotal() return this.statisticService.getTotal()
} }
} }

View File

@ -1,8 +1,9 @@
import { FormCreateMutation } from './form.create.mutation' import { FormCreateMutation } from './form.create.mutation'
import { FormDeleteMutation } from './form.delete.mutation' import { FormDeleteMutation } from './form.delete.mutation'
import { FormListQuery } from './form.list.query'
import { FormQuery } from './form.query' import { FormQuery } from './form.query'
import { FormResolver } from './form.resolver' import { FormResolver } from './form.resolver'
import { FormSearchResolver } from './form.search.resolver' import { FormStatisticQuery } from './form.statistic.query'
import { FormStatisticResolver } from './form.statistic.resolver' import { FormStatisticResolver } from './form.statistic.resolver'
import { FormUpdateMutation } from './form.update.mutation' import { FormUpdateMutation } from './form.update.mutation'
@ -11,7 +12,8 @@ export const formResolvers = [
FormDeleteMutation, FormDeleteMutation,
FormQuery, FormQuery,
FormResolver, FormResolver,
FormSearchResolver, FormListQuery,
FormStatisticQuery,
FormStatisticResolver, FormStatisticResolver,
FormUpdateMutation, FormUpdateMutation,
] ]

View File

@ -1,7 +1,7 @@
import { ProfileResolver } from './profile.resolver' import { ProfileQuery } from './profile.query'
import { ProfileUpdateMutation } from './profile.update.mutation' import { ProfileUpdateMutation } from './profile.update.mutation'
export const profileResolvers = [ export const profileResolvers = [
ProfileResolver, ProfileQuery,
ProfileUpdateMutation, ProfileUpdateMutation,
] ]

View File

@ -1,3 +1,4 @@
import { Injectable } from '@nestjs/common'
import { Context, Query } from '@nestjs/graphql' import { Context, Query } from '@nestjs/graphql'
import { Roles } from '../../decorator/roles.decorator' import { Roles } from '../../decorator/roles.decorator'
import { User } from '../../decorator/user.decorator' import { User } from '../../decorator/user.decorator'
@ -5,7 +6,8 @@ import { ProfileModel } from '../../dto/profile/profile.model'
import { UserEntity } from '../../entity/user.entity' import { UserEntity } from '../../entity/user.entity'
import { ContextCache } from '../context.cache' import { ContextCache } from '../context.cache'
export class ProfileResolver { @Injectable()
export class ProfileQuery {
@Query(() => ProfileModel) @Query(() => ProfileModel)
@Roles('user') @Roles('user')
public me( public me(

View File

@ -1,7 +1,7 @@
import { SettingMutation } from './setting.mutation' import { SettingMutation } from './setting.mutation'
import { SettingResolver } from './setting.resolver' import { SettingQuery } from './setting.query'
export const settingsResolvers = [ export const settingsResolvers = [
SettingResolver, SettingQuery,
SettingMutation, SettingMutation,
] ]

View File

@ -8,7 +8,7 @@ import { UserEntity } from '../../entity/user.entity'
import { SettingService } from '../../service/setting.service' import { SettingService } from '../../service/setting.service'
@Injectable() @Injectable()
export class SettingResolver { export class SettingQuery {
constructor( constructor(
private readonly settingService: SettingService, private readonly settingService: SettingService,
) { ) {

View File

@ -1,17 +1,21 @@
import { SubmissionFieldResolver } from './submission.field.resolver' import { SubmissionFieldResolver } from './submission.field.resolver'
import { SubmissionListQuery } from './submission.list.query'
import { SubmissionProgressResolver } from './submission.progress.resolver' import { SubmissionProgressResolver } from './submission.progress.resolver'
import { SubmissionQuery } from './submission.query'
import { SubmissionResolver } from './submission.resolver' import { SubmissionResolver } from './submission.resolver'
import { SubmissionSearchResolver } from './submission.search.resolver'
import { SubmissionSetFieldMutation } from './submission.set.field.mutation' import { SubmissionSetFieldMutation } from './submission.set.field.mutation'
import { SubmissionStartMutation } from './submission.start.mutation' import { SubmissionStartMutation } from './submission.start.mutation'
import { SubmissionStatisticQuery } from './submission.statistic.query'
import { SubmissionStatisticResolver } from './submission.statistic.resolver' import { SubmissionStatisticResolver } from './submission.statistic.resolver'
export const submissionResolvers = [ export const submissionResolvers = [
SubmissionFieldResolver, SubmissionFieldResolver,
SubmissionListQuery,
SubmissionProgressResolver, SubmissionProgressResolver,
SubmissionQuery,
SubmissionResolver, SubmissionResolver,
SubmissionSearchResolver,
SubmissionSetFieldMutation, SubmissionSetFieldMutation,
SubmissionStartMutation, SubmissionStartMutation,
SubmissionStatisticQuery,
SubmissionStatisticResolver, SubmissionStatisticResolver,
] ]

View File

@ -13,8 +13,8 @@ export class SubmissionFieldResolver {
) { ) {
} }
@ResolveField('field', () => FormFieldModel, { nullable: true }) @ResolveField(() => FormFieldModel, { nullable: true })
async getFields( async field(
@Parent() parent: SubmissionFieldModel, @Parent() parent: SubmissionFieldModel,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,
): Promise<FormFieldModel> { ): Promise<FormFieldModel> {

View File

@ -1,5 +1,5 @@
import { Args, Context, ID, Query, Resolver } from '@nestjs/graphql' import { Injectable } from '@nestjs/common'
import { GraphQLInt } from 'graphql' import { Args, Context, ID, Int, Query } from '@nestjs/graphql'
import { User } from '../../decorator/user.decorator' import { User } from '../../decorator/user.decorator'
import { SubmissionModel } from '../../dto/submission/submission.model' import { SubmissionModel } from '../../dto/submission/submission.model'
import { SubmissionPagerModel } from '../../dto/submission/submission.pager.model' import { SubmissionPagerModel } from '../../dto/submission/submission.pager.model'
@ -9,8 +9,8 @@ import { FormService } from '../../service/form/form.service'
import { SubmissionService } from '../../service/submission/submission.service' import { SubmissionService } from '../../service/submission/submission.service'
import { ContextCache } from '../context.cache' import { ContextCache } from '../context.cache'
@Resolver(() => SubmissionPagerModel) @Injectable()
export class SubmissionSearchResolver { export class SubmissionListQuery {
constructor( constructor(
private readonly formService: FormService, private readonly formService: FormService,
private readonly submissionService: SubmissionService, private readonly submissionService: SubmissionService,
@ -21,8 +21,8 @@ export class SubmissionSearchResolver {
async listSubmissions( async listSubmissions(
@User() user: UserEntity, @User() user: UserEntity,
@Args('form', {type: () => ID}) id: string, @Args('form', {type: () => ID}) id: string,
@Args('start', {type: () => GraphQLInt, defaultValue: 0, nullable: true}) start: number, @Args('start', {type: () => Int, defaultValue: 0, nullable: true}) start: number,
@Args('limit', {type: () => GraphQLInt, defaultValue: 50, nullable: true}) limit: number, @Args('limit', {type: () => Int, defaultValue: 50, nullable: true}) limit: number,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,
): Promise<SubmissionPagerModel> { ): Promise<SubmissionPagerModel> {
const form = await this.formService.findById(id) const form = await this.formService.findById(id)

View File

@ -0,0 +1,41 @@
import { Injectable } from '@nestjs/common'
import { Args, Context, ID, Query } from '@nestjs/graphql'
import { User } from '../../decorator/user.decorator'
import { SubmissionModel } from '../../dto/submission/submission.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 { SubmissionTokenService } from '../../service/submission/submission.token.service'
import { ContextCache } from '../context.cache'
@Injectable()
export class SubmissionQuery {
constructor(
private readonly formService: FormService,
private readonly submissionService: SubmissionService,
private readonly tokenService: SubmissionTokenService,
) {
}
@Query(() => SubmissionModel)
async getSubmissionById(
@User() user: UserEntity,
@Args('id', {type: () => ID}) id: string,
@Args('token', {nullable: true}) token: string,
@Context('cache') cache: ContextCache,
): Promise<SubmissionModel> {
const submission = await this.submissionService.findById(id)
if (
!await this.tokenService.verify(token, submission.tokenHash)
&& !this.formService.isAdmin(submission.form, user)
) {
throw new Error('invalid form')
}
cache.add(cache.getCacheKey(SubmissionEntity.name, submission.id), submission)
return new SubmissionModel(submission)
}
}

View File

@ -9,8 +9,8 @@ import { ContextCache } from '../context.cache'
@Resolver(() => SubmissionModel) @Resolver(() => SubmissionModel)
export class SubmissionResolver { export class SubmissionResolver {
@ResolveField('fields', () => [SubmissionFieldModel]) @ResolveField(() => [SubmissionFieldModel])
async getFields( async fields(
@User() user: UserEntity, @User() user: UserEntity,
@Parent() parent: SubmissionModel, @Parent() parent: SubmissionModel,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,

View File

@ -0,0 +1,11 @@
import { Injectable } from '@nestjs/common'
import { Query } from '@nestjs/graphql'
import { SubmissionStatisticModel } from '../../dto/submission/submission.statistic.model'
@Injectable()
export class SubmissionStatisticQuery {
@Query(() => SubmissionStatisticModel)
getSubmissionStatistic(): SubmissionStatisticModel {
return new SubmissionStatisticModel()
}
}

View File

@ -1,4 +1,4 @@
import { Query, ResolveField, Resolver } from '@nestjs/graphql' import { ResolveField, Resolver } from '@nestjs/graphql'
import { GraphQLInt } from 'graphql' import { GraphQLInt } from 'graphql'
import { Roles } from '../../decorator/roles.decorator' import { Roles } from '../../decorator/roles.decorator'
import { SubmissionStatisticModel } from '../../dto/submission/submission.statistic.model' import { SubmissionStatisticModel } from '../../dto/submission/submission.statistic.model'
@ -11,15 +11,9 @@ export class SubmissionStatisticResolver {
) { ) {
} }
@ResolveField(() => GraphQLInt)
@Query(() => SubmissionStatisticModel)
getSubmissionStatistic(): SubmissionStatisticModel {
return new SubmissionStatisticModel()
}
@ResolveField('total', () => GraphQLInt)
@Roles('admin') @Roles('admin')
getTotal(): Promise<number> { total(): Promise<number> {
return this.statisticService.getTotal() return this.statisticService.getTotal()
} }
} }

View File

@ -1,13 +1,17 @@
import { UserDeleteMutation } from './user.delete.mutation' import { UserDeleteMutation } from './user.delete.mutation'
import { UserListQuery } from './user.list.query'
import { UserQuery } from './user.query'
import { UserResolver } from './user.resolver' import { UserResolver } from './user.resolver'
import { UserSearchResolver } from './user.search.resolver' import { UserStatisticQuery } from './user.statistic.query'
import { UserStatisticResolver } from './user.statistic.resolver' import { UserStatisticResolver } from './user.statistic.resolver'
import { UserUpdateMutation } from './user.update.mutation' import { UserUpdateMutation } from './user.update.mutation'
export const userResolvers = [ export const userResolvers = [
UserDeleteMutation, UserDeleteMutation,
UserListQuery,
UserQuery,
UserResolver, UserResolver,
UserSearchResolver, UserStatisticQuery,
UserStatisticResolver, UserStatisticResolver,
UserUpdateMutation, UserUpdateMutation,
] ]

View File

@ -1,5 +1,4 @@
import { Args, Context, Query, Resolver } from '@nestjs/graphql' import { Args, Context, Int, Query, Resolver } from '@nestjs/graphql'
import { GraphQLInt } from 'graphql'
import { Roles } from '../../decorator/roles.decorator' import { Roles } from '../../decorator/roles.decorator'
import { UserModel } from '../../dto/user/user.model' import { UserModel } from '../../dto/user/user.model'
import { UserPagerModel } from '../../dto/user/user.pager.model' import { UserPagerModel } from '../../dto/user/user.pager.model'
@ -8,7 +7,7 @@ import { UserService } from '../../service/user/user.service'
import { ContextCache } from '../context.cache' import { ContextCache } from '../context.cache'
@Resolver(() => UserPagerModel) @Resolver(() => UserPagerModel)
export class UserSearchResolver { export class UserListQuery {
constructor( constructor(
private readonly userService: UserService, private readonly userService: UserService,
) { ) {
@ -17,8 +16,8 @@ export class UserSearchResolver {
@Query(() => UserPagerModel) @Query(() => UserPagerModel)
@Roles('superuser') @Roles('superuser')
async listUsers( async listUsers(
@Args('start', {type: () => GraphQLInt, defaultValue: 0, nullable: true}) start: number, @Args('start', {type: () => Int, defaultValue: 0, nullable: true}) start: number,
@Args('limit', {type: () => GraphQLInt, defaultValue: 50, nullable: true}) limit: number, @Args('limit', {type: () => Int, defaultValue: 50, nullable: true}) limit: number,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,
): Promise<UserPagerModel> { ): Promise<UserPagerModel> {
const [entities, total] = await this.userService.find(start, limit) const [entities, total] = await this.userService.find(start, limit)

View File

@ -0,0 +1,28 @@
import { Injectable } from '@nestjs/common'
import { Args, Context, ID, Query } from '@nestjs/graphql'
import { Roles } from '../../decorator/roles.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'
@Injectable()
export class UserQuery {
constructor(
private readonly userService: UserService,
) {
}
@Query(() => UserModel)
@Roles('admin')
public async getUserById(
@Args('id', {type: () => ID}) id: string,
@Context('cache') cache: ContextCache,
): Promise<UserModel> {
const user = await this.userService.findById(id)
cache.add(cache.getCacheKey(UserEntity.name, user.id), user)
return new UserModel(user)
}
}

View File

@ -1,4 +1,4 @@
import { Args, Context, ID, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql' import { Context, Parent, ResolveField, Resolver } from '@nestjs/graphql'
import { Roles } from '../../decorator/roles.decorator' import { Roles } from '../../decorator/roles.decorator'
import { User } from '../../decorator/user.decorator' import { User } from '../../decorator/user.decorator'
import { UserModel } from '../../dto/user/user.model' import { UserModel } from '../../dto/user/user.model'
@ -13,22 +13,9 @@ export class UserResolver {
) { ) {
} }
@Query(() => UserModel) @ResolveField(() => [String])
@Roles('admin')
public async getUserById(
@Args('id', {type: () => ID}) id: string,
@Context('cache') cache: ContextCache,
): Promise<UserModel> {
const user = await this.userService.findById(id)
cache.add(cache.getCacheKey(UserEntity.name, user.id), user)
return new UserModel(user)
}
@ResolveField('roles', () => [String])
@Roles('user') @Roles('user')
async getRoles( async roles(
@User() user: UserEntity, @User() user: UserEntity,
@Parent() parent: UserModel, @Parent() parent: UserModel,
@Context('cache') cache: ContextCache, @Context('cache') cache: ContextCache,
@ -40,7 +27,7 @@ export class UserResolver {
) )
} }
returnFieldForSuperuser<T>( private returnFieldForSuperuser<T>(
parent: UserEntity, parent: UserEntity,
user: UserEntity, user: UserEntity,
callback: (user: UserEntity) => T callback: (user: UserEntity) => T

View File

@ -0,0 +1,11 @@
import { Injectable } from '@nestjs/common'
import { Query } from '@nestjs/graphql'
import { UserStatisticModel } from '../../dto/user/user.statistic.model'
@Injectable()
export class UserStatisticQuery {
@Query(() => UserStatisticModel)
getUserStatistic(): UserStatisticModel {
return new UserStatisticModel()
}
}

View File

@ -1,4 +1,4 @@
import { Int, Query, ResolveField, Resolver } from '@nestjs/graphql' import { Int, ResolveField, Resolver } from '@nestjs/graphql'
import { Roles } from '../../decorator/roles.decorator' import { Roles } from '../../decorator/roles.decorator'
import { UserStatisticModel } from '../../dto/user/user.statistic.model' import { UserStatisticModel } from '../../dto/user/user.statistic.model'
import { UserStatisticService } from '../../service/user/user.statistic.service' import { UserStatisticService } from '../../service/user/user.statistic.service'
@ -10,14 +10,9 @@ export class UserStatisticResolver {
) { ) {
} }
@Query(() => UserStatisticModel) @ResolveField(() => Int)
getUserStatistic(): UserStatisticModel {
return new UserStatisticModel()
}
@ResolveField('total', () => Int)
@Roles('admin') @Roles('admin')
getTotal(): Promise<number> { total(): Promise<number> {
return this.statisticService.getTotal() return this.statisticService.getTotal()
} }
} }

View File

@ -43,7 +43,15 @@ export class SubmissionService {
} }
async findById(id: string): Promise<SubmissionEntity> { async findById(id: string): Promise<SubmissionEntity> {
const submission = await this.submissionRepository.findOne(id); const submission = await this.submissionRepository.findOne(
id,
{
relations: [
'form',
'form.admin',
],
}
);
if (!submission) { if (!submission) {
throw new Error('no form found') throw new Error('no form found')