mirror of
https://github.com/twentyhq/twenty.git
synced 2024-11-23 14:03:35 +03:00
chore: refacto NestJS in modules (#308)
* chore: wip refacto in modules * fix: rollback port * fix: jwt guard in wrong folder * chore: rename folder exception-filter in filters * fix: tests are running * fix: excessive stack depth comparing types * fix: auth issue * chore: move createUser in UserService * fix: test * fix: guards * fix: jwt guard don't handle falsy user
This commit is contained in:
parent
5921c7f11d
commit
2cd081234f
1
server/.nvmrc
Normal file
1
server/.nvmrc
Normal file
@ -0,0 +1 @@
|
||||
18.10.0
|
18
server/jest.config.ts
Normal file
18
server/jest.config.ts
Normal file
@ -0,0 +1,18 @@
|
||||
module.exports = {
|
||||
clearMocks: true,
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
setupFilesAfterEnv: ['<rootDir>/src/prisma-mock/jest-prisma-singleton.ts'],
|
||||
|
||||
moduleFileExtensions: ['js', 'json', 'ts'],
|
||||
moduleNameMapper: {
|
||||
'^src/(.*)': '<rootDir>/src/$1',
|
||||
},
|
||||
rootDir: './',
|
||||
testRegex: '.*\\.spec\\.ts$',
|
||||
transform: {
|
||||
'^.+\\.(t|j)s$': 'ts-jest',
|
||||
},
|
||||
collectCoverageFrom: ['**/*.(t|j)s'],
|
||||
coverageDirectory: '../coverage',
|
||||
};
|
@ -43,6 +43,7 @@
|
||||
"graphql": "^16.6.0",
|
||||
"graphql-type-json": "^0.3.2",
|
||||
"jest-mock-extended": "^3.0.4",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"passport": "^0.6.0",
|
||||
"passport-google-oauth20": "^2.0.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
@ -60,7 +61,9 @@
|
||||
"@types/jest": "28.1.8",
|
||||
"@types/node": "^16.0.0",
|
||||
"@types/passport-google-oauth20": "^2.0.11",
|
||||
"@types/passport-jwt": "^3.0.8",
|
||||
"@types/supertest": "^2.0.11",
|
||||
"@types/uuid": "^9.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||
"@typescript-eslint/parser": "^5.0.0",
|
||||
"eslint": "^8.0.1",
|
||||
@ -78,23 +81,6 @@
|
||||
"tsconfig-paths": "4.1.0",
|
||||
"typescript": "^4.9.4"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"json",
|
||||
"ts"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"testRegex": ".*\\.spec\\.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
},
|
||||
"collectCoverageFrom": [
|
||||
"**/*.(t|j)s"
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node"
|
||||
},
|
||||
"prisma": {
|
||||
"schema": "src/database/schema.prisma",
|
||||
"seed": "ts-node src/database/seeds/index.ts"
|
||||
|
@ -1,68 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { GraphQLModule } from '@nestjs/graphql';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
|
||||
|
||||
import { AuthModule } from 'src/auth/auth.module';
|
||||
import { PrismaModule } from 'src/database/prisma.module';
|
||||
import { ArgsService } from './resolvers/services/args.service';
|
||||
|
||||
import { CompanyResolver } from './resolvers/company.resolver';
|
||||
import { UserResolver } from './resolvers/user.resolver';
|
||||
import { PersonResolver } from './resolvers/person.resolver';
|
||||
import { CommentResolver } from './resolvers/comment.resolver';
|
||||
import { CommentThreadResolver } from './resolvers/comment-thread.resolver';
|
||||
import { PipelineResolver } from './resolvers/pipeline.resolver';
|
||||
import { PipelineStageResolver } from './resolvers/pipeline-stage.resolver';
|
||||
|
||||
import { PersonRelationsResolver } from './resolvers/relations/person-relations.resolver';
|
||||
import { UserRelationsResolver } from './resolvers/relations/user-relations.resolver';
|
||||
import { WorkspaceMemberRelationsResolver } from './resolvers/relations/workspace-member-relations.resolver';
|
||||
import { CompanyRelationsResolver } from './resolvers/relations/company-relations.resolver';
|
||||
import { CommentThreadRelationsResolver } from './resolvers/relations/comment-thread-relations.resolver';
|
||||
import { PipelineRelationsResolver } from './resolvers/relations/pipeline-relations.resolver';
|
||||
import { GraphQLError } from 'graphql';
|
||||
import { CommentRelationsResolver } from './resolvers/relations/comment-relations.resolver';
|
||||
import { PipelineProgressResolver } from './resolvers/pipeline-progress.resolver';
|
||||
import { PipelineStageRelationsResolver } from './resolvers/relations/pipeline-stage-relations.resolver';
|
||||
import { PipelineProgressRelationsResolver } from './resolvers/relations/pipeline-progress-relations.resolver';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
GraphQLModule.forRoot<ApolloDriverConfig>({
|
||||
context: ({ req }) => ({ req }),
|
||||
driver: ApolloDriver,
|
||||
autoSchemaFile: true,
|
||||
formatError: (error: GraphQLError) => {
|
||||
error.extensions.stacktrace = undefined;
|
||||
return error;
|
||||
},
|
||||
}),
|
||||
AuthModule,
|
||||
PrismaModule,
|
||||
],
|
||||
providers: [
|
||||
ConfigService,
|
||||
ArgsService,
|
||||
|
||||
CompanyResolver,
|
||||
PersonResolver,
|
||||
UserResolver,
|
||||
CommentResolver,
|
||||
CommentThreadResolver,
|
||||
PipelineResolver,
|
||||
PipelineStageResolver,
|
||||
PipelineProgressResolver,
|
||||
|
||||
CompanyRelationsResolver,
|
||||
CommentRelationsResolver,
|
||||
PersonRelationsResolver,
|
||||
UserRelationsResolver,
|
||||
WorkspaceMemberRelationsResolver,
|
||||
CommentThreadRelationsResolver,
|
||||
PipelineRelationsResolver,
|
||||
PipelineStageRelationsResolver,
|
||||
PipelineProgressRelationsResolver,
|
||||
],
|
||||
})
|
||||
export class ApiModule {}
|
@ -1,102 +0,0 @@
|
||||
import { Resolver, Args, Mutation, Query } from '@nestjs/graphql';
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
import { JwtAuthGuard } from 'src/auth/guards/jwt.auth.guard';
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
import { Workspace } from '../@generated/workspace/workspace.model';
|
||||
import { AuthWorkspace } from './decorators/auth-workspace.decorator';
|
||||
import { CommentThread } from '../@generated/comment-thread/comment-thread.model';
|
||||
import { CreateOneCommentThreadArgs } from '../@generated/comment-thread/create-one-comment-thread.args';
|
||||
import { CreateOneCommentThreadGuard } from './guards/create-one-comment-thread.guard';
|
||||
import { FindManyCommentThreadArgs } from '../@generated/comment-thread/find-many-comment-thread.args';
|
||||
import { ArgsService } from './services/args.service';
|
||||
import { UpdateOneCommentThreadArgs } from '../@generated/comment-thread/update-one-comment-thread.args';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Resolver(() => CommentThread)
|
||||
export class CommentThreadResolver {
|
||||
constructor(
|
||||
private readonly prismaService: PrismaService,
|
||||
private readonly argsService: ArgsService,
|
||||
) {}
|
||||
|
||||
@UseGuards(CreateOneCommentThreadGuard)
|
||||
@Mutation(() => CommentThread, {
|
||||
nullable: false,
|
||||
})
|
||||
async createOneCommentThread(
|
||||
@Args() args: CreateOneCommentThreadArgs,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
): Promise<CommentThread> {
|
||||
const newCommentData = args.data.comments?.createMany?.data
|
||||
? args.data.comments?.createMany?.data?.map((comment) => ({
|
||||
...comment,
|
||||
...{ workspaceId: workspace.id },
|
||||
}))
|
||||
: [];
|
||||
|
||||
const createdCommentThread = await this.prismaService.commentThread.create({
|
||||
data: {
|
||||
...args.data,
|
||||
...{ commentThreadTargets: undefined },
|
||||
...{ comments: { createMany: { data: newCommentData } } },
|
||||
...{ workspace: { connect: { id: workspace.id } } },
|
||||
},
|
||||
});
|
||||
|
||||
if (args.data.commentThreadTargets?.createMany?.data) {
|
||||
await this.prismaService.commentThreadTarget.createMany({
|
||||
data: args.data.commentThreadTargets?.createMany?.data?.map(
|
||||
(target) => ({
|
||||
...target,
|
||||
commentThreadId: args.data.id,
|
||||
}),
|
||||
),
|
||||
skipDuplicates:
|
||||
args.data.commentThreadTargets?.createMany?.skipDuplicates ?? false,
|
||||
});
|
||||
|
||||
return await this.prismaService.commentThread.update({
|
||||
where: { id: args.data.id },
|
||||
data: {
|
||||
commentThreadTargets: {
|
||||
connect: args.data.commentThreadTargets?.connect,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return createdCommentThread;
|
||||
}
|
||||
|
||||
@Mutation(() => CommentThread, {
|
||||
nullable: false,
|
||||
})
|
||||
async updateOneCommentThread(
|
||||
@Args() args: UpdateOneCommentThreadArgs,
|
||||
): Promise<CommentThread> {
|
||||
const updatedCommentThread = await this.prismaService.commentThread.update({
|
||||
data: args.data,
|
||||
where: args.where,
|
||||
});
|
||||
|
||||
return updatedCommentThread;
|
||||
}
|
||||
|
||||
@Query(() => [CommentThread])
|
||||
async findManyCommentThreads(
|
||||
@Args() args: FindManyCommentThreadArgs,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
) {
|
||||
const preparedArgs =
|
||||
await this.argsService.prepareFindManyArgs<FindManyCommentThreadArgs>(
|
||||
args,
|
||||
workspace,
|
||||
);
|
||||
|
||||
const result = await this.prismaService.commentThread.findMany(
|
||||
preparedArgs,
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
import { Resolver, Args, Mutation } from '@nestjs/graphql';
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
import { JwtAuthGuard } from 'src/auth/guards/jwt.auth.guard';
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
import { Workspace } from '../@generated/workspace/workspace.model';
|
||||
import { AuthWorkspace } from './decorators/auth-workspace.decorator';
|
||||
import { CreateOneCommentArgs } from '../@generated/comment/create-one-comment.args';
|
||||
import { Comment } from '../@generated/comment/comment.model';
|
||||
import { CreateOneCommentGuard } from './guards/create-one-comment.guard';
|
||||
import { Prisma } from '@prisma/client';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Resolver(() => Comment)
|
||||
export class CommentResolver {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
@UseGuards(CreateOneCommentGuard)
|
||||
@Mutation(() => Comment, {
|
||||
nullable: false,
|
||||
})
|
||||
async createOneComment(
|
||||
@Args() args: CreateOneCommentArgs,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
): Promise<Comment> {
|
||||
return this.prismaService.comment.create({
|
||||
data: {
|
||||
...args.data,
|
||||
...{ workspace: { connect: { id: workspace.id } } },
|
||||
},
|
||||
} satisfies CreateOneCommentArgs as Prisma.CommentCreateArgs);
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import { ExecutionContext, createParamDecorator } from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
export const AuthUser = createParamDecorator(
|
||||
(data: unknown, ctx: ExecutionContext) => {
|
||||
const gqlContext = GqlExecutionContext.create(ctx);
|
||||
const request = gqlContext.getContext().req;
|
||||
return request.user;
|
||||
},
|
||||
);
|
@ -1,10 +0,0 @@
|
||||
import { ExecutionContext, createParamDecorator } from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
export const AuthWorkspace = createParamDecorator(
|
||||
(data: unknown, ctx: ExecutionContext) => {
|
||||
const gqlContext = GqlExecutionContext.create(ctx);
|
||||
const request = gqlContext.getContext().req;
|
||||
return request.workspace;
|
||||
},
|
||||
);
|
@ -1,73 +0,0 @@
|
||||
import { Resolver, Args, Query, Mutation } from '@nestjs/graphql';
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
import { JwtAuthGuard } from 'src/auth/guards/jwt.auth.guard';
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
import { Workspace } from '../@generated/workspace/workspace.model';
|
||||
import { AuthWorkspace } from './decorators/auth-workspace.decorator';
|
||||
import { ArgsService } from './services/args.service';
|
||||
import { FindManyPipelineProgressArgs } from '../@generated/pipeline-progress/find-many-pipeline-progress.args';
|
||||
import { PipelineProgress } from '../@generated/pipeline-progress/pipeline-progress.model';
|
||||
import { UpdateOnePipelineProgressArgs } from '../@generated/pipeline-progress/update-one-pipeline-progress.args';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { AffectedRows } from '../@generated/prisma/affected-rows.output';
|
||||
import { DeleteManyPipelineProgressArgs } from '../@generated/pipeline-progress/delete-many-pipeline-progress.args';
|
||||
import { CreateOnePipelineProgressArgs } from '../@generated/pipeline-progress/create-one-pipeline-progress.args';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Resolver(() => PipelineProgress)
|
||||
export class PipelineProgressResolver {
|
||||
constructor(
|
||||
private readonly prismaService: PrismaService,
|
||||
private readonly argsService: ArgsService,
|
||||
) {}
|
||||
|
||||
@Query(() => [PipelineProgress])
|
||||
async findManyPipelineProgress(
|
||||
@Args() args: FindManyPipelineProgressArgs,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
) {
|
||||
const preparedArgs =
|
||||
await this.argsService.prepareFindManyArgs<FindManyPipelineProgressArgs>(
|
||||
args,
|
||||
workspace,
|
||||
);
|
||||
return this.prismaService.pipelineProgress.findMany(preparedArgs);
|
||||
}
|
||||
|
||||
@Mutation(() => PipelineProgress, {
|
||||
nullable: true,
|
||||
})
|
||||
async updateOnePipelineProgress(
|
||||
@Args() args: UpdateOnePipelineProgressArgs,
|
||||
): Promise<PipelineProgress | null> {
|
||||
return this.prismaService.pipelineProgress.update({
|
||||
...args,
|
||||
} satisfies UpdateOnePipelineProgressArgs as Prisma.PipelineProgressUpdateArgs);
|
||||
}
|
||||
|
||||
@Mutation(() => AffectedRows, {
|
||||
nullable: false,
|
||||
})
|
||||
async deleteManyPipelineProgress(
|
||||
@Args() args: DeleteManyPipelineProgressArgs,
|
||||
): Promise<AffectedRows> {
|
||||
return this.prismaService.pipelineProgress.deleteMany({
|
||||
...args,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => PipelineProgress, {
|
||||
nullable: false,
|
||||
})
|
||||
async createOnePipelineProgress(
|
||||
@Args() args: CreateOnePipelineProgressArgs,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
): Promise<PipelineProgress> {
|
||||
return this.prismaService.pipelineProgress.create({
|
||||
data: {
|
||||
...args.data,
|
||||
...{ workspace: { connect: { id: workspace.id } } },
|
||||
},
|
||||
} satisfies CreateOnePipelineProgressArgs as Prisma.PipelineProgressCreateArgs);
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
import { Resolver, Args, Query } from '@nestjs/graphql';
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
import { JwtAuthGuard } from 'src/auth/guards/jwt.auth.guard';
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
import { Workspace } from '../@generated/workspace/workspace.model';
|
||||
import { AuthWorkspace } from './decorators/auth-workspace.decorator';
|
||||
import { PipelineStage } from '../@generated/pipeline-stage/pipeline-stage.model';
|
||||
import { FindManyPipelineStageArgs } from '../@generated/pipeline-stage/find-many-pipeline-stage.args';
|
||||
import { ArgsService } from './services/args.service';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Resolver(() => PipelineStage)
|
||||
export class PipelineStageResolver {
|
||||
constructor(
|
||||
private readonly prismaService: PrismaService,
|
||||
private readonly argsService: ArgsService,
|
||||
) {}
|
||||
|
||||
@Query(() => [PipelineStage])
|
||||
async findManyPipelineStage(
|
||||
@Args() args: FindManyPipelineStageArgs,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
) {
|
||||
const preparedArgs =
|
||||
await this.argsService.prepareFindManyArgs<FindManyPipelineStageArgs>(
|
||||
args,
|
||||
workspace,
|
||||
);
|
||||
return this.prismaService.pipelineStage.findMany(preparedArgs);
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
import { Resolver, Args, Query } from '@nestjs/graphql';
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
import { JwtAuthGuard } from 'src/auth/guards/jwt.auth.guard';
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
import { Workspace } from '../@generated/workspace/workspace.model';
|
||||
import { AuthWorkspace } from './decorators/auth-workspace.decorator';
|
||||
import { Pipeline } from '../@generated/pipeline/pipeline.model';
|
||||
import { FindManyPipelineArgs } from '../@generated/pipeline/find-many-pipeline.args';
|
||||
import { ArgsService } from './services/args.service';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Resolver(() => Pipeline)
|
||||
export class PipelineResolver {
|
||||
constructor(
|
||||
private readonly prismaService: PrismaService,
|
||||
private readonly argsService: ArgsService,
|
||||
) {}
|
||||
|
||||
@Query(() => [Pipeline])
|
||||
async findManyPipeline(
|
||||
@Args() args: FindManyPipelineArgs,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
) {
|
||||
const preparedArgs =
|
||||
await this.argsService.prepareFindManyArgs<FindManyPipelineArgs>(
|
||||
args,
|
||||
workspace,
|
||||
);
|
||||
return this.prismaService.pipeline.findMany(preparedArgs);
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Workspace } from '@prisma/client';
|
||||
|
||||
type FindManyArgsType = { where?: object; orderBy?: object };
|
||||
|
||||
@Injectable()
|
||||
export class ArgsService {
|
||||
async prepareFindManyArgs<T extends FindManyArgsType>(
|
||||
args: T,
|
||||
workspace: Workspace,
|
||||
): Promise<T> {
|
||||
args.where = {
|
||||
...args.where,
|
||||
...{ workspace: { is: { id: { equals: workspace.id } } } },
|
||||
};
|
||||
return args;
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
import { Resolver, Query, Args } from '@nestjs/graphql';
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
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 { ExceptionFilter } from './exception-filters/exception.filter';
|
||||
import { JwtAuthGuard } from 'src/auth/guards/jwt.auth.guard';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Resolver(() => User)
|
||||
export class UserResolver {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
@UseFilters(ExceptionFilter)
|
||||
@Query(() => [User], {
|
||||
nullable: false,
|
||||
})
|
||||
async findManyUser(
|
||||
@Args() args: FindManyUserArgs,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
): Promise<User[]> {
|
||||
args.where = {
|
||||
...args.where,
|
||||
...{
|
||||
workspaceMember: {
|
||||
is: { workspace: { is: { id: { equals: workspace.id } } } },
|
||||
},
|
||||
},
|
||||
};
|
||||
return await this.prismaService.user.findMany({
|
||||
...args,
|
||||
});
|
||||
}
|
||||
}
|
@ -1,14 +1,32 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { GraphQLModule } from '@nestjs/graphql';
|
||||
import { AppService } from './app.service';
|
||||
import { HealthController } from './health.controller';
|
||||
import { TerminusModule } from '@nestjs/terminus';
|
||||
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { ApiModule } from './api/api.module';
|
||||
import { CoreModule } from './core/core.module';
|
||||
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
|
||||
import { GraphQLError } from 'graphql';
|
||||
import { PrismaModule } from './database/prisma.module';
|
||||
import { HealthModule } from './health/health.module';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule.forRoot({}), TerminusModule, AuthModule, ApiModule],
|
||||
controllers: [HealthController],
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
}),
|
||||
GraphQLModule.forRoot<ApolloDriverConfig>({
|
||||
context: ({ req }) => ({ req }),
|
||||
driver: ApolloDriver,
|
||||
autoSchemaFile: true,
|
||||
formatError: (error: GraphQLError) => {
|
||||
error.extensions.stacktrace = undefined;
|
||||
return error;
|
||||
},
|
||||
}),
|
||||
PrismaModule,
|
||||
HealthModule,
|
||||
CoreModule,
|
||||
],
|
||||
providers: [AppService],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
@ -1,70 +0,0 @@
|
||||
import {
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Injectable,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
import { Request } from 'express';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
import { JwtPayload } from '../strategies/jwt.auth.strategy';
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthGuard implements CanActivate {
|
||||
constructor(
|
||||
private jwtService: JwtService,
|
||||
private configService: ConfigService,
|
||||
private prismaService: PrismaService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
const token = this.extractTokenFromHeader(request);
|
||||
if (!token) {
|
||||
throw new UnauthorizedException();
|
||||
}
|
||||
try {
|
||||
const payload: JwtPayload = await this.jwtService.verifyAsync(token, {
|
||||
secret: this.configService.get('JWT_SECRET'),
|
||||
});
|
||||
|
||||
const user = this.prismaService.user.findUniqueOrThrow({
|
||||
where: { id: payload.userId },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new HttpException(
|
||||
{ reason: 'User does not exist' },
|
||||
HttpStatus.FORBIDDEN,
|
||||
);
|
||||
}
|
||||
|
||||
const workspace = this.prismaService.workspace.findUniqueOrThrow({
|
||||
where: { id: payload.workspaceId },
|
||||
});
|
||||
|
||||
if (!workspace) {
|
||||
throw new HttpException(
|
||||
{ reason: 'Workspace does not exist' },
|
||||
HttpStatus.FORBIDDEN,
|
||||
);
|
||||
}
|
||||
|
||||
request.user = user;
|
||||
request.workspace = workspace;
|
||||
} catch (exception) {
|
||||
throw new UnauthorizedException();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private extractTokenFromHeader(request: Request): string | undefined {
|
||||
const [type, token] = request.headers.authorization?.split(' ') ?? [];
|
||||
return type === 'Bearer' ? token : undefined;
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
import { Strategy } from 'passport-jwt';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
export type JwtPayload = { userId: string; workspaceId: string };
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthStrategy extends PassportStrategy(Strategy, 'jwt') {
|
||||
constructor(configService: ConfigService) {
|
||||
const extractJwtFromCookie = (req) => {
|
||||
let token = null;
|
||||
|
||||
if (req && req.cookies) {
|
||||
token = req.cookies['jwt'];
|
||||
}
|
||||
return token;
|
||||
};
|
||||
|
||||
super({
|
||||
jwtFromRequest: extractJwtFromCookie,
|
||||
ignoreExpiration: false,
|
||||
secretOrKey: configService.get<string>('JWT_SECRET'),
|
||||
});
|
||||
}
|
||||
|
||||
async validate(payload: JwtPayload): Promise<JwtPayload> {
|
||||
return { userId: payload.userId, workspaceId: payload.workspaceId };
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user