diff --git a/package.json b/package.json index f50ada8..8dff000 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@nestjs/core": "11.0.1", "@nestjs/passport": "11.0.5", "@nestjs/platform-express": "11.0.1", - "@prisma/client": "6.14.0", + "@prisma/client": "6.18.0", "axios": "1.12.0", "bcrypt": "6.0.0", "class-transformer": "0.5.1", @@ -34,12 +34,8 @@ "dayjs": "1.11.13", "jwks-rsa": "3.2.0", "lodash": "4.17.21", - "ollama": "0.6.0", - "openai": "6.1.0", "passport": "0.7.0", - "passport-jwt": "4.0.1", - "reflect-metadata": "0.2.2", - "rxjs": "7.8.1" + "passport-jwt": "4.0.1" }, "devDependencies": { "@eslint/eslintrc": "3.2.0", @@ -60,7 +56,7 @@ "globals": "16.0.0", "jest": "30.0.0", "prettier": "3.4.2", - "prisma": "6.14.0", + "prisma": "6.18.0", "source-map-support": "0.5.21", "supertest": "7.0.0", "ts-jest": "29.2.5", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 4574b8b..7a6ab82 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -36,21 +36,21 @@ enum eboolean { } model videos { - id Int @id @default(autoincrement()) - uuid String @default(dbgenerated("gen_random_uuid()")) @db.Uuid - datetime_download DateTime? @db.Timestamp(6) - datetime_convert DateTime? @db.Timestamp(6) - url String @db.VarChar(244) - situation video_situation - error_message String? @db.VarChar(244) + id Int @id @default(autoincrement()) + uuid String @default(dbgenerated("gen_random_uuid()")) @db.Uuid + datetime_download DateTime? @db.Timestamp(6) + datetime_convert DateTime? @db.Timestamp(6) + url String @db.VarChar(244) + situation video_situation @default(FILA) + error_message String? @db.VarChar(244) clips_quantity Int? - duration String? @db.VarChar(16) - title String? @db.VarChar(244) - filename String? @db.VarChar(244) - videoid String? @db.VarChar(244) - datetime_posted DateTime? @db.Timestamp(6) + duration String? @db.VarChar(16) + title String? @db.VarChar(244) + filename String? @db.VarChar(244) + videoid String? @db.VarChar(244) + datetime_posted DateTime? @db.Timestamp(6) usuario_id Int? - usuario Usuario? @relation(fields: [usuario_id], references: [id]) + usuario Usuario? @relation(fields: [usuario_id], references: [id]) @@map("videos") } diff --git a/src/modules/usuarios/dto/list-usuarios-query.dto.ts b/src/modules/usuarios/dto/list-usuarios-query.dto.ts new file mode 100644 index 0000000..fc1f57e --- /dev/null +++ b/src/modules/usuarios/dto/list-usuarios-query.dto.ts @@ -0,0 +1,35 @@ +import { Transform } from 'class-transformer'; +import { IsBoolean, IsNumber, IsOptional, IsString } from 'class-validator'; + +const trimString = ({ value }: { value: unknown }): string | undefined => + typeof value === 'string' ? value.trim() : undefined; + +export class ListUsuariosQueryDto { + @IsOptional() + @IsString() + @Transform(trimString) + name?: string; + + @IsOptional() + @IsString() + @Transform(trimString) + email?: string; + + @IsNumber() + @IsOptional() + @Transform(({ value }) => (value ? Number(value) : 1)) + page?: number; + + @IsNumber() + @IsOptional() + @Transform(({ value }) => (value ? Number(value) : 10)) + perPage?: number = 10; + + @IsOptional() + direction: 'asc' | 'desc' = 'desc'; + + @Transform(({ value }) => value !== 'false') + @IsBoolean() + @IsOptional() + pageable: boolean = true; +} diff --git a/src/modules/usuarios/usuarios.controller.ts b/src/modules/usuarios/usuarios.controller.ts index 1dda8a1..b4d591f 100644 --- a/src/modules/usuarios/usuarios.controller.ts +++ b/src/modules/usuarios/usuarios.controller.ts @@ -1,24 +1,42 @@ import { + Body, Controller, Get, Param, + Patch, Post, - Body, + Query, UsePipes, ValidationPipe, - Patch, } from '@nestjs/common'; import { UsuariosService } from './usuarios.service'; import { UsuariosResponseDto } from './dto/usuarios.response'; import { CreateUsuarioDto } from './dto/create-usuario-dto'; +import { PaginatedResponse } from '@shared/dto/paginated'; +import { ListUsuariosQueryDto } from './dto/list-usuarios-query.dto'; @Controller('usuarios') export class UsuariosController { constructor(private readonly usuariosService: UsuariosService) {} @Get() - async list(): Promise { - return this.usuariosService.list(); + async list( + @Query() query: ListUsuariosQueryDto, + ): Promise | UsuariosResponseDto[]> { + if (query.pageable || query.page || query.perPage) { + return this.usuariosService.listPaginated({ + page: query.page, + perPage: query.perPage, + direction: query.direction, + name: query.name, + email: query.email, + }); + } + + return this.usuariosService.list({ + name: query.name, + email: query.email, + }); } @Get(':uuid') diff --git a/src/modules/usuarios/usuarios.service.ts b/src/modules/usuarios/usuarios.service.ts index f67cd90..0e1ae90 100644 --- a/src/modules/usuarios/usuarios.service.ts +++ b/src/modules/usuarios/usuarios.service.ts @@ -9,6 +9,17 @@ import { PaginatedResponse } from '@shared/dto/paginated'; import { UsuariosResponseDto } from './dto/usuarios.response'; import { CreateUsuarioDto } from './dto/create-usuario-dto'; +type ListUsuariosFilters = { + name?: string; + email?: string; +}; + +type ListUsuariosPaginatedParams = ListUsuariosFilters & { + page?: number; + perPage?: number; + direction?: 'asc' | 'desc'; +}; + const SELECT = { id: true, uuid: true, @@ -30,9 +41,37 @@ const SELECT = { export class UsuariosService { constructor(private readonly prisma: PrismaService) {} - async list(): Promise { + private buildWhere({ + name, + email, + }: ListUsuariosFilters): Prisma.UsuarioWhereInput { + const andConditions: Prisma.UsuarioWhereInput[] = [ + { email: { not: 'admin@clipperia.com' } }, + ]; + + if (name) { + andConditions.push({ + OR: [ + { nome: { contains: name, mode: 'insensitive' } }, + { sobrenome: { contains: name, mode: 'insensitive' } }, + ], + }); + } + + if (email) { + andConditions.push({ email: { contains: email, mode: 'insensitive' } }); + } + + return { AND: andConditions }; + } + + async list( + filters: ListUsuariosFilters = {}, + ): Promise { + const where = this.buildWhere(filters); + const data = await this.prisma.usuario.findMany({ - where: { email: { not: 'admin@clipperia.com' } }, + where, orderBy: { id: 'desc' }, select: SELECT, }); @@ -43,20 +82,35 @@ export class UsuariosService { } async listPaginated( - page: number, - perPage: number, - direction: 'asc' | 'desc' = 'desc', + params: ListUsuariosPaginatedParams, ): Promise> { - const skip = page >= 1 ? page * perPage : 0; + const parsedPage = Number(params.page); + const safePage = + Number.isFinite(parsedPage) && parsedPage > 0 + ? Math.floor(parsedPage) + : 1; + + const parsedPerPage = Number(params.perPage); + const safePerPage = + Number.isFinite(parsedPerPage) && parsedPerPage > 0 + ? Math.floor(parsedPerPage) + : 10; + + const safeDirection: 'asc' | 'desc' = + params.direction === 'asc' ? 'asc' : 'desc'; + + const where = this.buildWhere(params); + const skip = (safePage - 1) * safePerPage; const [rows, total] = await Promise.all([ this.prisma.usuario.findMany({ - orderBy: { id: direction }, + where, + orderBy: { id: safeDirection }, skip, - take: perPage ?? 1, + take: safePerPage, select: SELECT, }), - this.prisma.usuario.count(), + this.prisma.usuario.count({ where }), ]); const content: UsuariosResponseDto[] = plainToInstance( @@ -65,18 +119,18 @@ export class UsuariosService { { excludeExtraneousValues: true }, ); - const totalPages = Math.max(1, Math.ceil(total / perPage)); + const totalPages = Math.max(1, Math.ceil(total / safePerPage)); return { content, pagination: { - page, - direction, - perPage, + page: safePage, + direction: safeDirection, + perPage: safePerPage, total, totalPages, - hasNext: page < totalPages, - hasPrev: page > 1, + hasNext: safePage < totalPages, + hasPrev: safePage > 1, }, }; } diff --git a/src/modules/videos/videos.service.ts b/src/modules/videos/videos.service.ts index e7f66a2..8b55157 100644 --- a/src/modules/videos/videos.service.ts +++ b/src/modules/videos/videos.service.ts @@ -155,7 +155,7 @@ export class VideosService { } async createNewVideo(data: CreateVideoDto): Promise { - const { url, videoid, duration, qualidade, title, timestamp } = data; + const { url, videoid, duration, qualidade, title } = data; const query: Prisma.videosWhereInput = { url }; @@ -194,23 +194,19 @@ export class VideosService { createData.duration = formattedDuration; } - if (typeof timestamp === 'number' && Number.isFinite(timestamp)) { - createData.datetime_download = new Date(timestamp * 1000); - } - await this.prisma.videos.create({ data: createData, }); - // const params = { - // url, - // videoid, - // qualidade: qualidade === 'automatic' ? 'medium' : qualidade, - // }; + const params = { + url, + videoid, + qualidade: qualidade === 'automatic' ? 'medium' : qualidade, + }; - // await axios.get(`${N8N_REMOTE_SERVER}/webhook/download-video`, { - // params, - // }); + await axios.get(`${N8N_REMOTE_SERVER}/webhook/download-video`, { + params, + }); } async update(id: number, data: Prisma.videosUpdateInput): Promise {