From f8af0947b96ffdfb8cab69ecf6ae317d6e8def3a Mon Sep 17 00:00:00 2001 From: evenegas Date: Thu, 27 Mar 2025 14:08:38 -0600 Subject: [PATCH 1/6] =?UTF-8?q?Actualizaci=C3=B3n=20de=20swagger?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env_example | 16 ++++++++++++++++ src/mail/mail.decorators.ts | 33 ++++++++++----------------------- 2 files changed, 26 insertions(+), 23 deletions(-) create mode 100644 .env_example diff --git a/.env_example b/.env_example new file mode 100644 index 0000000..75946e5 --- /dev/null +++ b/.env_example @@ -0,0 +1,16 @@ +#Contraseñas Gmail +USER_GMAIL= +PASS_GMAIL= + + +# MariaDB database settings +db_type= +db_host= +db_username= +db_database= +db_password= +db_port=3306 + +#Puero aplicación +PORT=3000 + diff --git a/src/mail/mail.decorators.ts b/src/mail/mail.decorators.ts index 312635f..2389d17 100644 --- a/src/mail/mail.decorators.ts +++ b/src/mail/mail.decorators.ts @@ -1,5 +1,5 @@ import { applyDecorators } from '@nestjs/common'; -import { ApiBody, ApiConsumes, ApiOperation, ApiResponse } from '@nestjs/swagger'; +import { ApiBody, ApiConsumes, ApiHeader, ApiOperation, ApiResponse } from '@nestjs/swagger'; export const ApiSendMail = () => { return applyDecorators( @@ -9,7 +9,14 @@ export const ApiSendMail = () => { - **to**: Dirección de correo del destinatario. - **subject**: Asunto del correo. - **text**: Cuerpo del mensaje. -- **fecha_recibido**: Fecha en que se registró la solicitud.`, +- **fecha_recibido**: Fecha en que se registró la solicitud. +- **sistema**: contraseña del sistema.`, + }), + ApiHeader({ + name: 'password', + description: 'Contraseña del sistema para autenticación', + required: true, + example: 'mi-password-segura' }), ApiBody({ description: 'Datos del correo a enviar', @@ -22,27 +29,7 @@ export const ApiSendMail = () => { 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', - }, - }, - }), + }) ); }; From 30513115c3d76e1a76bd8268145fac8dfef78629 Mon Sep 17 00:00:00 2001 From: evenegas Date: Thu, 27 Mar 2025 14:12:28 -0600 Subject: [PATCH 2/6] .env_example --- .env_example | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.env_example b/.env_example index 75946e5..4465316 100644 --- a/.env_example +++ b/.env_example @@ -4,13 +4,12 @@ PASS_GMAIL= # MariaDB database settings -db_type= -db_host= -db_username= -db_database= -db_password= +db_type=mysql +db_host=172.17.0.2 +db_username=root +db_database=ApiCorreos +db_password=mypass db_port=3306 #Puero aplicación PORT=3000 - From cac702af43a127d280aa6485a2402bedb35492a0 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 27 Mar 2025 17:56:44 -0600 Subject: [PATCH 3/6] docker, docker-compose, env example --- .env_example | 15 +++++++-------- Dockerfile | 23 +++++++++++++++++++++++ docker-compose.yml | 28 ++++++++++++++++++++++++++++ src/main.ts | 2 ++ 4 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.env_example b/.env_example index 4465316..a56b453 100644 --- a/.env_example +++ b/.env_example @@ -1,15 +1,14 @@ -#Contraseñas Gmail +# Gmail USER_GMAIL= PASS_GMAIL= - # MariaDB database settings db_type=mysql -db_host=172.17.0.2 -db_username=root -db_database=ApiCorreos -db_password=mypass +db_host=mariadb # <-- uso del nombre del servicio, NO IP db_port=3306 +db_username=root # <-- te conectarás con root +db_password=mypass # <-- la misma que MARIADB_ROOT_PASSWORD +db_database=ApiCorreos -#Puero aplicación -PORT=3000 +# Puerto de la aplicación +PORT=4100 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9259854 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +# Etapa de construcción +FROM node:20-alpine AS builder + +WORKDIR /app + +COPY package*.json ./ +RUN npm install + +COPY . . +RUN npm run build + +# Etapa de producción +FROM node:20-alpine AS production + +WORKDIR /app + +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/package*.json ./ + +EXPOSE 4100 + +CMD ["node", "dist/main"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..8b580e5 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,28 @@ +version: '3.8' + +services: + mariadb: + image: mariadb:latest + container_name: mariadb-service + ports: + - "4101:3306" + environment: + MARIADB_ROOT_PASSWORD: mypass + MARIADB_DATABASE: ApiCorreos + volumes: + - mariadb_data:/var/lib/mysql + + api: + build: + context: . + dockerfile: Dockerfile + container_name: nestjs-api + env_file: + - .env + ports: + - "4100:4100" + depends_on: + - mariadb + +volumes: + mariadb_data: diff --git a/src/main.ts b/src/main.ts index 77262f1..11ff22b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -18,5 +18,7 @@ async function bootstrap() { SwaggerModule.setup('documentation', app, document); await app.listen(process.env.PORT ?? 3000); + + console.log(`Aplicación corriendo en: http://localhost:${process.env.PORT ?? 3000}`); } bootstrap(); From 71e39eb65e8ce66f6fc91743499e4da11edaf2fb Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 28 Mar 2025 08:21:43 -0600 Subject: [PATCH 4/6] docker ignore, ignore tar file, commet mail controller, docker compose pentester --- .dockerignore | 6 ++++++ .gitignore | 4 ++++ docker-compose.pentest.yml | 32 ++++++++++++++++++++++++++++++++ src/mail/mail.controller.ts | 11 ++++++++--- 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 .dockerignore create mode 100644 docker-compose.pentest.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a328873 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +node_modules +dist +.git +.env +*.log + diff --git a/.gitignore b/.gitignore index 4b56acf..15e67f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ + +*.tar + + # compiled output /dist /node_modules diff --git a/docker-compose.pentest.yml b/docker-compose.pentest.yml new file mode 100644 index 0000000..880f7b5 --- /dev/null +++ b/docker-compose.pentest.yml @@ -0,0 +1,32 @@ +version: '3.8' + +services: + mariadb: + image: mariadb:latest + container_name: mariadb-service + ports: + - "4101:3306" + environment: + MARIADB_ROOT_PASSWORD: mypass + MARIADB_DATABASE: ApiCorreos + volumes: + - mariadb_data:/var/lib/mysql + + api: + image: correos_api:v0 # <--- la imagen final (comprobada en el paso anterior) + container_name: nestjs-api + environment: + # Ajustar estas vars a tu conveniencia + db_host: mariadb + db_port: 3306 + db_username: root + db_password: mypass + db_database: ApiCorreos + PORT: 4100 + ports: + - "4100:4100" + depends_on: + - mariadb + +volumes: + mariadb_data: diff --git a/src/mail/mail.controller.ts b/src/mail/mail.controller.ts index 866a308..54aeee6 100644 --- a/src/mail/mail.controller.ts +++ b/src/mail/mail.controller.ts @@ -33,7 +33,12 @@ export class MailController { @Headers() headers:{password:string}, @Body() body: { to: string; subject: string; text: string; fecha_recibido: Date }) { - +/* + +// esta parte hay que rehacerla, se tiene que obtener la contraseña del sistema en base a la clave del sistema. +// debe de existir un modulo para crear contraseñas para las apis y administrar esas contraseñas + + if (!headers.password) { throw new UnauthorizedException('Header "Password" es requerido'); } @@ -42,12 +47,12 @@ export class MailController { if (!sistem) { throw new UnauthorizedException('Password incorrecto'); - } + } */ const { to, subject, text, fecha_recibido } = body; - const result = await this.mailService.sendMail(to, subject, text, fecha_recibido,sistem); + const result = await this.mailService.sendMail(to, subject, text, fecha_recibido,1); // sistem return result; From 557beeab60fb22879a50565292db64c022255518 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 2 Apr 2025 09:50:01 -0600 Subject: [PATCH 5/6] comentar los inserts a la base de datos --- src/mail/mail.service.ts | 8 +++++--- src/main.ts | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/mail/mail.service.ts b/src/mail/mail.service.ts index 9e1b6f9..9f7f6f0 100644 --- a/src/mail/mail.service.ts +++ b/src/mail/mail.service.ts @@ -53,7 +53,7 @@ export class MailService { let resMail = await this.transporter.sendMail(mailOptions); const statusTexto = resMail.accepted.length > 0 ? "Enviado" : "Fallido"; - + /* let status = await this.statusRepository.findOne({ where: { status: statusTexto } }); @@ -70,11 +70,13 @@ export class MailService { destinatario: to, remitente: process.env.USER_GMAIL, - }); + }); */ + + if(!resMail){ throw new Error("fallo") } - this.correoRepository.save(info); + //this.correoRepository.save(info); diff --git a/src/main.ts b/src/main.ts index 11ff22b..4b9240c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,6 +6,9 @@ import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; async function bootstrap() { const app = await NestFactory.create(AppModule); + + app.enableCors(); + const config = new DocumentBuilder() .setTitle('Documentacion de la api de votaciones_mails v2') .setDescription( From afa6743b47f3e296241618f771d22c3b2c1bde27 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 3 Apr 2025 11:17:00 -0600 Subject: [PATCH 6/6] enviar qr y html --- src/mail/mail.controller.ts | 15 ++++++++++----- src/mail/mail.service.ts | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/mail/mail.controller.ts b/src/mail/mail.controller.ts index 54aeee6..f7e7c11 100644 --- a/src/mail/mail.controller.ts +++ b/src/mail/mail.controller.ts @@ -31,7 +31,7 @@ export class MailController { @ApiSendMail() async sendMail( @Headers() headers:{password:string}, - @Body() body: { to: string; subject: string; text: string; fecha_recibido: Date }) { + @Body() body: { to: string; subject: string; text: string; fecha_recibido: Date, html:string, adjuntos:any }) { /* @@ -49,10 +49,15 @@ export class MailController { throw new UnauthorizedException('Password incorrecto'); } */ - - const { to, subject, text, fecha_recibido } = body; + + + console.log("estos son los archivos adjuntos en el controller",body); - const result = await this.mailService.sendMail(to, subject, text, fecha_recibido,1); // sistem + + + const { to, subject, text, html, fecha_recibido, adjuntos } = body; + + const result = await this.mailService.sendMail(to, subject, text,html, fecha_recibido,1,adjuntos); // sistem return result; @@ -84,7 +89,7 @@ export class MailController { for (const email of await emails) { try { - await this.mailService.sendMail(email, "subject", "text", fechaActual,sistem); + await this.mailService.sendMail(email, "subject", "text","html", fechaActual,sistem); console.log(`📧 Enviado a: ${email}`); } catch (error) { console.error(`❌ Error enviando a ${email}:`, error.message); diff --git a/src/mail/mail.service.ts b/src/mail/mail.service.ts index 9f7f6f0..1775f43 100644 --- a/src/mail/mail.service.ts +++ b/src/mail/mail.service.ts @@ -42,14 +42,45 @@ export class MailService { // Función para generar el reporte de correos enviados y fallidos - async sendMail(to: string, subject: string, text: string, fecha_recibido: Date, sistema) { + async sendMail(to: string, subject: string, text: string, html: string, fecha_recibido: Date, sistema, adjuntos?: any[] ) { + + console.log("estos son los archivos adjuntos en el service",adjuntos); + + + const mailOptions = { from: process.env.USER_GMAIL, to, subject, text, + html, + + // OJO: nodemailer usa 'attachments', no 'adjuntos' + attachments: (adjuntos || []).map((adj) => { + // Asegúrate de no incluir 'data:image/png;base64,' en 'content' + let base64Clean = adj.content; + // Si viene con prefijo "data:image...", lo quitamos + if (base64Clean.startsWith('data:image/')) { + base64Clean = base64Clean.split('base64,')[1]; + } + + return { + filename: adj.filename || 'qr.png', + content: Buffer.from(base64Clean, adj.encoding || 'base64'), + cid: adj.cid || 'qrCode', // el mismo que uses en + contentType: 'image/png' // recomendable para que sepa que es PNG + }; + }) + + }; + + console.log(mailOptions); + + + + let resMail = await this.transporter.sendMail(mailOptions); const statusTexto = resMail.accepted.length > 0 ? "Enviado" : "Fallido";