diff --git a/apps/backend/src/app/admin/admin.controller.spec.ts b/apps/backend/src/app/admin/admin.controller.spec.ts index 714d356..550ea86 100644 --- a/apps/backend/src/app/admin/admin.controller.spec.ts +++ b/apps/backend/src/app/admin/admin.controller.spec.ts @@ -1,20 +1,20 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { AdminController } from './admin.controller'; -import { AdminService } from './admin.service'; +import { Test, TestingModule } from "@nestjs/testing"; +import { AdminController } from "./admin.controller"; +import { AdminService } from "./admin.service"; -describe('AdminController', () => { - let controller: AdminController; +describe("AdminController", () => { + let controller: AdminController; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [AdminController], - providers: [AdminService], - }).compile(); + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [AdminController], + providers: [AdminService], + }).compile(); - controller = module.get(AdminController); - }); + controller = module.get(AdminController); + }); - it('should be defined', () => { - expect(controller).toBeDefined(); - }); + it("should be defined", () => { + expect(controller).toBeDefined(); + }); }); diff --git a/apps/backend/src/app/admin/admin.controller.ts b/apps/backend/src/app/admin/admin.controller.ts index 70a9d11..faf55d0 100644 --- a/apps/backend/src/app/admin/admin.controller.ts +++ b/apps/backend/src/app/admin/admin.controller.ts @@ -1,7 +1,7 @@ -import { Controller } from '@nestjs/common'; -import { AdminService } from './admin.service'; +import { Controller } from "@nestjs/common"; +import { AdminService } from "./admin.service"; -@Controller('admin') +@Controller("admin") export class AdminController { - constructor(private readonly adminService: AdminService) {} + constructor(private readonly adminService: AdminService) {} } diff --git a/apps/backend/src/app/admin/admin.module.ts b/apps/backend/src/app/admin/admin.module.ts index 2926ee8..6d1a040 100644 --- a/apps/backend/src/app/admin/admin.module.ts +++ b/apps/backend/src/app/admin/admin.module.ts @@ -1,9 +1,9 @@ -import { Module } from '@nestjs/common'; -import { AdminService } from './admin.service'; -import { AdminController } from './admin.controller'; +import { Module } from "@nestjs/common"; +import { AdminController } from "./admin.controller"; +import { AdminService } from "./admin.service"; @Module({ - controllers: [AdminController], - providers: [AdminService], + controllers: [AdminController], + providers: [AdminService], }) export class AdminModule {} diff --git a/apps/backend/src/app/admin/admin.service.spec.ts b/apps/backend/src/app/admin/admin.service.spec.ts index 5e5e153..3d0ea1d 100644 --- a/apps/backend/src/app/admin/admin.service.spec.ts +++ b/apps/backend/src/app/admin/admin.service.spec.ts @@ -1,18 +1,18 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { AdminService } from './admin.service'; +import { Test, TestingModule } from "@nestjs/testing"; +import { AdminService } from "./admin.service"; -describe('AdminService', () => { - let service: AdminService; +describe("AdminService", () => { + let service: AdminService; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [AdminService], - }).compile(); + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [AdminService], + }).compile(); - service = module.get(AdminService); - }); + service = module.get(AdminService); + }); - it('should be defined', () => { - expect(service).toBeDefined(); - }); + it("should be defined", () => { + expect(service).toBeDefined(); + }); }); diff --git a/apps/backend/src/app/admin/admin.service.ts b/apps/backend/src/app/admin/admin.service.ts index 796f9fd..c63a8cd 100644 --- a/apps/backend/src/app/admin/admin.service.ts +++ b/apps/backend/src/app/admin/admin.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable } from "@nestjs/common"; @Injectable() export class AdminService {} diff --git a/apps/backend/src/app/app.module.ts b/apps/backend/src/app/app.module.ts index 055aaac..73f434a 100644 --- a/apps/backend/src/app/app.module.ts +++ b/apps/backend/src/app/app.module.ts @@ -1,39 +1,39 @@ -import { Module } from '@nestjs/common'; +import { Module } from "@nestjs/common"; -import { AppController } from './app.controller'; -import { AppService } from './app.service'; -import { DbModule } from './db/db.module'; -import { ThrottlerModule } from '@nestjs/throttler'; -import { ConfigModule } from '@nestjs/config'; -import { AuthModule } from './auth/auth.module'; -import { CredentialsModule } from './credentials/credentials.module'; -import { FilesModule } from './files/files.module'; -import { AdminModule } from './admin/admin.module'; -import { GroupsModule } from './groups/groups.module'; -import { MachinesModule } from './machines/machines.module'; -import { AuthorsModule } from 'apps/backend/src/app/authors/authors.module'; +import { ConfigModule } from "@nestjs/config"; +import { ThrottlerModule } from "@nestjs/throttler"; +import { AuthorsModule } from "apps/backend/src/app/authors/authors.module"; +import { AdminModule } from "./admin/admin.module"; +import { AppController } from "./app.controller"; +import { AppService } from "./app.service"; +import { AuthModule } from "./auth/auth.module"; +import { CredentialsModule } from "./credentials/credentials.module"; +import { DbModule } from "./db/db.module"; +import { FilesModule } from "./files/files.module"; +import { GroupsModule } from "./groups/groups.module"; +import { MachinesModule } from "./machines/machines.module"; @Module({ - imports: [ - ThrottlerModule.forRoot([ - { - ttl: 60000, - limit: 10, - }, - ]), - ConfigModule.forRoot({ - isGlobal: true, - }), - DbModule, - AuthModule, - CredentialsModule, - FilesModule, - AdminModule, - GroupsModule, - MachinesModule, - AuthorsModule, - ], - controllers: [AppController], - providers: [AppService], + imports: [ + ThrottlerModule.forRoot([ + { + ttl: 60000, + limit: 10, + }, + ]), + ConfigModule.forRoot({ + isGlobal: true, + }), + DbModule, + AuthModule, + CredentialsModule, + FilesModule, + AdminModule, + GroupsModule, + MachinesModule, + AuthorsModule, + ], + controllers: [AppController], + providers: [AppService], }) export class AppModule {} diff --git a/apps/backend/src/app/auth/auth.controller.ts b/apps/backend/src/app/auth/auth.controller.ts index 9ee7454..1de69e6 100644 --- a/apps/backend/src/app/auth/auth.controller.ts +++ b/apps/backend/src/app/auth/auth.controller.ts @@ -1,66 +1,67 @@ import { - Body, - Controller, - Delete, - Get, - HttpCode, - HttpStatus, Patch, - Post, - UnauthorizedException, - UseGuards + Body, + Controller, + Delete, + Get, + HttpCode, + HttpStatus, + Patch, + Post, + UnauthorizedException, + UseGuards, } from "@nestjs/common"; +import { SignInDto, SignUpDto } from "apps/backend/src/app/auth/auth.dto"; +import { AuthService } from "apps/backend/src/app/auth/auth.service"; import { UserGuard } from "./auth.guard"; -import { AuthService } from 'apps/backend/src/app/auth/auth.service'; -import { SignInDto, SignUpDto } from 'apps/backend/src/app/auth/auth.dto'; @Controller("auth") export class AuthController { - constructor(private readonly authService: AuthService) { } + constructor(private readonly authService: AuthService) {} - //TODO Initial account validation for admin privileges - //POST signup - @HttpCode(HttpStatus.CREATED) - @Post("signup") - async signUp(@Body() dto: SignUpDto) { - console.log(dto); - return this.authService.doRegister(dto); - } + //TODO Initial account validation for admin privileges + //POST signup + @HttpCode(HttpStatus.CREATED) + @Post("signup") + async signUp(@Body() dto: SignUpDto) { + console.log(dto); + return this.authService.doRegister(dto); + } - //POST signin - @HttpCode(HttpStatus.OK) - @Post("signin") - async signIn(@Body() dto: SignInDto) { - console.log(dto); - return this.authService.doLogin(dto); - } - //GET me -- Get current user data via jwt - @HttpCode(HttpStatus.OK) - @Get("me") - @UseGuards(UserGuard) - async getMe(@Body() body: object) { - // @ts-ignore - const targetId = body.sourceUserId - const userData = await this.authService.fetchUserById(targetId) - if (!userData) { - throw new UnauthorizedException(); - } - return userData; - } - //DELETE me - @HttpCode(HttpStatus.FOUND) - @Delete("me") - @UseGuards(UserGuard) - async deleteMe(@Body() body: object) { - // @ts-ignore - const targetId = body.sourceUserId - try { - await this.authService.deleteUser(targetId) - } catch (err) { - throw new UnauthorizedException(); - } - } + //POST signin + @HttpCode(HttpStatus.OK) + @Post("signin") + async signIn(@Body() dto: SignInDto) { + console.log(dto); + return this.authService.doLogin(dto); + } + //GET me -- Get current user data via jwt + @HttpCode(HttpStatus.OK) + @Get("me") + @UseGuards(UserGuard) + async getMe(@Body() body: object) { + // @ts-ignore + const targetId = body.sourceUserId; + const userData = await this.authService.fetchUserById(targetId); + if (!userData) { + throw new UnauthorizedException(); + } + return userData; + } + //DELETE me + @HttpCode(HttpStatus.FOUND) + @Delete("me") + @UseGuards(UserGuard) + async deleteMe(@Body() body: object) { + // @ts-ignore + const targetId = body.sourceUserId; + try { + await this.authService.deleteUser(targetId); + } catch (err) { + throw new UnauthorizedException(); + } + } - /* + /* //PATCH me @HttpCode(HttpStatus.OK) @Patch("me") diff --git a/apps/backend/src/app/auth/auth.dto.ts b/apps/backend/src/app/auth/auth.dto.ts index 6119775..9dd6daa 100644 --- a/apps/backend/src/app/auth/auth.dto.ts +++ b/apps/backend/src/app/auth/auth.dto.ts @@ -1,14 +1,14 @@ import { - IsEmail, - IsNotEmpty, - IsString, - IsStrongPassword, - MaxLength, - MinLength, + IsEmail, + IsNotEmpty, + IsString, + IsStrongPassword, + MaxLength, + MinLength, } from "class-validator"; export class SignUpDto { - /* + /* @MinLength(1) @MaxLength(24) @IsNotEmpty() @@ -22,33 +22,33 @@ export class SignUpDto { lastName: string; **/ - @MaxLength(32) - @IsEmail() - @IsNotEmpty() - email: string; + @MaxLength(32) + @IsEmail() + @IsNotEmpty() + email: string; - @IsString() - @IsNotEmpty() - @IsStrongPassword({ - minLength: 6, - minSymbols: 1, - }) - password: string; + @IsString() + @IsNotEmpty() + @IsStrongPassword({ + minLength: 6, + minSymbols: 1, + }) + password: string; } export class SignInDto { - @MaxLength(32) - @IsEmail() - @IsNotEmpty() - email: string; + @MaxLength(32) + @IsEmail() + @IsNotEmpty() + email: string; - @IsString() - @IsNotEmpty() - @IsStrongPassword({ - minLength: 6, - minSymbols: 1, - }) - password: string; + @IsString() + @IsNotEmpty() + @IsStrongPassword({ + minLength: 6, + minSymbols: 1, + }) + password: string; } /* diff --git a/apps/backend/src/app/auth/auth.guard.ts b/apps/backend/src/app/auth/auth.guard.ts index 53418eb..2cffdb3 100644 --- a/apps/backend/src/app/auth/auth.guard.ts +++ b/apps/backend/src/app/auth/auth.guard.ts @@ -1,87 +1,89 @@ -import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, Inject } from "@nestjs/common"; -import type { Request } from "express"; -import { eq } from "drizzle-orm"; +import { + CanActivate, + ExecutionContext, + Inject, + Injectable, + UnauthorizedException, +} from "@nestjs/common"; import { Reflector } from "@nestjs/core"; -import { DbService } from 'apps/backend/src/app/db/db.service'; -import { UsersTable } from 'apps/backend/src/app/db/schema'; -import { CredentialsService } from 'apps/backend/src/app/credentials/credentials.service'; +import { CredentialsService } from "apps/backend/src/app/credentials/credentials.service"; +import { DbService } from "apps/backend/src/app/db/db.service"; +import { UsersTable } from "apps/backend/src/app/db/schema"; +import { eq } from "drizzle-orm"; +import type { Request } from "express"; @Injectable() export class UserGuard implements CanActivate { + constructor( + @Inject(CredentialsService) + private readonly credentialService: CredentialsService, + @Inject(DbService) private readonly databaseService: DbService, + ) {} - constructor( - @Inject(CredentialsService) private readonly credentialService: CredentialsService, - @Inject(DbService) private readonly databaseService: DbService, - ) { - } + async canActivate(context: ExecutionContext): Promise { + const request: Request = context.switchToHttp().getRequest(); + const authHeader = request.headers.authorization; - async canActivate( - context: ExecutionContext - ): Promise { - const request: Request = context.switchToHttp().getRequest(); - const authHeader = request.headers.authorization; + if (!authHeader) + throw new UnauthorizedException("No authorization header found."); - if (!authHeader) - throw new UnauthorizedException("No authorization header found."); + const token = authHeader.split(" ")[1]; + const vToken = await this.credentialService.verifyAuthToken(token); - const token = authHeader.split(" ")[1]; - const vToken = await this.credentialService.verifyAuthToken(token); + const user = await this.databaseService + .use() + .select() + .from(UsersTable) + .where(eq(UsersTable.uuid, vToken.payload.sub)); - const user = await this.databaseService.use() - .select() - .from(UsersTable) - .where(eq(UsersTable.uuid, vToken.payload.sub)); - - if (user.length !== 1) - throw new UnauthorizedException("No such user found."); - /* + if (user.length !== 1) + throw new UnauthorizedException("No such user found."); + /* if (user[0].emailCode) throw new UnauthorizedException("Email not verified."); */ - // Inject user ID into request body - request.body.sourceUserId = vToken.payload.sub; + // Inject user ID into request body + request.body.sourceUserId = vToken.payload.sub; - return true; - } + return true; + } } @Injectable() export class AdminGuard implements CanActivate { + constructor( + @Inject(CredentialsService) + private readonly credentialService: CredentialsService, + @Inject(DbService) private readonly databaseService: DbService, + ) {} + async canActivate(context: ExecutionContext): Promise { + const request: Request = context.switchToHttp().getRequest(); - constructor( - @Inject(CredentialsService) private readonly credentialService: CredentialsService, - @Inject(DbService) private readonly databaseService: DbService, - ) {} - async canActivate( - context: ExecutionContext - ): Promise { - const request: Request = context.switchToHttp().getRequest(); + const authHeader = request.headers.authorization; + if (!authHeader) { + throw new UnauthorizedException("No authorization header found."); + } + const token = authHeader.split(" ")[1]; + const vToken = await this.credentialService.verifyAuthToken(token); - const authHeader = request.headers.authorization; - if (!authHeader) { - throw new UnauthorizedException("No authorization header found."); + const user = await this.databaseService + .use() + .select() + .from(UsersTable) + .where(eq(UsersTable.uuid, vToken.payload.sub)); - } - const token = authHeader.split(" ")[1]; - const vToken = await this.credentialService.verifyAuthToken(token); + if (user.length !== 1) + throw new UnauthorizedException("No such user found."); - const user = await this.databaseService.use() - .select() - .from(UsersTable) - .where(eq(UsersTable.uuid, vToken.payload.sub)); + if (!user[0].isAdmin) { + throw new UnauthorizedException("Administrator only.."); + } - if (user.length !== 1) - throw new UnauthorizedException("No such user found."); + // Inject user ID into request body + request.body.sourceUserId = vToken.payload.sub; - if (!user[0].isAdmin) { - throw new UnauthorizedException("Administrator only.."); - } - - // Inject user ID into request body - request.body.sourceUserId = vToken.payload.sub; - - return true; - } -} \ No newline at end of file + return true; + } +} diff --git a/apps/backend/src/app/auth/auth.module.ts b/apps/backend/src/app/auth/auth.module.ts index b76747e..8139a75 100644 --- a/apps/backend/src/app/auth/auth.module.ts +++ b/apps/backend/src/app/auth/auth.module.ts @@ -1,14 +1,14 @@ import { Module } from "@nestjs/common"; +import { AdminGuard, UserGuard } from "apps/backend/src/app/auth/auth.guard"; +import { CredentialsModule } from "apps/backend/src/app/credentials/credentials.module"; +import { CredentialsService } from "apps/backend/src/app/credentials/credentials.service"; +import { DbModule } from "apps/backend/src/app/db/db.module"; import { AuthController } from "./auth.controller"; import { AuthService } from "./auth.service"; -import { DbModule } from 'apps/backend/src/app/db/db.module'; -import { CredentialsModule } from 'apps/backend/src/app/credentials/credentials.module'; -import { CredentialsService } from 'apps/backend/src/app/credentials/credentials.service'; -import { AdminGuard, UserGuard } from 'apps/backend/src/app/auth/auth.guard'; @Module({ - imports: [DbModule, CredentialsModule], - providers: [AuthService, CredentialsService, AdminGuard, UserGuard], - controllers: [AuthController], + imports: [DbModule, CredentialsModule], + providers: [AuthService, CredentialsService, AdminGuard, UserGuard], + controllers: [AuthController], }) export class AuthModule {} diff --git a/apps/backend/src/app/auth/auth.service.ts b/apps/backend/src/app/auth/auth.service.ts index 969661f..b307e37 100644 --- a/apps/backend/src/app/auth/auth.service.ts +++ b/apps/backend/src/app/auth/auth.service.ts @@ -1,113 +1,113 @@ import { - Injectable, - OnModuleInit, - UnauthorizedException, + Injectable, + OnModuleInit, + UnauthorizedException, } from "@nestjs/common"; +import { SignInDto, SignUpDto } from "apps/backend/src/app/auth/auth.dto"; +import { CredentialsService } from "apps/backend/src/app/credentials/credentials.service"; +import { DbService } from "apps/backend/src/app/db/db.service"; +import { UsersTable } from "apps/backend/src/app/db/schema"; import { eq } from "drizzle-orm"; -import { DbService } from 'apps/backend/src/app/db/db.service'; -import { CredentialsService } from 'apps/backend/src/app/credentials/credentials.service'; -import { UsersTable } from 'apps/backend/src/app/db/schema'; -import { SignInDto, SignUpDto } from 'apps/backend/src/app/auth/auth.dto'; @Injectable() export class AuthService implements OnModuleInit { - constructor( - private db: DbService, - private credentials: CredentialsService, - ) {} + constructor( + private db: DbService, + private credentials: CredentialsService, + ) {} - //TODO Initial account validation for admin privileges - async doRegister(data: SignUpDto) { - console.log(data); - const existingUser = await this.db - .use() - .select() - .from(UsersTable) - .where(eq(UsersTable.email, data.email)) - .prepare("userByEmail") - .execute(); - if (existingUser.length !== 0) - throw new UnauthorizedException("Already exist"); - const query = await this.db - .use() - .insert(UsersTable) - .values({ - //firstName: data.firstName, - //lastName: data.lastName, - email: data.email, - hash: await this.credentials.hash(data.password), - }) - .returning() - .prepare("insertUser") - .execute() - .catch((err) => { - console.error(err); - throw new UnauthorizedException( - "Error occurred while inserting user", - err, - ); - }); - return { - message: "User created, check your email for validation.", - token: await this.credentials.signAuthToken({ sub: query[0].uuid }), - }; - } + //TODO Initial account validation for admin privileges + async doRegister(data: SignUpDto) { + console.log(data); + const existingUser = await this.db + .use() + .select() + .from(UsersTable) + .where(eq(UsersTable.email, data.email)) + .prepare("userByEmail") + .execute(); + if (existingUser.length !== 0) + throw new UnauthorizedException("Already exist"); + const query = await this.db + .use() + .insert(UsersTable) + .values({ + //firstName: data.firstName, + //lastName: data.lastName, + email: data.email, + hash: await this.credentials.hash(data.password), + }) + .returning() + .prepare("insertUser") + .execute() + .catch((err) => { + console.error(err); + throw new UnauthorizedException( + "Error occurred while inserting user", + err, + ); + }); + return { + message: "User created, check your email for validation.", + token: await this.credentials.signAuthToken({ sub: query[0].uuid }), + }; + } - async doLogin(data: SignInDto) { - const user = await this.db - .use() - .select() - .from(UsersTable) - .where(eq(UsersTable.email, data.email)) - .prepare("userByEmail") - .execute(); - if (user.length !== 1) - throw new UnauthorizedException("Invalid credentials"); - const passwordMatch = await this.credentials.check( - data.password, - user[0].hash, - ); - if (!passwordMatch) throw new UnauthorizedException("Invalid credentials"); - const token = await this.credentials.signAuthToken({ sub: user[0].uuid }); - return { - message: "Login successful", - token: token, - }; - } + async doLogin(data: SignInDto) { + const user = await this.db + .use() + .select() + .from(UsersTable) + .where(eq(UsersTable.email, data.email)) + .prepare("userByEmail") + .execute(); + if (user.length !== 1) + throw new UnauthorizedException("Invalid credentials"); + const passwordMatch = await this.credentials.check( + data.password, + user[0].hash, + ); + if (!passwordMatch) throw new UnauthorizedException("Invalid credentials"); + const token = await this.credentials.signAuthToken({ sub: user[0].uuid }); + return { + message: "Login successful", + token: token, + }; + } - async fetchUserById(userId: string) { - const user = await this.db - .use() - .select() - .from(UsersTable) - .where(eq(UsersTable.uuid, userId)) - .prepare("userById") - .execute(); - if (user.length !== 1) { - throw new UnauthorizedException("User not found"); - } - delete user[0].hash; - //delete user[0].emailCode; - return user[0]; - } + async fetchUserById(userId: string) { + const user = await this.db + .use() + .select() + .from(UsersTable) + .where(eq(UsersTable.uuid, userId)) + .prepare("userById") + .execute(); + if (user.length !== 1) { + throw new UnauthorizedException("User not found"); + } + delete user[0].hash; + //delete user[0].emailCode; + return user[0]; + } - async fetchUsers() { - //TODO Pagination - const usersInDb = await this.db.use().select().from(UsersTable); - const result = { - total: usersInDb.length, - users: usersInDb.map((user) => { - delete user.hash; - return { - ...user, - }; - }), - }; - console.log(result); - return result; - } + async fetchUsers() { + //TODO Pagination + const usersInDb = await this.db.use().select().from(UsersTable); + const result = { + total: usersInDb.length, + users: usersInDb.map((user) => { + delete user.hash; + return { + ...user, + }; + }), + }; + console.log(result); + return result; + } - /* + /* async updateUser(targetId: string, userData: IUserUpdateData) { const validationResult = UserUpdateSchema.safeParse(userData); if (!validationResult.success) { @@ -133,27 +133,26 @@ export class AuthService implements OnModuleInit { } */ - async deleteUser(targetId: string) { - await this.db - .use() - .delete(UsersTable) - .where(eq(UsersTable.uuid, targetId)) - .prepare("deleteUserById") - .execute() - .catch((err) => { - console.error(err); - throw new UnauthorizedException( - "Error occurred while deleting user", - err, - ); - }); - return true; - } + async deleteUser(targetId: string) { + await this.db + .use() + .delete(UsersTable) + .where(eq(UsersTable.uuid, targetId)) + .prepare("deleteUserById") + .execute() + .catch((err) => { + console.error(err); + throw new UnauthorizedException( + "Error occurred while deleting user", + err, + ); + }); + return true; + } - async onModuleInit() { - setTimeout(() => { - this.fetchUsers(); - }, 2000); - } + async onModuleInit() { + setTimeout(() => { + this.fetchUsers(); + }, 2000); + } } - diff --git a/apps/backend/src/app/authors/authors.controller.spec.ts b/apps/backend/src/app/authors/authors.controller.spec.ts index fd4a443..cbc7e2e 100644 --- a/apps/backend/src/app/authors/authors.controller.spec.ts +++ b/apps/backend/src/app/authors/authors.controller.spec.ts @@ -1,20 +1,20 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { AuthorsController } from 'apps/backend/src/app/authors/authors.controller'; -import { AuthorsService } from 'apps/backend/src/app/authors/authors.service'; +import { Test, TestingModule } from "@nestjs/testing"; +import { AuthorsController } from "apps/backend/src/app/authors/authors.controller"; +import { AuthorsService } from "apps/backend/src/app/authors/authors.service"; -describe('AuthorsController', () => { - let controller: AuthorsController; +describe("AuthorsController", () => { + let controller: AuthorsController; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [AuthorsController], - providers: [AuthorsService], - }).compile(); + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [AuthorsController], + providers: [AuthorsService], + }).compile(); - controller = module.get(AuthorsController); - }); + controller = module.get(AuthorsController); + }); - it('should be defined', () => { - expect(controller).toBeDefined(); - }); + it("should be defined", () => { + expect(controller).toBeDefined(); + }); }); diff --git a/apps/backend/src/app/authors/authors.controller.ts b/apps/backend/src/app/authors/authors.controller.ts index cf222a9..ec80ac9 100644 --- a/apps/backend/src/app/authors/authors.controller.ts +++ b/apps/backend/src/app/authors/authors.controller.ts @@ -1,41 +1,44 @@ -import { Controller, DefaultValuePipe, Delete, Get, Param, ParseIntPipe, Post, Query } from '@nestjs/common'; -import { AuthorsService } from 'apps/backend/src/app/authors/authors.service'; +import { + Controller, + DefaultValuePipe, + Delete, + Get, + Param, + ParseIntPipe, + Post, + Query, +} from "@nestjs/common"; +import { AuthorsService } from "apps/backend/src/app/authors/authors.service"; -@Controller('authors') +@Controller("authors") export class AuthorsController { - constructor(private readonly authorService: AuthorsService) {} + constructor(private readonly authorService: AuthorsService) {} - @Get() - async findMany( - @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number, - @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, - @Query("search", new DefaultValuePipe("")) search: string - ) { - const query = {limit, offset, search} + @Get() + async findMany( + @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number, + @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, + @Query("search", new DefaultValuePipe("")) search: string, + ) { + const query = { limit, offset, search }; + } - } + //POST a new group + @Post("new") + async newAuthor() {} - //POST a new group - @Post("new") - async newAuthor() { + //DELETE a group + @Delete(":authorId") + async deleteAuthor(@Param("authorId") authorId: string) {} - } - - //DELETE a group - @Delete(":authorId") - async deleteAuthor(@Param('authorId') authorId: string) { - - } - - //GET files associated to authors with limit and offset - @Get(":authorId") - async getForAuthor( - @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number, - @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, - @Query("search", new DefaultValuePipe("")) search: string, - @Param('authorId') authorId: string - ) { - const query = {limit, offset, search} - - } + //GET files associated to authors with limit and offset + @Get(":authorId") + async getForAuthor( + @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number, + @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, + @Query("search", new DefaultValuePipe("")) search: string, + @Param("authorId") authorId: string, + ) { + const query = { limit, offset, search }; + } } diff --git a/apps/backend/src/app/authors/authors.module.ts b/apps/backend/src/app/authors/authors.module.ts index f09496e..9482e37 100644 --- a/apps/backend/src/app/authors/authors.module.ts +++ b/apps/backend/src/app/authors/authors.module.ts @@ -1,9 +1,9 @@ -import { Module } from '@nestjs/common'; -import { AuthorsService } from 'apps/backend/src/app/authors/authors.service'; -import { AuthorsController } from 'apps/backend/src/app/authors/authors.controller'; +import { Module } from "@nestjs/common"; +import { AuthorsController } from "apps/backend/src/app/authors/authors.controller"; +import { AuthorsService } from "apps/backend/src/app/authors/authors.service"; @Module({ - controllers: [AuthorsController], - providers: [AuthorsService], + controllers: [AuthorsController], + providers: [AuthorsService], }) export class AuthorsModule {} diff --git a/apps/backend/src/app/authors/authors.service.spec.ts b/apps/backend/src/app/authors/authors.service.spec.ts index 1a19df0..3ee590f 100644 --- a/apps/backend/src/app/authors/authors.service.spec.ts +++ b/apps/backend/src/app/authors/authors.service.spec.ts @@ -1,18 +1,18 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { AuthorsService } from 'apps/backend/src/app/authors/authors.service'; +import { Test, TestingModule } from "@nestjs/testing"; +import { AuthorsService } from "apps/backend/src/app/authors/authors.service"; -describe('AuthorsService', () => { - let service: AuthorsService; +describe("AuthorsService", () => { + let service: AuthorsService; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [AuthorsService], - }).compile(); + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [AuthorsService], + }).compile(); - service = module.get(AuthorsService); - }); + service = module.get(AuthorsService); + }); - it('should be defined', () => { - expect(service).toBeDefined(); - }); + it("should be defined", () => { + expect(service).toBeDefined(); + }); }); diff --git a/apps/backend/src/app/authors/authors.service.ts b/apps/backend/src/app/authors/authors.service.ts index 4fd5760..dd04e4e 100644 --- a/apps/backend/src/app/authors/authors.service.ts +++ b/apps/backend/src/app/authors/authors.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable } from "@nestjs/common"; @Injectable() export class AuthorsService {} diff --git a/apps/backend/src/app/credentials/credentials.module.ts b/apps/backend/src/app/credentials/credentials.module.ts index 37c4990..589578a 100644 --- a/apps/backend/src/app/credentials/credentials.module.ts +++ b/apps/backend/src/app/credentials/credentials.module.ts @@ -3,8 +3,8 @@ import { ConfigModule } from "@nestjs/config"; import { CredentialsService } from "./credentials.service"; @Module({ - imports: [ConfigModule], - providers: [CredentialsService], - exports: [CredentialsService], + imports: [ConfigModule], + providers: [CredentialsService], + exports: [CredentialsService], }) export class CredentialsModule {} diff --git a/apps/backend/src/app/credentials/credentials.service.ts b/apps/backend/src/app/credentials/credentials.service.ts index 4c679e0..39081dc 100644 --- a/apps/backend/src/app/credentials/credentials.service.ts +++ b/apps/backend/src/app/credentials/credentials.service.ts @@ -6,52 +6,52 @@ import { JWTPayload, generateSecret } from "jose"; @Injectable() export class CredentialsService { - constructor(private readonly configService: ConfigService) {} + constructor(private readonly configService: ConfigService) {} - async hash(plaintextPassword: string) { - console.log(plaintextPassword); - if (plaintextPassword.length < 6) - throw new BadRequestException("Password is not strong enough !"); - return argon.hash(plaintextPassword, { - secret: Buffer.from(this.configService.get("APP_HASH_SECRET")), - }); - } + async hash(plaintextPassword: string) { + console.log(plaintextPassword); + if (plaintextPassword.length < 6) + throw new BadRequestException("Password is not strong enough !"); + return argon.hash(plaintextPassword, { + secret: Buffer.from(this.configService.get("APP_HASH_SECRET")), + }); + } - async check(plaintextPassword: string, hashedPassword: string) { - return argon.verify(hashedPassword, plaintextPassword, { - secret: Buffer.from(this.configService.get("APP_HASH_SECRET")), - }); - } + async check(plaintextPassword: string, hashedPassword: string) { + return argon.verify(hashedPassword, plaintextPassword, { + secret: Buffer.from(this.configService.get("APP_HASH_SECRET")), + }); + } - async verifyAuthToken(token: string) { - try { - const result = await jose.jwtVerify( - token, - Uint8Array.from(this.configService.get("APP_TOKEN_SECRET")), - { - audience: "auth:user", - issuer: "FabLab", - }, - ); - console.log(result); - return result; - } catch (error) { - console.log(error) - throw new BadRequestException("Invalid token"); - } - } + async verifyAuthToken(token: string) { + try { + const result = await jose.jwtVerify( + token, + Uint8Array.from(this.configService.get("APP_TOKEN_SECRET")), + { + audience: "auth:user", + issuer: "FabLab", + }, + ); + console.log(result); + return result; + } catch (error) { + console.log(error); + throw new BadRequestException("Invalid token"); + } + } - async signAuthToken(payload: JWTPayload) { - console.log(this.configService.get("APP_TOKEN_SECRET")); - const token = new jose.SignJWT(payload) - .setProtectedHeader({ alg: "HS512", enc: "A128CBC-HS512" }) - .setIssuedAt() - .setExpirationTime("5 day") - .setIssuer("FabLab") - .setAudience("auth:user"); - console.log(token); - return await token.sign( - Uint8Array.from(this.configService.get("APP_TOKEN_SECRET")), - ); - } + async signAuthToken(payload: JWTPayload) { + console.log(this.configService.get("APP_TOKEN_SECRET")); + const token = new jose.SignJWT(payload) + .setProtectedHeader({ alg: "HS512", enc: "A128CBC-HS512" }) + .setIssuedAt() + .setExpirationTime("5 day") + .setIssuer("FabLab") + .setAudience("auth:user"); + console.log(token); + return await token.sign( + Uint8Array.from(this.configService.get("APP_TOKEN_SECRET")), + ); + } } diff --git a/apps/backend/src/app/db/schema.ts b/apps/backend/src/app/db/schema.ts index 8f838cd..33d6f50 100644 --- a/apps/backend/src/app/db/schema.ts +++ b/apps/backend/src/app/db/schema.ts @@ -61,9 +61,11 @@ export const FilesTable = pgTable("files", { }) .notNull(), - checksum: p.varchar("checksum", { - length: 64 - }).notNull(), + checksum: p + .varchar("checksum", { + length: 64, + }) + .notNull(), uploader: p .varchar("uploader", { @@ -71,9 +73,7 @@ export const FilesTable = pgTable("files", { }) .notNull(), - groupId: p - .uuid("group_id") - .references(()=> FilesGroupTable.uuid), + groupId: p.uuid("group_id").references(() => FilesGroupTable.uuid), fileSize: p.integer("file_size").notNull(), @@ -101,15 +101,15 @@ export const FilesTable = pgTable("files", { export const FilesGroupTable = pgTable("f_groups", { // Unique identifier on a technical aspect. - uuid: p.uuid("uuid").unique().primaryKey().defaultRandom().notNull(), + uuid: p.uuid("uuid").unique().primaryKey().defaultRandom().notNull(), - groupName: p - .varchar("group_name", { - length: 64, - }) + groupName: p + .varchar("group_name", { + length: 64, + }) .unique() - .notNull(), -}) + .notNull(), +}); //TODO Files types export const FilesTypesTable = pgTable("f_types", { diff --git a/apps/backend/src/app/files/files.controller.spec.ts b/apps/backend/src/app/files/files.controller.spec.ts index b352a39..97aaa47 100644 --- a/apps/backend/src/app/files/files.controller.spec.ts +++ b/apps/backend/src/app/files/files.controller.spec.ts @@ -1,20 +1,20 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { FilesController } from './files.controller'; -import { FilesService } from './files.service'; +import { Test, TestingModule } from "@nestjs/testing"; +import { FilesController } from "./files.controller"; +import { FilesService } from "./files.service"; -describe('FilesController', () => { - let controller: FilesController; +describe("FilesController", () => { + let controller: FilesController; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [FilesController], - providers: [FilesService], - }).compile(); + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [FilesController], + providers: [FilesService], + }).compile(); - controller = module.get(FilesController); - }); + controller = module.get(FilesController); + }); - it('should be defined', () => { - expect(controller).toBeDefined(); - }); + it("should be defined", () => { + expect(controller).toBeDefined(); + }); }); diff --git a/apps/backend/src/app/files/files.controller.ts b/apps/backend/src/app/files/files.controller.ts index 79a5fe4..3f89e02 100644 --- a/apps/backend/src/app/files/files.controller.ts +++ b/apps/backend/src/app/files/files.controller.ts @@ -1,7 +1,7 @@ -import { Controller } from '@nestjs/common'; -import { FilesService } from './files.service'; +import { Controller } from "@nestjs/common"; +import { FilesService } from "./files.service"; -@Controller('files') +@Controller("files") export class FilesController { - constructor(private readonly filesService: FilesService) {} + constructor(private readonly filesService: FilesService) {} } diff --git a/apps/backend/src/app/files/files.module.ts b/apps/backend/src/app/files/files.module.ts index 9b10b69..3689d40 100644 --- a/apps/backend/src/app/files/files.module.ts +++ b/apps/backend/src/app/files/files.module.ts @@ -1,9 +1,9 @@ -import { Module } from '@nestjs/common'; -import { FilesService } from './files.service'; -import { FilesController } from './files.controller'; +import { Module } from "@nestjs/common"; +import { FilesController } from "./files.controller"; +import { FilesService } from "./files.service"; @Module({ - controllers: [FilesController], - providers: [FilesService], + controllers: [FilesController], + providers: [FilesService], }) export class FilesModule {} diff --git a/apps/backend/src/app/files/files.service.spec.ts b/apps/backend/src/app/files/files.service.spec.ts index c653b32..38817b2 100644 --- a/apps/backend/src/app/files/files.service.spec.ts +++ b/apps/backend/src/app/files/files.service.spec.ts @@ -1,18 +1,18 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { FilesService } from './files.service'; +import { Test, TestingModule } from "@nestjs/testing"; +import { FilesService } from "./files.service"; -describe('FilesService', () => { - let service: FilesService; +describe("FilesService", () => { + let service: FilesService; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [FilesService], - }).compile(); + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [FilesService], + }).compile(); - service = module.get(FilesService); - }); + service = module.get(FilesService); + }); - it('should be defined', () => { - expect(service).toBeDefined(); - }); + it("should be defined", () => { + expect(service).toBeDefined(); + }); }); diff --git a/apps/backend/src/app/files/files.service.ts b/apps/backend/src/app/files/files.service.ts index ab8a4e6..8075ec8 100644 --- a/apps/backend/src/app/files/files.service.ts +++ b/apps/backend/src/app/files/files.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable } from "@nestjs/common"; @Injectable() export class FilesService {} diff --git a/apps/backend/src/app/global.dto.ts b/apps/backend/src/app/global.dto.ts new file mode 100644 index 0000000..e69de29 diff --git a/apps/backend/src/app/groups/groups.controller.spec.ts b/apps/backend/src/app/groups/groups.controller.spec.ts index 66ef3d4..cbb4687 100644 --- a/apps/backend/src/app/groups/groups.controller.spec.ts +++ b/apps/backend/src/app/groups/groups.controller.spec.ts @@ -1,20 +1,20 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { GroupsController } from './groups.controller'; -import { GroupsService } from './groups.service'; +import { Test, TestingModule } from "@nestjs/testing"; +import { GroupsController } from "./groups.controller"; +import { GroupsService } from "./groups.service"; -describe('GroupsController', () => { - let controller: GroupsController; +describe("GroupsController", () => { + let controller: GroupsController; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [GroupsController], - providers: [GroupsService], - }).compile(); + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [GroupsController], + providers: [GroupsService], + }).compile(); - controller = module.get(GroupsController); - }); + controller = module.get(GroupsController); + }); - it('should be defined', () => { - expect(controller).toBeDefined(); - }); + it("should be defined", () => { + expect(controller).toBeDefined(); + }); }); diff --git a/apps/backend/src/app/groups/groups.controller.ts b/apps/backend/src/app/groups/groups.controller.ts index 85569e5..1036324 100644 --- a/apps/backend/src/app/groups/groups.controller.ts +++ b/apps/backend/src/app/groups/groups.controller.ts @@ -1,43 +1,46 @@ -import { Controller, DefaultValuePipe, Delete, Get, Param, ParseIntPipe, Post, Query } from '@nestjs/common'; -import { GroupsService } from './groups.service'; -import { ISearchQuery } from 'apps/backend/src/app/groups/groups.types'; +import { + Controller, + DefaultValuePipe, + Delete, + Get, + Param, + ParseIntPipe, + Post, + Query, +} from "@nestjs/common"; +import { ISearchQuery } from "apps/backend/src/app/groups/groups.types"; +import { GroupsService } from "./groups.service"; -@Controller('groups') +@Controller("groups") export class GroupsController { - constructor(private readonly groupsService: GroupsService) {} + constructor(private readonly groupsService: GroupsService) {} - //GET all groups with limit and offset + optional search - @Get() - async findMany( - @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number, - @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, - @Query("search", new DefaultValuePipe("")) search: string - ) { - const query = {limit, offset, search} + //GET all groups with limit and offset + optional search + @Get() + async findMany( + @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number, + @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, + @Query("search", new DefaultValuePipe("")) search: string, + ) { + const query = { limit, offset, search }; + } - } + //POST a new group + @Post("new") + async newGroup() {} - //POST a new group - @Post("new") - async newGroup() { + //DELETE a group + @Delete(":groupId") + async deleteGroup(@Param("groupId") groupId: string) {} - } - - //DELETE a group - @Delete(":groupId") - async deleteGroup(@Param('groupId') groupId: string) { - - } - - //GET files associated to group with limit and offset - @Get(":groupId") - async getForGroup( - @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number, - @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, - @Query("search", new DefaultValuePipe("")) search: string, - @Param('groupId') groupId: string - ) { - const query = {limit, offset, search} - - } + //GET files associated to group with limit and offset + @Get(":groupId") + async getForGroup( + @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number, + @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, + @Query("search", new DefaultValuePipe("")) search: string, + @Param("groupId") groupId: string, + ) { + const query = { limit, offset, search }; + } } diff --git a/apps/backend/src/app/groups/groups.module.ts b/apps/backend/src/app/groups/groups.module.ts index 83d027d..718f09d 100644 --- a/apps/backend/src/app/groups/groups.module.ts +++ b/apps/backend/src/app/groups/groups.module.ts @@ -1,9 +1,9 @@ -import { Module } from '@nestjs/common'; -import { GroupsService } from './groups.service'; -import { GroupsController } from './groups.controller'; +import { Module } from "@nestjs/common"; +import { GroupsController } from "./groups.controller"; +import { GroupsService } from "./groups.service"; @Module({ - controllers: [GroupsController], - providers: [GroupsService], + controllers: [GroupsController], + providers: [GroupsService], }) export class GroupsModule {} diff --git a/apps/backend/src/app/groups/groups.service.spec.ts b/apps/backend/src/app/groups/groups.service.spec.ts index 77bd2c6..dd1b8ed 100644 --- a/apps/backend/src/app/groups/groups.service.spec.ts +++ b/apps/backend/src/app/groups/groups.service.spec.ts @@ -1,18 +1,18 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { GroupsService } from './groups.service'; +import { Test, TestingModule } from "@nestjs/testing"; +import { GroupsService } from "./groups.service"; -describe('GroupsService', () => { - let service: GroupsService; +describe("GroupsService", () => { + let service: GroupsService; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [GroupsService], - }).compile(); + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [GroupsService], + }).compile(); - service = module.get(GroupsService); - }); + service = module.get(GroupsService); + }); - it('should be defined', () => { - expect(service).toBeDefined(); - }); + it("should be defined", () => { + expect(service).toBeDefined(); + }); }); diff --git a/apps/backend/src/app/groups/groups.service.ts b/apps/backend/src/app/groups/groups.service.ts index efa0581..29d53cc 100644 --- a/apps/backend/src/app/groups/groups.service.ts +++ b/apps/backend/src/app/groups/groups.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable } from "@nestjs/common"; @Injectable() export class GroupsService {} diff --git a/apps/backend/src/app/groups/groups.types.ts b/apps/backend/src/app/groups/groups.types.ts index 5fcc2ee..d17430d 100644 --- a/apps/backend/src/app/groups/groups.types.ts +++ b/apps/backend/src/app/groups/groups.types.ts @@ -1,5 +1,5 @@ export interface ISearchQuery { - limit: number; - offset: number; - search?: string; -} \ No newline at end of file + limit: number; + offset: number; + search?: string; +} diff --git a/apps/backend/src/app/machines/machines.controller.spec.ts b/apps/backend/src/app/machines/machines.controller.spec.ts index fc9d727..d1f35b1 100644 --- a/apps/backend/src/app/machines/machines.controller.spec.ts +++ b/apps/backend/src/app/machines/machines.controller.spec.ts @@ -1,20 +1,20 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { MachinesController } from 'apps/backend/src/app/machines/machines.controller'; -import { MachinesService } from 'apps/backend/src/app/machines/machines.service'; +import { Test, TestingModule } from "@nestjs/testing"; +import { MachinesController } from "apps/backend/src/app/machines/machines.controller"; +import { MachinesService } from "apps/backend/src/app/machines/machines.service"; -describe('MachineController', () => { - let controller: MachinesController; +describe("MachineController", () => { + let controller: MachinesController; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [MachinesController], - providers: [MachinesService], - }).compile(); + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [MachinesController], + providers: [MachinesService], + }).compile(); - controller = module.get(MachinesController); - }); + controller = module.get(MachinesController); + }); - it('should be defined', () => { - expect(controller).toBeDefined(); - }); + it("should be defined", () => { + expect(controller).toBeDefined(); + }); }); diff --git a/apps/backend/src/app/machines/machines.controller.ts b/apps/backend/src/app/machines/machines.controller.ts index c5808e4..6bd6496 100644 --- a/apps/backend/src/app/machines/machines.controller.ts +++ b/apps/backend/src/app/machines/machines.controller.ts @@ -1,38 +1,41 @@ -import { Controller, DefaultValuePipe, Delete, Get, Param, ParseIntPipe, Post, Query } from '@nestjs/common'; -import { MachinesService } from 'apps/backend/src/app/machines/machines.service'; +import { + Controller, + DefaultValuePipe, + Delete, + Get, + Param, + ParseIntPipe, + Post, + Query, +} from "@nestjs/common"; +import { MachinesService } from "apps/backend/src/app/machines/machines.service"; -@Controller('machines') +@Controller("machines") export class MachinesController { - constructor(private readonly machineService: MachinesService) {} + constructor(private readonly machineService: MachinesService) {} - @Get() - async findMany( - @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number, - @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, - @Query("search", new DefaultValuePipe("")) search: string - ) { - const query = {limit, offset, search} + @Get() + async findMany( + @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number, + @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, + @Query("search", new DefaultValuePipe("")) search: string, + ) { + const query = { limit, offset, search }; + } - } + @Post("new") + async newMachine() {} - @Post("new") - async newMachine() { + @Delete(":machineId") + async deleteGroup(@Param("machineId") machineId: string) {} - } - - @Delete(":machineId") - async deleteGroup(@Param('machineId') machineId: string) { - - } - - @Get(":groupId") - async getForGroup( - @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number, - @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, - @Query("search", new DefaultValuePipe("")) search: string, - @Param('machineId') machineId: string - ) { - const query = {limit, offset, search} - - } + @Get(":groupId") + async getForGroup( + @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number, + @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, + @Query("search", new DefaultValuePipe("")) search: string, + @Param("machineId") machineId: string, + ) { + const query = { limit, offset, search }; + } } diff --git a/apps/backend/src/app/machines/machines.module.ts b/apps/backend/src/app/machines/machines.module.ts index 6b84b65..4c79ab7 100644 --- a/apps/backend/src/app/machines/machines.module.ts +++ b/apps/backend/src/app/machines/machines.module.ts @@ -1,9 +1,9 @@ -import { Module } from '@nestjs/common'; -import { MachinesService } from 'apps/backend/src/app/machines/machines.service'; -import { MachinesController } from 'apps/backend/src/app/machines/machines.controller'; +import { Module } from "@nestjs/common"; +import { MachinesController } from "apps/backend/src/app/machines/machines.controller"; +import { MachinesService } from "apps/backend/src/app/machines/machines.service"; @Module({ - controllers: [MachinesController], - providers: [MachinesService], + controllers: [MachinesController], + providers: [MachinesService], }) export class MachinesModule {} diff --git a/apps/backend/src/app/machines/machines.service.spec.ts b/apps/backend/src/app/machines/machines.service.spec.ts index 53a657a..5e5df43 100644 --- a/apps/backend/src/app/machines/machines.service.spec.ts +++ b/apps/backend/src/app/machines/machines.service.spec.ts @@ -1,18 +1,18 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { MachinesService } from 'apps/backend/src/app/machines/machines.service'; +import { Test, TestingModule } from "@nestjs/testing"; +import { MachinesService } from "apps/backend/src/app/machines/machines.service"; -describe('MachinesService', () => { - let service: MachinesService; +describe("MachinesService", () => { + let service: MachinesService; - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [MachinesService], - }).compile(); + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [MachinesService], + }).compile(); - service = module.get(MachinesService); - }); + service = module.get(MachinesService); + }); - it('should be defined', () => { - expect(service).toBeDefined(); - }); + it("should be defined", () => { + expect(service).toBeDefined(); + }); }); diff --git a/apps/backend/src/app/machines/machines.service.ts b/apps/backend/src/app/machines/machines.service.ts index 165c8ba..93d52c6 100644 --- a/apps/backend/src/app/machines/machines.service.ts +++ b/apps/backend/src/app/machines/machines.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable } from "@nestjs/common"; @Injectable() export class MachinesService {} diff --git a/apps/backend/src/app/storage/storage.module.ts b/apps/backend/src/app/storage/storage.module.ts index 128f770..a42b9a9 100644 --- a/apps/backend/src/app/storage/storage.module.ts +++ b/apps/backend/src/app/storage/storage.module.ts @@ -1,6 +1,6 @@ import { Module } from "@nestjs/common"; +import { DbModule } from "apps/backend/src/app/db/db.module"; import { StorageService } from "apps/backend/src/app/storage/storage.service"; -import { DbModule } from 'apps/backend/src/app/db/db.module'; @Module({ imports: [DbModule], diff --git a/apps/backend/src/app/storage/storage.service.ts b/apps/backend/src/app/storage/storage.service.ts index 9613ad3..50ae43e 100644 --- a/apps/backend/src/app/storage/storage.service.ts +++ b/apps/backend/src/app/storage/storage.service.ts @@ -8,11 +8,14 @@ import { InternalServerErrorException, NotFoundException, } from "@nestjs/common"; +import { DbService } from "apps/backend/src/app/db/db.service"; +import { + FilesTypeForMachine, + FilesTypesTable, +} from "apps/backend/src/app/db/schema"; +import { IFileInformation } from "apps/backend/src/app/storage/storage.types"; +import { eq } from "drizzle-orm"; import FileType from "file-type"; -import { DbService } from 'apps/backend/src/app/db/db.service'; -import { IFileInformation } from 'apps/backend/src/app/storage/storage.types'; -import { FilesTypeForMachine, FilesTypesTable } from 'apps/backend/src/app/db/schema'; -import { eq } from 'drizzle-orm'; @Injectable() export class StorageService { @@ -20,7 +23,6 @@ export class StorageService { private maxFileSize = 256; // MiB unit constructor(private readonly dbService: DbService) {} - /** * Save a file to the specified directory. * @@ -44,8 +46,10 @@ export class StorageService { * @param {Buffer} file - The file to check. * @return {Promise} - A Promise that resolves to true if the conditions are met, false otherwise. */ - private async checkConditions(machineIds: Array,file: Buffer): Promise { - + private async checkConditions( + machineIds: Array, + file: Buffer, + ): Promise { /** * Checks if the current MIME type is allowed based on the given set of allowed MIME types. * @param {Set} allowedMime - The set of allowed MIME types. @@ -60,53 +64,55 @@ export class StorageService { const fileType = await FileType.fileTypeFromBuffer(file); // Array of MIMEs with possible duplicate field - const _mimes: Array = [] + const _mimes: Array = []; // Fetching MIMEs for the associated machines for (const machineId of machineIds) { - console.debug(`Fetching mimeTypes for machine : ${machineId}`) + console.debug(`Fetching mimeTypes for machine : ${machineId}`); // Get MIMEs associated to a machine - const allowedMimeId = this.dbService.use() + const allowedMimeId = this.dbService + .use() .select() .from(FilesTypeForMachine) - .where(eq(FilesTypeForMachine.machineId, machineId)).as("allowedMimeId"); - const _allowedMime = await this.dbService.use() + .where(eq(FilesTypeForMachine.machineId, machineId)) + .as("allowedMimeId"); + const _allowedMime = await this.dbService + .use() .select({ slug: FilesTypesTable.mime, - name: FilesTypesTable.typeName + name: FilesTypesTable.typeName, }) .from(FilesTypesTable) - .leftJoin(allowedMimeId, eq(FilesTypesTable.id, allowedMimeId.fileTypeId)) - console.debug(`Total : ${_allowedMime.length}`) + .leftJoin( + allowedMimeId, + eq(FilesTypesTable.id, allowedMimeId.fileTypeId), + ); + console.debug(`Total : ${_allowedMime.length}`); // Append each MIME of a machine for (const allowedMimeElement of _allowedMime) { - _mimes.push(allowedMimeElement.slug) + _mimes.push(allowedMimeElement.slug); } } //Store the MIMEs without duplicate - const mimeSet = new Set(_mimes) - console.debug(`Indexed ${mimeSet.size} unique mimeTypes`) + const mimeSet = new Set(_mimes); + console.debug(`Indexed ${mimeSet.size} unique mimeTypes`); //check file size is less than 2mb const fileSize = file.byteLength; if (fileSize > this.maxFileSize * (1024 * 1024)) { - throw new BadRequestException( - "File size to high.", - { - cause: "File size", - description: `File size exceeds the limit. Maximum file size allowed is ${this.maxFileSize}MiB.` - } - ); + throw new BadRequestException("File size to high.", { + cause: "File size", + description: `File size exceeds the limit. Maximum file size allowed is ${this.maxFileSize}MiB.`, + }); } - if (!checkMime(mimeSet, fileType.mime)) throw new BadRequestException( - { - cause: "MIME type", - description: `Invalid MIME type. Allowed MIME types are: ${[...mimeSet].join(", ")}.` - } - ) + if (!checkMime(mimeSet, fileType.mime)) + throw new BadRequestException({ + cause: "MIME type", + description: `Invalid MIME type. Allowed MIME types are: ${[...mimeSet].join(", ")}.`, + }); - return true + return true; } /** @@ -133,12 +139,16 @@ export class StorageService { public async getChecksum(file: Buffer): Promise { return new Promise((resolve) => { try { - const checksum = crypto.createHash("sha256").update(file).digest("hex").toLowerCase(); - resolve(checksum) + const checksum = crypto + .createHash("sha256") + .update(file) + .digest("hex") + .toLowerCase(); + resolve(checksum); } catch (err) { - throw new InternalServerErrorException(err) + throw new InternalServerErrorException(err); } - }) + }); } /** @@ -149,9 +159,13 @@ export class StorageService { * @param {boolean} [isDocumentation] - Optional flag to indicate if the file is a documentation file. * @returns {Promise} - A Promise that resolves to the generated file information. */ - public async generateInformation(file: Buffer, fileDisplayName: string, isDocumentation?: boolean): Promise { + public async generateInformation( + file: Buffer, + fileDisplayName: string, + isDocumentation?: boolean, + ): Promise { const fileType = await FileType.fileTypeFromBuffer(file); - const checksum = await this.getChecksum(file) + const checksum = await this.getChecksum(file); const fileName = `${isDocumentation ? "doc" : "file"}-${checksum}.${fileType.ext.toLowerCase()}`; return { fileName: fileName, @@ -159,24 +173,39 @@ export class StorageService { fileSize: file.byteLength, fileChecksum: checksum, fileType: fileType, - isDocumentation: isDocumentation || false - } + isDocumentation: isDocumentation || false, + }; } - public async new(fileDisplayName: string, file: Buffer, isDocumentation?: boolean) { + public async new( + fileDisplayName: string, + file: Buffer, + isDocumentation?: boolean, + ) { try { - const info = await this.generateInformation(file, fileDisplayName, isDocumentation); - console.log(`Trying to append a new file : "${info.fileDisplayName}"...\n > Checksum SHA-256 : ${info.fileChecksum}\n > Size : ${info.fileSize / (1024*1024)}Mio\n > File format : ${info.fileType.mime}\n`) - const condition = await this.checkConditions([/* TODO import autorized file format */], file) + const info = await this.generateInformation( + file, + fileDisplayName, + isDocumentation, + ); + console.log( + `Trying to append a new file : "${info.fileDisplayName}"...\n > Checksum SHA-256 : ${info.fileChecksum}\n > Size : ${info.fileSize / (1024 * 1024)}Mio\n > File format : ${info.fileType.mime}\n`, + ); + const condition = await this.checkConditions( + [ + /* TODO import autorized file format */ + ], + file, + ); if (!condition) { - console.warn(`File "${info.fileDisplayName}" did not pass the files requirement.\n${info.fileChecksum}`) + console.warn( + `File "${info.fileDisplayName}" did not pass the files requirement.\n${info.fileChecksum}`, + ); } //TODO Append in DB and save to storage - - } catch (err) { - throw new BadRequestException(err) + throw new BadRequestException(err); } } } diff --git a/apps/backend/src/app/storage/storage.types.ts b/apps/backend/src/app/storage/storage.types.ts index 071572b..888a151 100644 --- a/apps/backend/src/app/storage/storage.types.ts +++ b/apps/backend/src/app/storage/storage.types.ts @@ -1,17 +1,16 @@ -import FileType from 'file-type'; - +import FileType from "file-type"; export interface IFileInformation { - fileDisplayName: string; - fileName: string; - fileChecksum: string; - isDocumentation: boolean; - fileType: FileType.FileTypeResult; - fileSize: number; + fileDisplayName: string; + fileName: string; + fileChecksum: string; + isDocumentation: boolean; + fileType: FileType.FileTypeResult; + fileSize: number; } export interface IFileWithInformation { - buffer: Buffer; - info: IFileInformation; - additionalData?: AdditionalData -} \ No newline at end of file + buffer: Buffer; + info: IFileInformation; + additionalData?: AdditionalData; +} diff --git a/apps/frontend/src/components/ui/use-toast.ts b/apps/frontend/src/components/ui/use-toast.ts index 524a3fd..71b8d28 100644 --- a/apps/frontend/src/components/ui/use-toast.ts +++ b/apps/frontend/src/components/ui/use-toast.ts @@ -1,195 +1,192 @@ -"use client" +"use client"; // Inspired by react-hot-toast library -import * as React from "react" +import * as React from "react"; -import type { - ToastActionElement, - ToastProps, -} from "./toast" +import type { ToastActionElement, ToastProps } from "./toast"; -const TOAST_LIMIT = 1 -const TOAST_REMOVE_DELAY = 1000000 +const TOAST_LIMIT = 1; +const TOAST_REMOVE_DELAY = 1000000; type ToasterToast = ToastProps & { - id: string - title?: React.ReactNode - description?: React.ReactNode - action?: ToastActionElement -} + id: string; + title?: React.ReactNode; + description?: React.ReactNode; + action?: ToastActionElement; +}; const actionTypes = { - ADD_TOAST: "ADD_TOAST", - UPDATE_TOAST: "UPDATE_TOAST", - DISMISS_TOAST: "DISMISS_TOAST", - REMOVE_TOAST: "REMOVE_TOAST", -} as const + ADD_TOAST: "ADD_TOAST", + UPDATE_TOAST: "UPDATE_TOAST", + DISMISS_TOAST: "DISMISS_TOAST", + REMOVE_TOAST: "REMOVE_TOAST", +} as const; -let count = 0 +let count = 0; function genId() { - count = (count + 1) % Number.MAX_SAFE_INTEGER - return count.toString() + count = (count + 1) % Number.MAX_SAFE_INTEGER; + return count.toString(); } -type ActionType = typeof actionTypes +type ActionType = typeof actionTypes; type Action = - | { - type: ActionType["ADD_TOAST"] - toast: ToasterToast - } - | { - type: ActionType["UPDATE_TOAST"] - toast: Partial - } - | { - type: ActionType["DISMISS_TOAST"] - toastId?: ToasterToast["id"] - } - | { - type: ActionType["REMOVE_TOAST"] - toastId?: ToasterToast["id"] - } + | { + type: ActionType["ADD_TOAST"]; + toast: ToasterToast; + } + | { + type: ActionType["UPDATE_TOAST"]; + toast: Partial; + } + | { + type: ActionType["DISMISS_TOAST"]; + toastId?: ToasterToast["id"]; + } + | { + type: ActionType["REMOVE_TOAST"]; + toastId?: ToasterToast["id"]; + }; interface State { - toasts: ToasterToast[] + toasts: ToasterToast[]; } -const toastTimeouts = new Map>() +const toastTimeouts = new Map>(); const addToRemoveQueue = (toastId: string) => { - if (toastTimeouts.has(toastId)) { - return - } + if (toastTimeouts.has(toastId)) { + return; + } - const timeout = setTimeout(() => { - toastTimeouts.delete(toastId) - dispatch({ - type: "REMOVE_TOAST", - toastId: toastId, - }) - }, TOAST_REMOVE_DELAY) + const timeout = setTimeout(() => { + toastTimeouts.delete(toastId); + dispatch({ + type: "REMOVE_TOAST", + toastId: toastId, + }); + }, TOAST_REMOVE_DELAY); - toastTimeouts.set(toastId, timeout) -} + toastTimeouts.set(toastId, timeout); +}; export const reducer = (state: State, action: Action): State => { - switch (action.type) { - case "ADD_TOAST": - return { - ...state, - toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), - } + switch (action.type) { + case "ADD_TOAST": + return { + ...state, + toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), + }; - case "UPDATE_TOAST": - return { - ...state, - toasts: state.toasts.map((t) => - t.id === action.toast.id ? { ...t, ...action.toast } : t - ), - } + case "UPDATE_TOAST": + return { + ...state, + toasts: state.toasts.map((t) => + t.id === action.toast.id ? { ...t, ...action.toast } : t, + ), + }; - case "DISMISS_TOAST": { - const { toastId } = action + case "DISMISS_TOAST": { + const { toastId } = action; - // ! Side effects ! - This could be extracted into a dismissToast() action, - // but I'll keep it here for simplicity - if (toastId) { - addToRemoveQueue(toastId) - } else { - for (const toast1 of state.toasts) { - addToRemoveQueue(toast1.id) - } - } + // ! Side effects ! - This could be extracted into a dismissToast() action, + // but I'll keep it here for simplicity + if (toastId) { + addToRemoveQueue(toastId); + } else { + for (const toast1 of state.toasts) { + addToRemoveQueue(toast1.id); + } + } - return { - ...state, - toasts: state.toasts.map((t) => - t.id === toastId || toastId === undefined - ? { - ...t, - open: false, - } - : t - ), - } - } - case "REMOVE_TOAST": - if (action.toastId === undefined) { - return { - ...state, - toasts: [], - } - } - return { - ...state, - toasts: state.toasts.filter((t) => t.id !== action.toastId), - } - } -} + return { + ...state, + toasts: state.toasts.map((t) => + t.id === toastId || toastId === undefined + ? { + ...t, + open: false, + } + : t, + ), + }; + } + case "REMOVE_TOAST": + if (action.toastId === undefined) { + return { + ...state, + toasts: [], + }; + } + return { + ...state, + toasts: state.toasts.filter((t) => t.id !== action.toastId), + }; + } +}; -const listeners: Array<(state: State) => void> = [] +const listeners: Array<(state: State) => void> = []; -let memoryState: State = { toasts: [] } +let memoryState: State = { toasts: [] }; function dispatch(action: Action) { - memoryState = reducer(memoryState, action) - for (const listener of listeners) { - listener(memoryState) - } + memoryState = reducer(memoryState, action); + for (const listener of listeners) { + listener(memoryState); + } } -type Toast = Omit +type Toast = Omit; function toast({ ...props }: Toast) { - const id = genId() + const id = genId(); - const update = (props: ToasterToast) => - dispatch({ - type: "UPDATE_TOAST", - toast: { ...props, id }, - }) - const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) + const update = (props: ToasterToast) => + dispatch({ + type: "UPDATE_TOAST", + toast: { ...props, id }, + }); + const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }); - dispatch({ - type: "ADD_TOAST", - toast: { - ...props, - id, - open: true, - onOpenChange: (open) => { - if (!open) dismiss() - }, - }, - }) + dispatch({ + type: "ADD_TOAST", + toast: { + ...props, + id, + open: true, + onOpenChange: (open) => { + if (!open) dismiss(); + }, + }, + }); - return { - id: id, - dismiss, - update, - } + return { + id: id, + dismiss, + update, + }; } function useToast() { - const [state, setState] = React.useState(memoryState) + const [state, setState] = React.useState(memoryState); - // biome-ignore lint/correctness/useExhaustiveDependencies: - React.useEffect(() => { - listeners.push(setState) - return () => { - const index = listeners.indexOf(setState) - if (index > -1) { - listeners.splice(index, 1) - } - } - }, [state]) + // biome-ignore lint/correctness/useExhaustiveDependencies: + React.useEffect(() => { + listeners.push(setState); + return () => { + const index = listeners.indexOf(setState); + if (index > -1) { + listeners.splice(index, 1); + } + }; + }, [state]); - return { - ...state, - toast, - dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), - } + return { + ...state, + toast, + dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), + }; } -export { useToast, toast } +export { useToast, toast }; diff --git a/apps/frontend/src/lib/utils.ts b/apps/frontend/src/lib/utils.ts index d084cca..ac680b3 100644 --- a/apps/frontend/src/lib/utils.ts +++ b/apps/frontend/src/lib/utils.ts @@ -1,6 +1,6 @@ -import { type ClassValue, clsx } from "clsx" -import { twMerge } from "tailwind-merge" +import { type ClassValue, clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) + return twMerge(clsx(inputs)); }