Se agregó la documentación en swagger

This commit is contained in:
2025-03-11 15:47:32 -06:00
parent c52b997db6
commit 27888ef2f8
7 changed files with 172 additions and 57 deletions
+11 -5
View File
@@ -1,14 +1,20 @@
import { Controller, Get } from '@nestjs/common';
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiTags, ApiConsumes } from '@nestjs/swagger';
import { ExcelService } from './excel.service';
import { ApiReadEmails } from './excel.decorators';
@ApiTags('Excel') // Agrupa los endpoints en Swagger
@Controller('excel')
export class ExcelController {
constructor(private readonly excelService: ExcelService) {}
@Get('read-emails')
async getEmails() {
const filePath = './src/excel_Usuarios/usuarios_fake.xlsx';
const emails = this.excelService.readEmailsFromExcel(filePath);
@Post('read-emails')
@UseInterceptors(FileInterceptor('file')) // Permite subir archivos
@ApiConsumes('multipart/form-data') // Indica que se usa un formulario con archivos
@ApiReadEmails()
async getEmails(@UploadedFile() file: Express.Multer.File) {
const emails = await this.excelService.readEmailsFromExcel(file);
return { emails };
}
}
+45
View File
@@ -0,0 +1,45 @@
import { applyDecorators } from '@nestjs/common';
import { ApiBody, ApiConsumes, ApiOperation, ApiResponse } from '@nestjs/swagger';
export const ApiReadEmails = () => {
return applyDecorators(
ApiOperation({
summary: 'Leer correos desde un archivo Excel',
description: `Este endpoint permite subir un archivo Excel y extraer los correos electrónicos de la primera columna.
El archivo debe ser un **.xlsx** válido con una estructura adecuada.`,
}),
ApiConsumes('multipart/form-data'),
ApiBody({
description: 'Sube un archivo Excel con correos',
schema: {
type: 'object',
properties: {
file: {
type: 'string',
format: 'binary',
},
},
},
}),
ApiResponse({
status: 200,
description: 'Lista de correos extraídos exitosamente',
schema: {
example: {
emails: ['usuario1@example.com', 'usuario2@example.com', 'usuario3@example.com'],
},
},
}),
ApiResponse({
status: 400,
description: 'Error en la lectura del archivo Excel',
schema: {
example: {
statusCode: 400,
message: 'Formato de archivo inválido o columna de correos no encontrada',
error: 'Bad Request',
},
},
}),
);
};
+3 -3
View File
@@ -4,17 +4,17 @@ import { Injectable } from '@nestjs/common';
@Injectable()
export class ExcelService {
async readEmailsFromExcel(filePath: string): Promise<string[]> {
async readEmailsFromExcel(file: Express.Multer.File) {
if (!fs.existsSync(filePath)) {
if (!file) {
throw new Error('Archivo Excel no encontrado');
}
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.readFile(filePath); // 🔹 `await` para leer el archivo correctamente
await workbook.xlsx.load(file.buffer); // 🔹 `await` para leer el archivo correctamente
const worksheet = workbook.getWorksheet(1); // Obtiene la primera hoja
if (!worksheet) {
+7 -48
View File
@@ -7,11 +7,9 @@ import {
} from '@nestjs/common';
import { MailService } from './mail.service';
import { ExcelService } from 'src/excel/excel.service';
import { FileInterceptor } from '@nestjs/platform-express';
import * as fs from 'fs';
import * as csv from 'csv-parser';
import { diskStorage } from 'multer'; // Importar para almacenar en el sistema de archivos
import { ApiTags } from '@nestjs/swagger';
import { ApiSendMail, ApiSendMailExcel} from './mail.decorators';
@ApiTags('Mail') // Grupo de endpoints
@Controller('mail')
@@ -22,7 +20,9 @@ export class MailController {
) {}
// Endpoint para enviar correos a través de una solicitud POST
@Post('send')
@ApiSendMail()
async sendMail(@Body() body: { to: string; subject: string; text: string; fecha_recibido: Date }) {
const { to, subject, text, fecha_recibido } = body;
@@ -31,9 +31,10 @@ export class MailController {
}
@Post('send-excel')
async sendMailExcel() {
@ApiSendMailExcel()
async sendMailExcel(@UploadedFile() file: Express.Multer.File) {
const emails=this.excelService.readEmailsFromExcel('./src/excel_Usuarios/usuarios_fake.xlsx');
const emails=this.excelService.readEmailsFromExcel(file);
let fechaActual: Date = new Date();
for (const email of await emails) {
@@ -45,46 +46,4 @@ export class MailController {
}
}
}
@Post('send-bulk')
//@UseInterceptors(FileInterceptor('file'))
@UseInterceptors(
FileInterceptor('file', {
storage: diskStorage({
destination: './uploads', // Carpeta donde guardar los archivos
filename: (req, file, cb) => {
// Guardar el archivo con su nombre original
const filename = file.originalname;
cb(null, filename);
},
}),
}),
)
async sendBulkMails(@UploadedFile() file: Express.Multer.File) {
const emails: string[] = [];
const subject = 'Correo de prueba';
const text = 'Este es un correo enviado de manera masiva.';
// Leer el archivo CSV
return new Promise((resolve, reject) => {
fs.createReadStream(file.path)
.pipe(csv())
.on('data', (row) => {
emails.push(row.email); // Agregar cada correo a la lista
})
.on('end', async () => {
// Enviar correos en bulk usando el servicio de correos
const result = await this.mailService.sendBulkMails(
emails,
subject,
text,
);
resolve(result);
})
.on('error', (error) => {
reject(error);
});
});
}
}
+91
View File
@@ -0,0 +1,91 @@
import { applyDecorators } from '@nestjs/common';
import { ApiBody, ApiConsumes, ApiOperation, ApiResponse } from '@nestjs/swagger';
export const ApiSendMail = () => {
return applyDecorators(
ApiOperation({
summary: 'Enviar un correo manualmente',
description: `Este endpoint permite enviar un correo individualmente. Se requiere proporcionar:
- **to**: Dirección de correo del destinatario.
- **subject**: Asunto del correo.
- **text**: Cuerpo del mensaje.
- **fecha_recibido**: Fecha en que se registró la solicitud.`,
}),
ApiBody({
description: 'Datos del correo a enviar',
schema: {
type: 'object',
properties: {
to: { type: 'string', example: 'usuario@example.com' },
subject: { type: 'string', example: 'Asunto del correo' },
text: { type: 'string', example: 'Cuerpo del mensaje' },
fecha_recibido: { type: 'string', format: 'date-time', example: '2025-03-10T12:00:00Z' }
},
},
}),
ApiResponse({
status: 200,
description: 'Correo enviado con éxito',
schema: {
example: {
message: 'Correo enviado correctamente',
},
},
}),
ApiResponse({
status: 400,
description: 'Error en el envío del correo',
schema: {
example: {
statusCode: 400,
message: 'Dirección de correo inválida',
error: 'Bad Request',
},
},
}),
);
};
export const ApiSendMailExcel = () => {
return applyDecorators(
ApiOperation({
summary: 'Enviar correos desde un archivo Excel',
description: `Este endpoint permite enviar correos a partir de una lista contenida en un archivo Excel.
El archivo debe contener una columna con direcciones de correo válidas.`,
}),
ApiConsumes('multipart/form-data'),
ApiBody({
description: 'Sube un archivo Excel con correos',
schema: {
type: 'object',
properties: {
file: {
type: 'string',
format: 'binary',
},
},
},
}),
ApiResponse({
status: 200,
description: 'Correos enviados exitosamente',
schema: {
example: {
message: 'Correos enviados correctamente',
emails: ['usuario1@example.com', 'usuario2@example.com'],
},
},
}),
ApiResponse({
status: 400,
description: 'Error al procesar el archivo',
schema: {
example: {
statusCode: 400,
message: 'El archivo no es un Excel válido',
error: 'Bad Request',
},
},
}),
);
};
+1 -1
View File
@@ -12,7 +12,7 @@ export class MailService {
private transporter;
constructor(
@InjectRepository(Correo) private readonly correoRepository: Repository<Correo>,
@InjectRepository(Correo) private readonly correoRepository: Repository<Correo>,
@InjectRepository(Status) private readonly statusRepository: Repository<Status>,
) {
+14
View File
@@ -1,8 +1,22 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const config = new DocumentBuilder()
.setTitle('Documentacion de la api de votaciones v2')
.setDescription(
'El proyecto ha sido refactorizado a una version mejorada con nestjs',
)
.setVersion('1.0')
.addTag('description')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('documentation', app, document);
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();