add missing resolvers

This commit is contained in:
Michael Schramm 2020-05-31 23:19:40 +02:00
parent eda8a3920c
commit cbd4691704
44 changed files with 625 additions and 51 deletions

11
src/dto/deleted.model.ts Normal file
View File

@ -0,0 +1,11 @@
import { Field, ObjectType } from '@nestjs/graphql';
@ObjectType('Deleted')
export class DeletedModel {
@Field()
id: string
constructor(id: string) {
this.id = id
}
}

View File

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

View File

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

View File

@ -0,0 +1,25 @@
import { Field, ID, InputType } from '@nestjs/graphql';
@InputType()
export class ProfileUpdateInput {
@Field(() => ID)
readonly id: string
@Field({ nullable: true })
readonly username: string
@Field({ nullable: true })
readonly email: string
@Field({ nullable: true })
readonly firstName: string
@Field({ nullable: true })
readonly lastName: string
@Field({ nullable: true })
readonly password: string
@Field({ nullable: true })
readonly language: string
}

View File

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

View File

@ -0,0 +1,25 @@
import { Field, ObjectType } from '@nestjs/graphql';
import { GraphQLInt } from 'graphql';
import { UserModel } from './user.model';
@ObjectType('PagerUser')
export class PagerUserModel {
@Field(() => [UserModel])
entries: UserModel[]
@Field(() => GraphQLInt)
total: number
@Field(() => GraphQLInt)
limit: number
@Field(() => GraphQLInt)
start: number
constructor(entries: UserModel[], total: number, limit: number, start: number) {
this.entries = entries
this.total = total
this.limit = limit
this.start = start
}
}

View File

@ -6,6 +6,9 @@ export class UserModel {
@Field(() => ID)
readonly id: string
@Field()
readonly verifiedEmail: boolean
@Field()
readonly username: string
@ -15,12 +18,18 @@ export class UserModel {
@Field()
readonly language: string
@Field()
@Field({ nullable: true })
readonly firstName?: string
@Field()
@Field({ nullable: true })
readonly lastName?: string
@Field()
readonly created: Date
@Field({ nullable: true })
readonly lastModified: Date
constructor(user: UserDocument) {
this.id = user.id
this.username = user.username
@ -29,5 +38,10 @@ export class UserModel {
this.language = user.language
this.firstName = user.firstName
this.lastName = user.lastName
this.verifiedEmail = !user.token
this.created = user.created
this.lastModified = user.lastModified
}
}

View File

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

View File

@ -0,0 +1,29 @@
import { Field, ID, InputType } from '@nestjs/graphql';
import { GraphQLString } from 'graphql';
@InputType()
export class UserUpdateInput {
@Field(() => ID)
readonly id: string
@Field({ nullable: true })
readonly username: string
@Field({ nullable: true })
readonly email: string
@Field({ nullable: true })
readonly firstName: string
@Field({ nullable: true })
readonly lastName: string
@Field({ nullable: true })
readonly password: string
@Field(() => [GraphQLString], { nullable: true })
readonly roles: string[]
@Field({ nullable: true })
readonly language: string
}

View File

@ -1,5 +1,6 @@
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';
@ -16,7 +17,11 @@ export class ContextCache {
[id: string]: SubmissionDocument,
} = {}
private formField: {
private submissionFields: {
[id: string]: SubmissionFieldDocument,
} = {}
private formFields: {
[id: string]: FormFieldDocument,
} = {}
@ -44,11 +49,19 @@ export class ContextCache {
return this.submissions[id]
}
public addFormField(formField: FormFieldDocument) {
this.formField[formField.id] = formField
public addFormField(field: FormFieldDocument) {
this.formFields[field.id] = field
}
public async getFormField(id: any): Promise<FormFieldDocument> {
return this.formField[id]
return this.formFields[id]
}
public addSubmissionField(field: SubmissionFieldDocument) {
this.submissionFields[field.id] = field
}
public async getSubmissionField(id: any): Promise<SubmissionFieldDocument> {
return this.submissionFields[id]
}
}

View File

@ -2,7 +2,7 @@ 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 { FormModel } from '../../dto/form/form.model';
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';
@ -15,7 +15,7 @@ export class FormDeleteMutation {
) {
}
@Mutation(() => FormModel)
@Mutation(() => DeletedModel)
@Roles('admin')
async deleteForm(
@User() user: UserDocument,
@ -29,6 +29,6 @@ export class FormDeleteMutation {
await this.deleteService.delete(id)
return new FormModel(form)
return new DeletedModel(id)
}
}

View File

@ -0,0 +1,24 @@
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 {
constructor(
private readonly statisticService: FormStatisticService,
) {
}
@Query(() => FormStatisticModel)
async getFormStatistic(): Promise<FormStatisticModel> {
return new FormStatisticModel()
}
@ResolveField('total', () => GraphQLInt)
@Roles('admin')
getTotal(): Promise<number> {
return this.statisticService.getTotal()
}
}

View File

@ -24,13 +24,13 @@ export class FormUpdateMutation {
@Args({ name: 'form', type: () => FormUpdateInput }) input: FormUpdateInput,
@Context('cache') cache: ContextCache,
): Promise<FormModel> {
let form = await this.formService.findById(input.id)
const form = await this.formService.findById(input.id)
if (!form.isLive && !await this.formService.isAdmin(form, user)) {
throw new Error('invalid form')
}
form = await this.updateService.update(form, input)
await this.updateService.update(form, input)
cache.addForm(form)

View File

@ -2,12 +2,14 @@ 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 = [
FormResolver,
FormSearchResolver,
FormCreateMutation,
FormDeleteMutation,
FormResolver,
FormSearchResolver,
FormStatisticResolver,
FormUpdateMutation,
]

View File

@ -1,6 +1,6 @@
import { authServices } from './auth';
import { formResolvers } from './form';
import { myResolvers } from './me';
import { profileResolvers } from './profile';
import { StatusResolver } from './status.resolver';
import { submissionResolvers } from './submission';
import { userResolvers } from './user';
@ -9,7 +9,7 @@ export const resolvers = [
StatusResolver,
...userResolvers,
...authServices,
...myResolvers,
...profileResolvers,
...formResolvers,
...submissionResolvers,
]

View File

@ -1,5 +0,0 @@
import { ProfileResolver } from './profile.resolver';
export const myResolvers = [
ProfileResolver,
]

View File

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

View File

@ -1,19 +1,19 @@
import { Context, Query } from '@nestjs/graphql';
import { Roles } from '../../decorator/roles.decorator';
import { User } from '../../decorator/user.decorator';
import { OwnUserModel } from '../../dto/user/own.user.model';
import { ProfileModel } from '../../dto/profile/profile.model';
import { UserDocument } from '../../schema/user.schema';
import { ContextCache } from '../context.cache';
export class ProfileResolver {
@Query(() => OwnUserModel)
@Query(() => ProfileModel)
@Roles('user')
async me(
@User() user: UserDocument,
@Context('cache') cache: ContextCache,
): Promise<OwnUserModel> {
): Promise<ProfileModel> {
cache.addUser(user)
return new OwnUserModel(user)
return new ProfileModel(user)
}
}

View File

@ -0,0 +1,29 @@
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';
@Injectable()
export class ProfileUpdateMutation {
constructor(
private readonly updateService: ProfileUpdateService,
) {
}
@Mutation(() => ProfileModel)
async updateProfile(
@User() user: UserDocument,
@Args({ name: 'user', type: () => ProfileUpdateInput }) input: ProfileUpdateInput,
@Context('cache') cache: ContextCache,
): Promise<ProfileModel> {
await this.updateService.update(user, input)
cache.addUser(user)
return new ProfileModel(user)
}
}

View File

@ -1,13 +1,17 @@
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,
SubmissionProgressResolver,
SubmissionResolver,
SubmissionSearchResolver,
SubmissionSetFieldMutation,
SubmissionStartMutation,
SubmissionSearchResolver,
SubmissionStatisticResolver,
]

View File

@ -0,0 +1,25 @@
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';
@Resolver(() => SubmissionFieldModel)
export class SubmissionFieldResolver {
@ResolveField('field', () => FormFieldModel, { nullable: true })
async getFields(
@Parent() parent: SubmissionFieldModel,
@Context('cache') cache: ContextCache,
): Promise<FormFieldModel> {
const submissionField = await cache.getSubmissionField(parent.id)
console.log(submissionField.field)
const field = await cache.getFormField(submissionField.field)
if (!field) {
return null
}
return new FormFieldModel(field)
}
}

View File

@ -25,6 +25,9 @@ export class SubmissionResolver {
cache.addFormField(field)
})
return submission.fields.map(field => new SubmissionFieldModel(field))
return submission.fields.map(field => {
cache.addSubmissionField(field)
return new SubmissionFieldModel(field)
})
}
}

View File

@ -0,0 +1,25 @@
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 {
constructor(
private readonly statisticService: SubmissionStatisticService,
) {
}
@Query(() => SubmissionStatisticModel)
async getSubmissionStatistic(): Promise<SubmissionStatisticModel> {
return new SubmissionStatisticModel()
}
@ResolveField('total', () => GraphQLInt)
@Roles('admin')
getTotal(): Promise<number> {
return this.statisticService.getTotal()
}
}

View File

@ -1,5 +1,13 @@
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,
UserResolver,
UserSearchResolver,
UserStatisticResolver,
UserUpdateMutation,
]

View File

@ -0,0 +1,30 @@
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';
@Injectable()
export class UserDeleteMutation {
constructor(
private readonly deleteService: UserDeleteService,
) {
}
@Mutation(() => DeletedModel)
@Roles('admin')
async deleteUser(
@User() auth: UserDocument,
@Args({ name: 'id', type: () => ID}) id: string,
): Promise<DeletedModel> {
if (auth.id === id) {
throw new Error('cannot delete your own user')
}
await this.deleteService.delete(id)
return new DeletedModel(id)
}
}

View File

@ -1,7 +1,8 @@
import { Args, Context, GraphQLExecutionContext, ID, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql';
import { rolesType } from '../../config/roles';
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';
@ -26,11 +27,24 @@ export class UserResolver {
}
@ResolveField('roles', () => [String])
@Roles('superuser')
@Roles('user')
async getRoles(
@Parent() user: UserModel,
@User() user: UserDocument,
@Parent() parent: UserModel,
@Context('cache') cache: ContextCache,
): Promise<string[]> {
return (await cache.getUser(user.id)).roles
return await this.returnFieldForSuperuser(
await cache.getUser(parent.id),
user,
c => c.roles
)
}
async returnFieldForSuperuser<T>(parent: UserDocument, user: UserDocument, callback: (user: UserDocument) => T): Promise<T> {
if (user.id !== parent.id && !await this.userService.isSuperuser(user)) {
throw new Error('No access to roles')
}
return callback(parent)
}
}

View File

@ -0,0 +1,35 @@
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';
@Resolver(() => PagerUserModel)
export class UserSearchResolver {
constructor(
private readonly userService: UserService,
) {
}
@Query(() => PagerUserModel)
@Roles('superuser')
async listUsers(
@Args('start', {type: () => GraphQLInt, defaultValue: 0, nullable: true}) start,
@Args('limit', {type: () => GraphQLInt, defaultValue: 50, nullable: true}) limit,
@Context('cache') cache: ContextCache,
): Promise<PagerUserModel> {
const [entities, total] = await this.userService.find(start, limit)
return new PagerUserModel(
entities.map(entity => {
cache.addUser(entity)
return new UserModel(entity)
}),
total,
limit,
start,
)
}
}

View File

@ -0,0 +1,24 @@
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 {
constructor(
private readonly statisticService: UserStatisticService,
) {
}
@Query(() => UserStatisticModel)
async getUserStatistic(): Promise<UserStatisticModel> {
return new UserStatisticModel()
}
@ResolveField('total', () => GraphQLInt)
@Roles('admin')
getTotal(): Promise<number> {
return this.statisticService.getTotal()
}
}

View File

@ -0,0 +1,39 @@
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';
@Injectable()
export class UserUpdateMutation {
constructor(
private readonly updateService: UserUpdateService,
private readonly userService: UserService,
) {
}
@Mutation(() => UserModel)
@Roles('superuser')
async updateUser(
@User() auth: UserDocument,
@Args({ name: 'user', type: () => UserUpdateInput }) input: UserUpdateInput,
@Context('cache') cache: ContextCache,
): Promise<UserModel> {
if (auth.id === input.id) {
throw new Error('cannot update your own user')
}
const user = await this.userService.findById(input.id)
await this.updateService.update(user, input)
cache.addUser(user)
return new UserModel(user)
}
}

View File

@ -2,16 +2,20 @@ 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';
@Injectable()
export class FormDeleteService {
constructor(
@InjectModel(FormSchemaName) private formModel: Model<FormDocument>,
@InjectModel(SubmissionSchemaName) private readonly submissionModel: Model<SubmissionDocument>,
) {
}
async delete(id: string): Promise<void> {
// TODO
throw new Error('form.delete not yet implemented')
const form = await this.formModel.findByIdAndDelete(id).exec()
await this.submissionModel.deleteMany({
form
}).exec()
}
}

View File

@ -28,15 +28,14 @@ export class FormService {
}
}
const qb = this.formModel.find(conditions)
// TODO apply restrictions based on user!
return [
await qb.sort(sort)
await this.formModel
.find(conditions)
.sort(sort)
.skip(start)
.limit(limit),
await qb.count()
await this.formModel
.countDocuments(conditions)
]
}

View File

@ -0,0 +1,14 @@
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { FormDocument, FormSchemaName } from '../../schema/form.schema';
export class FormStatisticService {
constructor(
@InjectModel(FormSchemaName) private formModel: Model<FormDocument>,
) {
}
async getTotal(): Promise<number> {
return await this.formModel.estimatedDocumentCount();
}
}

View File

@ -1,11 +1,13 @@
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 = [
FormService,
FormCreateService,
FormUpdateService,
FormDeleteService,
FormService,
FormStatisticService,
FormUpdateService,
]

View File

@ -6,11 +6,13 @@ import { PinoLogger } from 'nestjs-pino/dist';
import { authServices } from './auth';
import { formServices } from './form';
import { MailService } from './mail.service';
import { profileServices } from './profile';
import { submissionServices } from './submission';
import { userServices } from './user';
export const services = [
...userServices,
...profileServices,
...formServices,
...authServices,
...submissionServices,

View File

@ -0,0 +1,5 @@
import { ProfileUpdateService } from './profile.update.service';
export const profileServices = [
ProfileUpdateService,
]

View File

@ -0,0 +1,38 @@
import { Injectable } from '@nestjs/common';
import { ProfileUpdateInput } from '../../dto/profile/profile.update.input';
import { UserDocument } from '../../schema/user.schema';
@Injectable()
export class ProfileUpdateService {
async update(user: UserDocument, input: ProfileUpdateInput): Promise<UserDocument> {
if (input.firstName !== undefined) {
user.set('firstName', input.firstName)
}
if (input.lastName !== undefined) {
user.set('lastName', input.lastName)
}
if (input.email !== undefined) {
user.set('email', input.email)
// TODO request email verification
}
if (input.username !== undefined) {
user.set('username', input.username)
}
if (input.language !== undefined) {
user.set('language', input.language)
}
if (input.password !== undefined) {
// user.set('language', input.language)
// TODO password handling
}
await user.save()
return user
}
}

View File

@ -1,11 +1,13 @@
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,
SubmissionSetFieldService,
SubmissionStartService,
SubmissionService,
SubmissionStatisticService,
SubmissionTokenService,
]

View File

@ -1,5 +1,5 @@
import { InjectModel } from '@nestjs/mongoose';
import { Model } from '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';
@ -16,15 +16,18 @@ export class SubmissionService {
}
async find(form: FormDocument, start: number, limit: number, sort: any = {}): Promise<[SubmissionDocument[], number]> {
const qb = this.submissionModel.find({
const conditions: FilterQuery<SubmissionDocument> = {
form
})
}
return [
await qb.sort(sort)
await this.submissionModel
.find(conditions)
.sort(sort)
.skip(start)
.limit(limit),
await qb.count()
await this.submissionModel
.countDocuments(conditions)
]
}

View File

@ -0,0 +1,14 @@
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { SubmissionDocument, SubmissionSchemaName } from '../../schema/submission.schema';
export class SubmissionStatisticService {
constructor(
@InjectModel(SubmissionSchemaName) private readonly submissionModel: Model<SubmissionDocument>,
) {
}
async getTotal(): Promise<number> {
return await this.submissionModel.estimatedDocumentCount();
}
}

View File

@ -1,7 +1,13 @@
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 = [
UserCreateService,
UserDeleteService,
UserService,
UserStatisticService,
UserUpdateService,
]

View File

@ -0,0 +1,16 @@
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { UserDocument, UserSchemaName } from '../../schema/user.schema';
@Injectable()
export class UserDeleteService {
constructor(
@InjectModel(UserSchemaName) private userModel: Model<UserDocument>,
) {
}
async delete(id: string): Promise<void> {
await this.userModel.findByIdAndDelete(id).exec()
}
}

View File

@ -1,6 +1,5 @@
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { GraphQLError } from 'graphql';
import { Model } from 'mongoose';
import { UserDocument, UserSchemaName } from '../../schema/user.schema';
@ -11,6 +10,22 @@ export class UserService {
) {
}
async isSuperuser(user: UserDocument): Promise<boolean> {
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 findById(id: string): Promise<UserDocument> {
const user = await this.userModel.findById(id);

View File

@ -0,0 +1,14 @@
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { UserDocument, UserSchemaName } from '../../schema/user.schema';
export class UserStatisticService {
constructor(
@InjectModel(UserSchemaName) private userModel: Model<UserDocument>,
) {
}
async getTotal(): Promise<number> {
return await this.userModel.estimatedDocumentCount();
}
}

View File

@ -0,0 +1,41 @@
import { Injectable } from '@nestjs/common';
import { UserUpdateInput } from '../../dto/user/user.update.input';
import { UserDocument } from '../../schema/user.schema';
@Injectable()
export class UserUpdateService {
async update(user: UserDocument, input: UserUpdateInput): Promise<UserDocument> {
if (input.firstName !== undefined) {
user.set('firstName', input.firstName)
}
if (input.lastName !== undefined) {
user.set('lastName', input.lastName)
}
if (input.email !== undefined) {
user.set('email', input.email)
}
if (input.username !== undefined) {
user.set('username', input.username)
}
if (input.roles !== undefined) {
user.set('roles', input.roles)
}
if (input.language !== undefined) {
user.set('language', input.language)
}
if (input.password !== undefined) {
// user.set('language', input.language)
// TODO password handling
}
await user.save()
return user
}
}