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:
Jérémy M
2023-06-16 10:38:11 +02:00
committed by GitHub
parent 5921c7f11d
commit 2cd081234f
1084 changed files with 2251 additions and 758 deletions

View File

@ -0,0 +1,105 @@
import {
CanActivate,
ExecutionContext,
HttpException,
HttpStatus,
Injectable,
} from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
import { PrismaService } from 'src/database/prisma.service';
@Injectable()
export class CreateOneCommentThreadGuard implements CanActivate {
constructor(private prismaService: PrismaService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const gqlContext = GqlExecutionContext.create(context);
// TODO: type request
const request = gqlContext.getContext().req;
const args = gqlContext.getArgs();
const targets = args.data?.commentThreadTargets?.createMany?.data;
const comments = args.data?.comments?.createMany?.data;
const workspace = request.user.workspace;
if (!targets || targets.length === 0) {
throw new HttpException(
{ reason: 'Missing commentThreadTargets' },
HttpStatus.BAD_REQUEST,
);
}
await targets.map(async (target) => {
if (!target.commentableId || !target.commentableType) {
throw new HttpException(
{
reason:
'Missing commentThreadTarget.commentableId or commentThreadTarget.commentableType',
},
HttpStatus.BAD_REQUEST,
);
}
if (!['Person', 'Company'].includes(target.commentableType)) {
throw new HttpException(
{ reason: 'Invalid commentThreadTarget.commentableType' },
HttpStatus.BAD_REQUEST,
);
}
const targetEntity = await this.prismaService[
target.commentableType
].findUnique({
where: { id: target.commentableId },
});
if (!targetEntity || targetEntity.workspaceId !== workspace.id) {
throw new HttpException(
{ reason: 'CommentThreadTarget not found' },
HttpStatus.NOT_FOUND,
);
}
});
if (!comments) {
return true;
}
await comments.map(async (comment) => {
if (!comment.authorId) {
throw new HttpException(
{ reason: 'Missing comment.authorId' },
HttpStatus.BAD_REQUEST,
);
}
const author = await this.prismaService.user.findUnique({
where: { id: comment.authorId },
});
if (!author) {
throw new HttpException(
{ reason: 'Comment.authorId not found' },
HttpStatus.NOT_FOUND,
);
}
const userWorkspaceMember =
await this.prismaService.workspaceMember.findFirst({
where: { userId: author.id },
});
if (
!userWorkspaceMember ||
userWorkspaceMember.workspaceId !== workspace.id
) {
throw new HttpException(
{ reason: 'userWorkspaceMember.workspaceId not found' },
HttpStatus.NOT_FOUND,
);
}
});
return true;
}
}

View File

@ -0,0 +1,71 @@
import {
CanActivate,
ExecutionContext,
HttpException,
HttpStatus,
Injectable,
} from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
import { PrismaService } from 'src/database/prisma.service';
@Injectable()
export class CreateOneCommentGuard implements CanActivate {
constructor(private prismaService: PrismaService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const gqlContext = GqlExecutionContext.create(context);
const request = gqlContext.getContext().req;
const args = gqlContext.getArgs();
const authorId = args.data?.author?.connect?.id;
const commentThreadId = args.data?.commentThread?.connect?.id;
if (!authorId || !commentThreadId) {
throw new HttpException(
{ reason: 'Missing author or commentThread' },
HttpStatus.BAD_REQUEST,
);
}
const author = await this.prismaService.user.findUnique({
where: { id: authorId },
});
const commentThread = await this.prismaService.commentThread.findUnique({
where: { id: commentThreadId },
});
if (!author || !commentThread) {
throw new HttpException(
{ reason: 'Author or commentThread not found' },
HttpStatus.NOT_FOUND,
);
}
const userWorkspaceMember =
await this.prismaService.workspaceMember.findFirst({
where: { userId: author.id },
});
if (!userWorkspaceMember) {
throw new HttpException(
{ reason: 'Author or commentThread not found' },
HttpStatus.NOT_FOUND,
);
}
const workspace = request.user.workspace;
if (
userWorkspaceMember.workspaceId !== workspace.id ||
commentThread.workspaceId !== workspace.id
) {
throw new HttpException(
{ reason: 'Author or commentThread not found' },
HttpStatus.NOT_FOUND,
);
}
return true;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,40 @@
import {
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { JsonWebTokenError } from 'jsonwebtoken';
import { assert } from 'src/utils/assert';
import { getRequest } from 'src/utils/extract-request';
@Injectable()
export class JwtAuthGuard extends AuthGuard(['jwt']) {
constructor() {
super();
}
getRequest(context: ExecutionContext) {
const request = getRequest(context);
return request;
}
handleRequest(err: any, user: any, info: any) {
assert(user, '', UnauthorizedException);
if (err) {
throw err;
}
if (info && info instanceof Error) {
if (info instanceof JsonWebTokenError) {
info = String(info);
}
throw new UnauthorizedException(info);
}
return user;
}
}

View File

@ -0,0 +1,49 @@
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();
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 = request.user.workspace;
if (object.workspaceId !== workspace.id) {
throw new HttpException(
{ reason: 'Record not found' },
HttpStatus.NOT_FOUND,
);
}
return true;
}
}