Compare commits

...

6 Commits

Author SHA1 Message Date
4547a22f5c
Add Swagger metadata to DTOs and controllers
Enhanced API documentation by adding Swagger decorators like @ApiProperty, @ApiTags, and @ApiBearerAuth to DTOs and controllers. This will improve clarity and usability of the API for developers using Swagger.
2024-10-17 14:21:23 +02:00
1020d6283d
Refactor code to improve readability and consistency
Reformatted import statements and function parameters for better readability. Improved alignment and punctuation to enhance code consistency and maintainability.
2024-10-17 12:26:51 +02:00
0330358139
Add missing semicolons for consistency
This commit adds missing semicolons to type definitions in schema.ts for consistent code style and better readability. No functional changes were made to the existing code logic.
2024-10-17 12:25:11 +02:00
38634132ba
Add search method to Files Service
Implemented a method to search for files in the database by limit, offset, and search term. This method enhances the service by providing a way to paginate and filter file results.
2024-10-17 12:21:58 +02:00
7b4792b612
Fix data type in pagination schema
Updated the `data` property in the pagination schema from a single object to an array of objects to accurately represent paginated data. This change ensures that the schema aligns with the actual data structure used in the application.
2024-10-17 12:21:21 +02:00
989ec71e2e
Fix data type in pagination schema
Updated the `data` property in the pagination schema from a single object to an array of objects to accurately represent paginated data. This change ensures that the schema aligns with the actual data structure used in the application.
2024-10-17 12:21:14 +02:00
13 changed files with 103 additions and 37 deletions

View File

@ -1,8 +1,10 @@
import { Controller, Get } from "@nestjs/common";
import { AppService } from "./app.service";
import { ApiTags } from '@nestjs/swagger';
@Controller()
@ApiTags("useless")
export class AppController {
constructor(private readonly appService: AppService) {}

View File

@ -13,7 +13,9 @@ import {
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 { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
@ApiTags('User authentification')
@Controller("auth")
export class AuthController {
constructor(private readonly authService: AuthService) {}
@ -33,6 +35,7 @@ export class AuthController {
return this.authService.doLogin(dto);
}
//GET me -- Get current user data via jwt
@ApiBearerAuth()
@HttpCode(HttpStatus.OK)
@Get("me")
@UseGuards(UserGuard)
@ -46,6 +49,7 @@ export class AuthController {
return userData;
}
//DELETE me
@ApiBearerAuth()
@HttpCode(HttpStatus.FOUND)
@Delete("me")
@UseGuards(UserGuard)

View File

@ -6,6 +6,7 @@ import {
MaxLength,
MinLength,
} from "class-validator";
import { ApiProperty } from '@nestjs/swagger';
export class SignUpDto {
/*
@ -22,11 +23,17 @@ export class SignUpDto {
lastName: string;
**/
@ApiProperty({
example: 'jean@paul.fr',
})
@MaxLength(32)
@IsEmail()
@IsNotEmpty()
email: string;
@ApiProperty({
example: 'zSEs-6ze$',
})
@IsString()
@IsNotEmpty()
@IsStrongPassword({
@ -36,12 +43,16 @@ export class SignUpDto {
}
export class SignInDto {
@MaxLength(32)
@MaxLength(32)@ApiProperty({
example: 'jean@paul.fr',
})
@IsEmail()
@IsNotEmpty()
email: string;
@IsString()
@IsString()@ApiProperty({
example: 'zSEs-6ze$',
})
@IsNotEmpty()
@IsStrongPassword({
minLength: 6,

View File

@ -11,7 +11,9 @@ import {
} from "@nestjs/common";
import { AdminGuard } from "apps/backend/src/app/auth/auth.guard";
import { AuthorsService } from "apps/backend/src/app/authors/authors.service";
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
@ApiTags('File authors')
@Controller("authors")
export class AuthorsController {
constructor(private readonly authorService: AuthorsService) {}
@ -25,8 +27,8 @@ export class AuthorsController {
return await this.authorService.find(limit, offset, search);
}
//TODO DTO
//TODO Refactor
@ApiBearerAuth()
@UseGuards(AdminGuard)
@Delete(":autor")
async deleteAuthor(@Param("author") author: string) {

View File

@ -103,7 +103,7 @@ export const FilesTable = pgTable("files", {
})
.notNull(),
});
export type IFileTable = typeof FilesTable.$inferSelect
export type IFileTable = typeof FilesTable.$inferSelect;
export const FilesGroupTable = pgTable("f_groups", {
uuid: p.uuid("uuid").unique().primaryKey().defaultRandom().notNull(),
@ -115,8 +115,7 @@ export const FilesGroupTable = pgTable("f_groups", {
.unique()
.notNull(),
});
export type IFileGroupTable = typeof FilesGroupTable.$inferSelect
export type IFileGroupTable = typeof FilesGroupTable.$inferSelect;
//TODO Files types
export const FilesTypesTable = pgTable("f_types", {
@ -137,7 +136,7 @@ export const FilesTypesTable = pgTable("f_types", {
.unique()
.notNull(),
});
export type IFilesTypesTable = typeof FilesTypesTable.$inferSelect
export type IFilesTypesTable = typeof FilesTypesTable.$inferSelect;
export const MachinesTable = pgTable("machines", {
id: p.uuid("id").unique().primaryKey().defaultRandom().notNull(),
@ -156,7 +155,7 @@ export const MachinesTable = pgTable("machines", {
//supported files format
});
export type IMachinesTable = typeof MachinesTable.$inferSelect
export type IMachinesTable = typeof MachinesTable.$inferSelect;
//TODO Many to Many table betwen File en Machine
export const FilesForMachinesTable = pgTable("files_for_machines", {
@ -172,7 +171,7 @@ export const FilesForMachinesTable = pgTable("files_for_machines", {
.notNull()
.references(() => MachinesTable.id),
});
export type IFilesForMachinesTable = typeof FilesForMachinesTable.$inferSelect
export type IFilesForMachinesTable = typeof FilesForMachinesTable.$inferSelect;
export const FilesTypeForMachine = pgTable("f_type_for_machines", {
id: p.uuid("id").unique().primaryKey().defaultRandom().notNull(),
@ -186,11 +185,11 @@ export const FilesTypeForMachine = pgTable("f_type_for_machines", {
.notNull()
.references(() => FilesTypesTable.id),
});
export type IFilesTypeForMachine = typeof FilesTypeForMachine.$inferSelect
export type IFilesTypeForMachine = typeof FilesTypeForMachine.$inferSelect;
export interface IWithCount<T> {
count: number;
limit: number;
currentOffset: number;
data: T
data: T[];
}

View File

@ -23,7 +23,9 @@ import {
import { CreateFileTypeDto } from "apps/backend/src/app/files/files.dto";
import { AdminGuard, InsertAdminState } from "../auth/auth.guard";
import { FilesService } from "./files.service";
import { ApiBearerAuth, ApiSecurity, ApiTags } from '@nestjs/swagger';
@ApiTags('Files')
@Controller("files")
export class FilesController {
constructor(private readonly filesService: FilesService) {}
@ -129,6 +131,7 @@ export class FilesController {
return await this.filesService.getAllFilesTypes();
}
@ApiBearerAuth()
@HttpCode(HttpStatus.CREATED)
@UseGuards(AdminGuard)
@Post("types/new")
@ -136,6 +139,7 @@ export class FilesController {
return await this.filesService.createFileType(body.name, body.mime);
}
@ApiBearerAuth()
@HttpCode(HttpStatus.ACCEPTED)
@UseGuards(AdminGuard)
@Delete("types/:typeId")
@ -149,6 +153,7 @@ export class FilesController {
return await this.filesService.get(fileId);
}
@ApiBearerAuth()
@HttpCode(HttpStatus.OK)
@UseGuards(AdminGuard)
@Delete(":fileId")

View File

@ -1,27 +1,26 @@
import { DefaultValuePipe } from "@nestjs/common";
import { IsUUID, MaxLength, MinLength } from "class-validator";
export class CreateFilesDto {
@MaxLength(128)
@MinLength(4)
fileName: string;
@MaxLength(64)
@MinLength(2)
uploadedBy: string;
isDocumentation?: boolean;
isRestricted?: boolean;
@IsUUID()
groupId: string;
}
import { ApiBearerAuth, ApiProperty } from '@nestjs/swagger';
export class CreateFileTypeDto {
@ApiProperty({
description: "Admin uniquement, nom d'affichage.",
examples: [
".scad",
"jpg"
]
})
@MaxLength(128)
@MinLength(3)
name: string;
@ApiProperty({
description: "Admin uniquement, Multipurpose Internet Mail Extensions (MIME)",
examples: [
"application/x-openscad",
"image/jpeg"
]
})
@MaxLength(64)
@MinLength(4)
mime: string;

View File

@ -12,10 +12,12 @@ import {
FilesTable,
FilesTypeForMachine,
FilesTypesTable,
IFileTable,
IWithCount,
MachinesTable,
} from "apps/backend/src/app/db/schema";
import { StorageService } from "apps/backend/src/app/storage/storage.service";
import { eq, ilike } from "drizzle-orm";
import { count, eq, ilike } from "drizzle-orm";
@Injectable()
export class FilesService {
@ -124,17 +126,27 @@ export class FilesService {
}
/**
* Searches for files in the database using the specified search field, limit, and offset.
* Searches for files in the database based on the provided search field, limit, and offset.
*
* @param {number} limit - The maximum number of results to return.
* @param {number} offset - The number of results to skip before starting to return results.
* @param {string} searchField - The field used to search for matching file names.
*
* @return {Promise<object>} A promise that resolves to the search results.
* @param {number} offset - The offset for the results.
* @param {string} searchField - The value to search for within the file names.
* @return {Promise<IWithCount<IFileTable>>} A promise that resolves to an object containing the count of files that match the search criteria, the provided limit, the current offset, and the matching data.
*/
public async search(limit: number, offset: number, searchField: string) {
public async search(
limit: number,
offset: number,
searchField: string,
): Promise<IWithCount<IFileTable>> {
try {
return await this.database
const countResult = await this.database
.use()
.select({ count: count() })
.from(FilesTable)
.where(ilike(FilesTable.fileName, String(`%${searchField}%`)))
.prepare("searchFilesCount")
.execute();
const dataResult = await this.database
.use()
.select()
.from(FilesTable)
@ -143,6 +155,12 @@ export class FilesService {
.offset(offset)
.prepare("searchFiles")
.execute();
return {
count: countResult[0].count,
limit: limit,
currentOffset: offset,
data: dataResult,
};
} catch (error) {
throw new InternalServerErrorException(error);
}

View File

@ -14,7 +14,9 @@ import { AdminGuard } from "apps/backend/src/app/auth/auth.guard";
import { CreateGroupDto } from "apps/backend/src/app/groups/groups.dto";
import { ISearchQuery } from "apps/backend/src/app/groups/groups.types";
import { GroupsService } from "./groups.service";
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
@ApiTags('File groups')
@Controller("groups")
export class GroupsController {
constructor(private readonly groupsService: GroupsService) {}
@ -33,6 +35,7 @@ export class GroupsController {
return await this.groupsService.newGroup(body.groupName);
}
@ApiBearerAuth()
@UseGuards(AdminGuard)
@Delete(":groupId")
async deleteGroup(@Param("groupId") groupId: string) {

View File

@ -1,6 +1,11 @@
import { IsString, MaxLength, MinLength } from "class-validator";
import { ApiProperty } from '@nestjs/swagger';
export class CreateGroupDto {
@ApiProperty({
description: "Nom unique.",
example: "Numérique en communs"
})
@IsString()
@MinLength(4)
@MaxLength(64)

View File

@ -19,7 +19,9 @@ import {
TypeDto,
} from "apps/backend/src/app/machines/machines.dto";
import { MachinesService } from "apps/backend/src/app/machines/machines.service";
import { ApiTags } from '@nestjs/swagger';
@ApiTags('Machines')
@Controller("machines")
export class MachinesController {
constructor(private readonly machineService: MachinesService) {}

View File

@ -1,16 +1,27 @@
import { IsUUID, MaxLength, MinLength } from "class-validator";
import { ApiProperty } from '@nestjs/swagger';
export class CreateMachineDto {
@ApiProperty({
example: "Découpeuse laser portable"
})
@MaxLength(128)
@MinLength(4)
machineName: string;
@ApiProperty({
example: "Découpe au laser"
})
@MaxLength(64)
@MinLength(2)
machineType: string;
}
export class TypeDto {
@ApiProperty({
description: "Un identifiant unique présent en base de donnée qui représente un MIME",
example: "dfd0fbb1-2bf3-4dbe-b86d-89b1bff5106c"
})
@IsUUID()
fileTypeId: string;
}

View File

@ -10,6 +10,11 @@ async function bootstrap() {
.setTitle("Fab Explorer")
.setDescription("Définition de l'api du FabLab Explorer")
.setVersion("1.0")
.addBearerAuth({
type: 'http',
scheme: 'bearer',
in: 'header',
})
.build();
const app = await NestFactory.create(AppModule);