Se agregó la documentación en swagger
This commit is contained in:
@@ -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 };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
};
|
||||
@@ -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,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);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
};
|
||||
@@ -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
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user