Refactor backend and add exception handlers (#189)
This commit is contained in:
@@ -1,18 +1,17 @@
|
||||
import { Field } from '@nestjs/graphql';
|
||||
import { InputType } from '@nestjs/graphql';
|
||||
import { CompanyCreateWithoutPeopleInput } from './company-create-without-people.input';
|
||||
import { Type } from 'class-transformer';
|
||||
import { HideField } from '@nestjs/graphql';
|
||||
import { CompanyCreateOrConnectWithoutPeopleInput } from './company-create-or-connect-without-people.input';
|
||||
import { CompanyWhereUniqueInput } from './company-where-unique.input';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
@InputType()
|
||||
export class CompanyCreateNestedOneWithoutPeopleInput {
|
||||
@Field(() => CompanyCreateWithoutPeopleInput, { nullable: true })
|
||||
@Type(() => CompanyCreateWithoutPeopleInput)
|
||||
@HideField()
|
||||
create?: CompanyCreateWithoutPeopleInput;
|
||||
|
||||
@Field(() => CompanyCreateOrConnectWithoutPeopleInput, { nullable: true })
|
||||
@Type(() => CompanyCreateOrConnectWithoutPeopleInput)
|
||||
@HideField()
|
||||
connectOrCreate?: CompanyCreateOrConnectWithoutPeopleInput;
|
||||
|
||||
@Field(() => CompanyWhereUniqueInput, { nullable: true })
|
||||
|
||||
+8
-11
@@ -1,37 +1,34 @@
|
||||
import { Field } from '@nestjs/graphql';
|
||||
import { InputType } from '@nestjs/graphql';
|
||||
import { CompanyCreateWithoutPeopleInput } from './company-create-without-people.input';
|
||||
import { Type } from 'class-transformer';
|
||||
import { HideField } from '@nestjs/graphql';
|
||||
import { CompanyCreateOrConnectWithoutPeopleInput } from './company-create-or-connect-without-people.input';
|
||||
import { CompanyUpsertWithoutPeopleInput } from './company-upsert-without-people.input';
|
||||
import { CompanyWhereUniqueInput } from './company-where-unique.input';
|
||||
import { Type } from 'class-transformer';
|
||||
import { CompanyUpdateWithoutPeopleInput } from './company-update-without-people.input';
|
||||
|
||||
@InputType()
|
||||
export class CompanyUpdateOneWithoutPeopleNestedInput {
|
||||
@Field(() => CompanyCreateWithoutPeopleInput, { nullable: true })
|
||||
@Type(() => CompanyCreateWithoutPeopleInput)
|
||||
@HideField()
|
||||
create?: CompanyCreateWithoutPeopleInput;
|
||||
|
||||
@Field(() => CompanyCreateOrConnectWithoutPeopleInput, { nullable: true })
|
||||
@Type(() => CompanyCreateOrConnectWithoutPeopleInput)
|
||||
@HideField()
|
||||
connectOrCreate?: CompanyCreateOrConnectWithoutPeopleInput;
|
||||
|
||||
@Field(() => CompanyUpsertWithoutPeopleInput, { nullable: true })
|
||||
@Type(() => CompanyUpsertWithoutPeopleInput)
|
||||
@HideField()
|
||||
upsert?: CompanyUpsertWithoutPeopleInput;
|
||||
|
||||
@Field(() => Boolean, { nullable: true })
|
||||
@HideField()
|
||||
disconnect?: boolean;
|
||||
|
||||
@Field(() => Boolean, { nullable: true })
|
||||
@HideField()
|
||||
delete?: boolean;
|
||||
|
||||
@Field(() => CompanyWhereUniqueInput, { nullable: true })
|
||||
@Type(() => CompanyWhereUniqueInput)
|
||||
connect?: CompanyWhereUniqueInput;
|
||||
|
||||
@Field(() => CompanyUpdateWithoutPeopleInput, { nullable: true })
|
||||
@Type(() => CompanyUpdateWithoutPeopleInput)
|
||||
@HideField()
|
||||
update?: CompanyUpdateWithoutPeopleInput;
|
||||
}
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
import { Field } from '@nestjs/graphql';
|
||||
import { InputType } from '@nestjs/graphql';
|
||||
import { PersonCreateWithoutCompanyInput } from './person-create-without-company.input';
|
||||
import { Type } from 'class-transformer';
|
||||
import { HideField } from '@nestjs/graphql';
|
||||
import { PersonCreateOrConnectWithoutCompanyInput } from './person-create-or-connect-without-company.input';
|
||||
import { PersonCreateManyCompanyInputEnvelope } from './person-create-many-company-input-envelope.input';
|
||||
import { PersonWhereUniqueInput } from './person-where-unique.input';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
@InputType()
|
||||
export class PersonCreateNestedManyWithoutCompanyInput {
|
||||
@Field(() => [PersonCreateWithoutCompanyInput], { nullable: true })
|
||||
@Type(() => PersonCreateWithoutCompanyInput)
|
||||
@HideField()
|
||||
create?: Array<PersonCreateWithoutCompanyInput>;
|
||||
|
||||
@Field(() => [PersonCreateOrConnectWithoutCompanyInput], { nullable: true })
|
||||
@Type(() => PersonCreateOrConnectWithoutCompanyInput)
|
||||
@HideField()
|
||||
connectOrCreate?: Array<PersonCreateOrConnectWithoutCompanyInput>;
|
||||
|
||||
@Field(() => PersonCreateManyCompanyInputEnvelope, { nullable: true })
|
||||
@Type(() => PersonCreateManyCompanyInputEnvelope)
|
||||
@HideField()
|
||||
createMany?: PersonCreateManyCompanyInputEnvelope;
|
||||
|
||||
@Field(() => [PersonWhereUniqueInput], { nullable: true })
|
||||
|
||||
+12
-27
@@ -1,64 +1,49 @@
|
||||
import { Field } from '@nestjs/graphql';
|
||||
import { InputType } from '@nestjs/graphql';
|
||||
import { PersonCreateWithoutCompanyInput } from './person-create-without-company.input';
|
||||
import { Type } from 'class-transformer';
|
||||
import { HideField } from '@nestjs/graphql';
|
||||
import { PersonCreateOrConnectWithoutCompanyInput } from './person-create-or-connect-without-company.input';
|
||||
import { PersonUpsertWithWhereUniqueWithoutCompanyInput } from './person-upsert-with-where-unique-without-company.input';
|
||||
import { PersonCreateManyCompanyInputEnvelope } from './person-create-many-company-input-envelope.input';
|
||||
import { PersonWhereUniqueInput } from './person-where-unique.input';
|
||||
import { Type } from 'class-transformer';
|
||||
import { PersonUpdateWithWhereUniqueWithoutCompanyInput } from './person-update-with-where-unique-without-company.input';
|
||||
import { PersonUpdateManyWithWhereWithoutCompanyInput } from './person-update-many-with-where-without-company.input';
|
||||
import { PersonScalarWhereInput } from './person-scalar-where.input';
|
||||
|
||||
@InputType()
|
||||
export class PersonUpdateManyWithoutCompanyNestedInput {
|
||||
@Field(() => [PersonCreateWithoutCompanyInput], { nullable: true })
|
||||
@Type(() => PersonCreateWithoutCompanyInput)
|
||||
@HideField()
|
||||
create?: Array<PersonCreateWithoutCompanyInput>;
|
||||
|
||||
@Field(() => [PersonCreateOrConnectWithoutCompanyInput], { nullable: true })
|
||||
@Type(() => PersonCreateOrConnectWithoutCompanyInput)
|
||||
@HideField()
|
||||
connectOrCreate?: Array<PersonCreateOrConnectWithoutCompanyInput>;
|
||||
|
||||
@Field(() => [PersonUpsertWithWhereUniqueWithoutCompanyInput], {
|
||||
nullable: true,
|
||||
})
|
||||
@Type(() => PersonUpsertWithWhereUniqueWithoutCompanyInput)
|
||||
@HideField()
|
||||
upsert?: Array<PersonUpsertWithWhereUniqueWithoutCompanyInput>;
|
||||
|
||||
@Field(() => PersonCreateManyCompanyInputEnvelope, { nullable: true })
|
||||
@Type(() => PersonCreateManyCompanyInputEnvelope)
|
||||
@HideField()
|
||||
createMany?: PersonCreateManyCompanyInputEnvelope;
|
||||
|
||||
@Field(() => [PersonWhereUniqueInput], { nullable: true })
|
||||
@Type(() => PersonWhereUniqueInput)
|
||||
@HideField()
|
||||
set?: Array<PersonWhereUniqueInput>;
|
||||
|
||||
@Field(() => [PersonWhereUniqueInput], { nullable: true })
|
||||
@Type(() => PersonWhereUniqueInput)
|
||||
@HideField()
|
||||
disconnect?: Array<PersonWhereUniqueInput>;
|
||||
|
||||
@Field(() => [PersonWhereUniqueInput], { nullable: true })
|
||||
@Type(() => PersonWhereUniqueInput)
|
||||
@HideField()
|
||||
delete?: Array<PersonWhereUniqueInput>;
|
||||
|
||||
@Field(() => [PersonWhereUniqueInput], { nullable: true })
|
||||
@Type(() => PersonWhereUniqueInput)
|
||||
connect?: Array<PersonWhereUniqueInput>;
|
||||
|
||||
@Field(() => [PersonUpdateWithWhereUniqueWithoutCompanyInput], {
|
||||
nullable: true,
|
||||
})
|
||||
@Type(() => PersonUpdateWithWhereUniqueWithoutCompanyInput)
|
||||
@HideField()
|
||||
update?: Array<PersonUpdateWithWhereUniqueWithoutCompanyInput>;
|
||||
|
||||
@Field(() => [PersonUpdateManyWithWhereWithoutCompanyInput], {
|
||||
nullable: true,
|
||||
})
|
||||
@Type(() => PersonUpdateManyWithWhereWithoutCompanyInput)
|
||||
@HideField()
|
||||
updateMany?: Array<PersonUpdateManyWithWhereWithoutCompanyInput>;
|
||||
|
||||
@Field(() => [PersonScalarWhereInput], { nullable: true })
|
||||
@Type(() => PersonScalarWhereInput)
|
||||
@HideField()
|
||||
deleteMany?: Array<PersonScalarWhereInput>;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import { Field } from '@nestjs/graphql';
|
||||
import { InputType } from '@nestjs/graphql';
|
||||
import { UserCreateWithoutCompaniesInput } from './user-create-without-companies.input';
|
||||
import { Type } from 'class-transformer';
|
||||
import { HideField } from '@nestjs/graphql';
|
||||
import { UserCreateOrConnectWithoutCompaniesInput } from './user-create-or-connect-without-companies.input';
|
||||
import { UserWhereUniqueInput } from './user-where-unique.input';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
@InputType()
|
||||
export class UserCreateNestedOneWithoutCompaniesInput {
|
||||
@Field(() => UserCreateWithoutCompaniesInput, { nullable: true })
|
||||
@Type(() => UserCreateWithoutCompaniesInput)
|
||||
@HideField()
|
||||
create?: UserCreateWithoutCompaniesInput;
|
||||
|
||||
@Field(() => UserCreateOrConnectWithoutCompaniesInput, { nullable: true })
|
||||
@Type(() => UserCreateOrConnectWithoutCompaniesInput)
|
||||
@HideField()
|
||||
connectOrCreate?: UserCreateOrConnectWithoutCompaniesInput;
|
||||
|
||||
@Field(() => UserWhereUniqueInput, { nullable: true })
|
||||
|
||||
@@ -1,37 +1,34 @@
|
||||
import { Field } from '@nestjs/graphql';
|
||||
import { InputType } from '@nestjs/graphql';
|
||||
import { UserCreateWithoutCompaniesInput } from './user-create-without-companies.input';
|
||||
import { Type } from 'class-transformer';
|
||||
import { HideField } from '@nestjs/graphql';
|
||||
import { UserCreateOrConnectWithoutCompaniesInput } from './user-create-or-connect-without-companies.input';
|
||||
import { UserUpsertWithoutCompaniesInput } from './user-upsert-without-companies.input';
|
||||
import { UserWhereUniqueInput } from './user-where-unique.input';
|
||||
import { Type } from 'class-transformer';
|
||||
import { UserUpdateWithoutCompaniesInput } from './user-update-without-companies.input';
|
||||
|
||||
@InputType()
|
||||
export class UserUpdateOneWithoutCompaniesNestedInput {
|
||||
@Field(() => UserCreateWithoutCompaniesInput, { nullable: true })
|
||||
@Type(() => UserCreateWithoutCompaniesInput)
|
||||
@HideField()
|
||||
create?: UserCreateWithoutCompaniesInput;
|
||||
|
||||
@Field(() => UserCreateOrConnectWithoutCompaniesInput, { nullable: true })
|
||||
@Type(() => UserCreateOrConnectWithoutCompaniesInput)
|
||||
@HideField()
|
||||
connectOrCreate?: UserCreateOrConnectWithoutCompaniesInput;
|
||||
|
||||
@Field(() => UserUpsertWithoutCompaniesInput, { nullable: true })
|
||||
@Type(() => UserUpsertWithoutCompaniesInput)
|
||||
@HideField()
|
||||
upsert?: UserUpsertWithoutCompaniesInput;
|
||||
|
||||
@Field(() => Boolean, { nullable: true })
|
||||
@HideField()
|
||||
disconnect?: boolean;
|
||||
|
||||
@Field(() => Boolean, { nullable: true })
|
||||
@HideField()
|
||||
delete?: boolean;
|
||||
|
||||
@Field(() => UserWhereUniqueInput, { nullable: true })
|
||||
@Type(() => UserWhereUniqueInput)
|
||||
connect?: UserWhereUniqueInput;
|
||||
|
||||
@Field(() => UserUpdateWithoutCompaniesInput, { nullable: true })
|
||||
@Type(() => UserUpdateWithoutCompaniesInput)
|
||||
@HideField()
|
||||
update?: UserUpdateWithoutCompaniesInput;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import { CompanyRelationsResolver } from './resolvers/relations/company-relation
|
||||
import { CommentThreadRelationsResolver } from './resolvers/relations/comment-thread-relations.resolver';
|
||||
import { PipelineRelationsResolver } from './resolvers/relations/pipeline-relations.resolver';
|
||||
import { PipelineStageRelationsResolver } from './resolvers/relations/pipeline-stage-relations.resolver';
|
||||
import { GraphQLError } from 'graphql';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -29,6 +30,10 @@ import { PipelineStageRelationsResolver } from './resolvers/relations/pipeline-s
|
||||
context: ({ req }) => ({ req }),
|
||||
driver: ApolloDriver,
|
||||
autoSchemaFile: true,
|
||||
formatError: (error: GraphQLError) => {
|
||||
error.extensions.stacktrace = undefined;
|
||||
return error;
|
||||
},
|
||||
}),
|
||||
AuthModule,
|
||||
PrismaModule,
|
||||
|
||||
@@ -11,10 +11,12 @@ import { AffectedRows } from '../@generated/prisma/affected-rows.output';
|
||||
import { DeleteManyCompanyArgs } from '../@generated/company/delete-many-company.args';
|
||||
import { Workspace } from '@prisma/client';
|
||||
import { ArgsService } from './services/args.service';
|
||||
import { CheckWorkspaceOwnership } from 'src/auth/guards/check-workspace-ownership.guard';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { UpdateOneGuard } from './guards/update-one.guard';
|
||||
import { DeleteManyGuard } from './guards/delete-many.guard';
|
||||
import { CreateOneGuard } from './guards/create-one.guard';
|
||||
|
||||
@UseGuards(JwtAuthGuard, CheckWorkspaceOwnership)
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Resolver(() => Company)
|
||||
export class CompanyResolver {
|
||||
constructor(
|
||||
@@ -35,6 +37,7 @@ export class CompanyResolver {
|
||||
return this.prismaService.company.findMany(preparedArgs);
|
||||
}
|
||||
|
||||
@UseGuards(UpdateOneGuard)
|
||||
@Mutation(() => Company, {
|
||||
nullable: true,
|
||||
})
|
||||
@@ -50,6 +53,7 @@ export class CompanyResolver {
|
||||
} satisfies UpdateOneCompanyArgs as Prisma.CompanyUpdateArgs);
|
||||
}
|
||||
|
||||
@UseGuards(DeleteManyGuard)
|
||||
@Mutation(() => AffectedRows, {
|
||||
nullable: false,
|
||||
})
|
||||
@@ -61,6 +65,7 @@ export class CompanyResolver {
|
||||
});
|
||||
}
|
||||
|
||||
@UseGuards(CreateOneGuard)
|
||||
@Mutation(() => Company, {
|
||||
nullable: false,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Catch, HttpException } from '@nestjs/common';
|
||||
import { GqlExceptionFilter } from '@nestjs/graphql';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { GraphQLError } from 'graphql';
|
||||
|
||||
@Catch()
|
||||
export class ExceptionFilter implements GqlExceptionFilter {
|
||||
catch(exception: HttpException) {
|
||||
if (exception instanceof Prisma.PrismaClientValidationError) {
|
||||
throw new GraphQLError('Invalid request', {
|
||||
extensions: {
|
||||
code: 'INVALID_REQUEST',
|
||||
},
|
||||
});
|
||||
}
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { CanActivate, Injectable } from '@nestjs/common';
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
|
||||
@Injectable()
|
||||
export class CreateOneGuard implements CanActivate {
|
||||
constructor(private prismaService: PrismaService) {}
|
||||
|
||||
async canActivate(): Promise<boolean> {
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { CanActivate, Injectable } from '@nestjs/common';
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteManyGuard implements CanActivate {
|
||||
constructor(private prismaService: PrismaService) {}
|
||||
|
||||
async canActivate(): Promise<boolean> {
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Injectable,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateOneGuard implements CanActivate {
|
||||
constructor(private prismaService: PrismaService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
const entity = gqlContext.getArgByIndex(3).returnType?.name;
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
console.log(args.data);
|
||||
if (!entity || !args.where?.id) {
|
||||
throw new HttpException(
|
||||
{ reason: 'Invalid Request' },
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
|
||||
const object = await this.prismaService[entity].findUniqueOrThrow({
|
||||
where: { id: args.where.id },
|
||||
});
|
||||
|
||||
if (!object) {
|
||||
throw new HttpException(
|
||||
{ reason: 'Record not found' },
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const workspace = await request.workspace;
|
||||
|
||||
if (object.workspaceId !== workspace.id) {
|
||||
throw new HttpException(
|
||||
{ reason: 'Record not found' },
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,12 @@ import { DeleteManyPersonArgs } from '../@generated/person/delete-many-person.ar
|
||||
import { Workspace } from '../@generated/workspace/workspace.model';
|
||||
import { AuthWorkspace } from './decorators/auth-workspace.decorator';
|
||||
import { ArgsService } from './services/args.service';
|
||||
import { CheckWorkspaceOwnership } from 'src/auth/guards/check-workspace-ownership.guard';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { UpdateOneGuard } from './guards/update-one.guard';
|
||||
import { DeleteManyGuard } from './guards/delete-many.guard';
|
||||
import { CreateOneGuard } from './guards/create-one.guard';
|
||||
|
||||
@UseGuards(JwtAuthGuard, CheckWorkspaceOwnership)
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Resolver(() => Person)
|
||||
export class PersonResolver {
|
||||
constructor(
|
||||
@@ -39,6 +41,7 @@ export class PersonResolver {
|
||||
});
|
||||
}
|
||||
|
||||
@UseGuards(UpdateOneGuard)
|
||||
@Mutation(() => Person, {
|
||||
nullable: true,
|
||||
})
|
||||
@@ -54,6 +57,7 @@ export class PersonResolver {
|
||||
} satisfies UpdateOnePersonArgs as Prisma.PersonUpdateArgs);
|
||||
}
|
||||
|
||||
@UseGuards(DeleteManyGuard)
|
||||
@Mutation(() => AffectedRows, {
|
||||
nullable: false,
|
||||
})
|
||||
@@ -65,6 +69,7 @@ export class PersonResolver {
|
||||
});
|
||||
}
|
||||
|
||||
@UseGuards(CreateOneGuard)
|
||||
@Mutation(() => Person, {
|
||||
nullable: false,
|
||||
})
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
import { Resolver, Query, Args } from '@nestjs/graphql';
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
import { JwtAuthGuard } from 'src/auth/guards/jwt.auth.guard';
|
||||
import { UseFilters, UseGuards } from '@nestjs/common';
|
||||
|
||||
import { User } from '../@generated/user/user.model';
|
||||
import { FindManyUserArgs } from '../@generated/user/find-many-user.args';
|
||||
import { Workspace } from '@prisma/client';
|
||||
import { AuthWorkspace } from './decorators/auth-workspace.decorator';
|
||||
import { ArgsService } from './services/args.service';
|
||||
import { CheckWorkspaceOwnership } from 'src/auth/guards/check-workspace-ownership.guard';
|
||||
import { ExceptionFilter } from './exception-filters/exception.filter';
|
||||
import { JwtAuthGuard } from 'src/auth/guards/jwt.auth.guard';
|
||||
|
||||
@UseGuards(JwtAuthGuard, CheckWorkspaceOwnership)
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Resolver(() => User)
|
||||
export class UserResolver {
|
||||
constructor(
|
||||
private readonly prismaService: PrismaService,
|
||||
private readonly argsService: ArgsService,
|
||||
) {}
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
@UseFilters(ExceptionFilter)
|
||||
@Query(() => [User], {
|
||||
nullable: false,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user