Ajustes e add usurios

This commit is contained in:
LeoMortari
2025-11-02 20:40:34 -03:00
parent ca38cee6e3
commit 0f2c051eb9
6 changed files with 151 additions and 52 deletions

View File

@@ -25,7 +25,7 @@
"@nestjs/core": "11.0.1", "@nestjs/core": "11.0.1",
"@nestjs/passport": "11.0.5", "@nestjs/passport": "11.0.5",
"@nestjs/platform-express": "11.0.1", "@nestjs/platform-express": "11.0.1",
"@prisma/client": "6.14.0", "@prisma/client": "6.18.0",
"axios": "1.12.0", "axios": "1.12.0",
"bcrypt": "6.0.0", "bcrypt": "6.0.0",
"class-transformer": "0.5.1", "class-transformer": "0.5.1",
@@ -34,12 +34,8 @@
"dayjs": "1.11.13", "dayjs": "1.11.13",
"jwks-rsa": "3.2.0", "jwks-rsa": "3.2.0",
"lodash": "4.17.21", "lodash": "4.17.21",
"ollama": "0.6.0",
"openai": "6.1.0",
"passport": "0.7.0", "passport": "0.7.0",
"passport-jwt": "4.0.1", "passport-jwt": "4.0.1"
"reflect-metadata": "0.2.2",
"rxjs": "7.8.1"
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "3.2.0", "@eslint/eslintrc": "3.2.0",
@@ -60,7 +56,7 @@
"globals": "16.0.0", "globals": "16.0.0",
"jest": "30.0.0", "jest": "30.0.0",
"prettier": "3.4.2", "prettier": "3.4.2",
"prisma": "6.14.0", "prisma": "6.18.0",
"source-map-support": "0.5.21", "source-map-support": "0.5.21",
"supertest": "7.0.0", "supertest": "7.0.0",
"ts-jest": "29.2.5", "ts-jest": "29.2.5",

View File

@@ -36,21 +36,21 @@ enum eboolean {
} }
model videos { model videos {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
uuid String @default(dbgenerated("gen_random_uuid()")) @db.Uuid uuid String @default(dbgenerated("gen_random_uuid()")) @db.Uuid
datetime_download DateTime? @db.Timestamp(6) datetime_download DateTime? @db.Timestamp(6)
datetime_convert DateTime? @db.Timestamp(6) datetime_convert DateTime? @db.Timestamp(6)
url String @db.VarChar(244) url String @db.VarChar(244)
situation video_situation situation video_situation @default(FILA)
error_message String? @db.VarChar(244) error_message String? @db.VarChar(244)
clips_quantity Int? clips_quantity Int?
duration String? @db.VarChar(16) duration String? @db.VarChar(16)
title String? @db.VarChar(244) title String? @db.VarChar(244)
filename String? @db.VarChar(244) filename String? @db.VarChar(244)
videoid String? @db.VarChar(244) videoid String? @db.VarChar(244)
datetime_posted DateTime? @db.Timestamp(6) datetime_posted DateTime? @db.Timestamp(6)
usuario_id Int? usuario_id Int?
usuario Usuario? @relation(fields: [usuario_id], references: [id]) usuario Usuario? @relation(fields: [usuario_id], references: [id])
@@map("videos") @@map("videos")
} }

View File

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

View File

@@ -1,24 +1,42 @@
import { import {
Body,
Controller, Controller,
Get, Get,
Param, Param,
Patch,
Post, Post,
Body, Query,
UsePipes, UsePipes,
ValidationPipe, ValidationPipe,
Patch,
} from '@nestjs/common'; } from '@nestjs/common';
import { UsuariosService } from './usuarios.service'; import { UsuariosService } from './usuarios.service';
import { UsuariosResponseDto } from './dto/usuarios.response'; import { UsuariosResponseDto } from './dto/usuarios.response';
import { CreateUsuarioDto } from './dto/create-usuario-dto'; import { CreateUsuarioDto } from './dto/create-usuario-dto';
import { PaginatedResponse } from '@shared/dto/paginated';
import { ListUsuariosQueryDto } from './dto/list-usuarios-query.dto';
@Controller('usuarios') @Controller('usuarios')
export class UsuariosController { export class UsuariosController {
constructor(private readonly usuariosService: UsuariosService) {} constructor(private readonly usuariosService: UsuariosService) {}
@Get() @Get()
async list(): Promise<UsuariosResponseDto[]> { async list(
return this.usuariosService.list(); @Query() query: ListUsuariosQueryDto,
): Promise<PaginatedResponse<UsuariosResponseDto> | 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') @Get(':uuid')

View File

@@ -9,6 +9,17 @@ import { PaginatedResponse } from '@shared/dto/paginated';
import { UsuariosResponseDto } from './dto/usuarios.response'; import { UsuariosResponseDto } from './dto/usuarios.response';
import { CreateUsuarioDto } from './dto/create-usuario-dto'; 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 = { const SELECT = {
id: true, id: true,
uuid: true, uuid: true,
@@ -30,9 +41,37 @@ const SELECT = {
export class UsuariosService { export class UsuariosService {
constructor(private readonly prisma: PrismaService) {} constructor(private readonly prisma: PrismaService) {}
async list(): Promise<UsuariosResponseDto[]> { 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<UsuariosResponseDto[]> {
const where = this.buildWhere(filters);
const data = await this.prisma.usuario.findMany({ const data = await this.prisma.usuario.findMany({
where: { email: { not: 'admin@clipperia.com' } }, where,
orderBy: { id: 'desc' }, orderBy: { id: 'desc' },
select: SELECT, select: SELECT,
}); });
@@ -43,20 +82,35 @@ export class UsuariosService {
} }
async listPaginated( async listPaginated(
page: number, params: ListUsuariosPaginatedParams,
perPage: number,
direction: 'asc' | 'desc' = 'desc',
): Promise<PaginatedResponse<UsuariosResponseDto>> { ): Promise<PaginatedResponse<UsuariosResponseDto>> {
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([ const [rows, total] = await Promise.all([
this.prisma.usuario.findMany({ this.prisma.usuario.findMany({
orderBy: { id: direction }, where,
orderBy: { id: safeDirection },
skip, skip,
take: perPage ?? 1, take: safePerPage,
select: SELECT, select: SELECT,
}), }),
this.prisma.usuario.count(), this.prisma.usuario.count({ where }),
]); ]);
const content: UsuariosResponseDto[] = plainToInstance( const content: UsuariosResponseDto[] = plainToInstance(
@@ -65,18 +119,18 @@ export class UsuariosService {
{ excludeExtraneousValues: true }, { excludeExtraneousValues: true },
); );
const totalPages = Math.max(1, Math.ceil(total / perPage)); const totalPages = Math.max(1, Math.ceil(total / safePerPage));
return { return {
content, content,
pagination: { pagination: {
page, page: safePage,
direction, direction: safeDirection,
perPage, perPage: safePerPage,
total, total,
totalPages, totalPages,
hasNext: page < totalPages, hasNext: safePage < totalPages,
hasPrev: page > 1, hasPrev: safePage > 1,
}, },
}; };
} }

View File

@@ -155,7 +155,7 @@ export class VideosService {
} }
async createNewVideo(data: CreateVideoDto): Promise<void> { async createNewVideo(data: CreateVideoDto): Promise<void> {
const { url, videoid, duration, qualidade, title, timestamp } = data; const { url, videoid, duration, qualidade, title } = data;
const query: Prisma.videosWhereInput = { url }; const query: Prisma.videosWhereInput = { url };
@@ -194,23 +194,19 @@ export class VideosService {
createData.duration = formattedDuration; createData.duration = formattedDuration;
} }
if (typeof timestamp === 'number' && Number.isFinite(timestamp)) {
createData.datetime_download = new Date(timestamp * 1000);
}
await this.prisma.videos.create({ await this.prisma.videos.create({
data: createData, data: createData,
}); });
// const params = { const params = {
// url, url,
// videoid, videoid,
// qualidade: qualidade === 'automatic' ? 'medium' : qualidade, qualidade: qualidade === 'automatic' ? 'medium' : qualidade,
// }; };
// await axios.get(`${N8N_REMOTE_SERVER}/webhook/download-video`, { await axios.get(`${N8N_REMOTE_SERVER}/webhook/download-video`, {
// params, params,
// }); });
} }
async update(id: number, data: Prisma.videosUpdateInput): Promise<videos> { async update(id: number, data: Prisma.videosUpdateInput): Promise<videos> {