diff --git a/package-lock.json b/package-lock.json index 6aa72ab..07d8eae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,10 +15,12 @@ "@nestjs/swagger": "^11.0.5", "csv-parser": "^3.2.0", "dotenv": "^16.4.7", + "fs": "^0.0.1-security", "multer": "^1.4.5-lts.1", "nodemailer": "^6.10.0", "reflect-metadata": "^0.2.2", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "xlsx": "^0.18.5" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", @@ -3653,6 +3655,14 @@ "node": ">=0.4.0" } }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -4347,6 +4357,18 @@ } ] }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -4542,6 +4564,14 @@ "node": ">= 0.12.0" } }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/collect-v8-coverage": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", @@ -4731,6 +4761,17 @@ } } }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -5997,6 +6038,14 @@ "node": ">= 0.6" } }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", @@ -6005,6 +6054,11 @@ "node": ">= 0.8" } }, + "node_modules/fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + }, "node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -9157,6 +9211,17 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -10423,6 +10488,22 @@ "node": ">= 8" } }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -10530,6 +10611,26 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index 06a9e8a..08cbb51 100644 --- a/package.json +++ b/package.json @@ -26,10 +26,12 @@ "@nestjs/swagger": "^11.0.5", "csv-parser": "^3.2.0", "dotenv": "^16.4.7", + "fs": "^0.0.1-security", "multer": "^1.4.5-lts.1", "nodemailer": "^6.10.0", "reflect-metadata": "^0.2.2", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "xlsx": "^0.18.5" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", diff --git a/src/app.module.ts b/src/app.module.ts index 455467a..89cfbb1 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -2,8 +2,13 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { MailModule } from './mail/mail.module'; +import {ExcelModule} from './excel/excel.module' @Module({ - imports: [MailModule], + imports: [ + MailModule, + ExcelModule, + + ], controllers: [AppController], providers: [AppService], }) diff --git a/src/excel/excel.controller.ts b/src/excel/excel.controller.ts new file mode 100644 index 0000000..182d6b1 --- /dev/null +++ b/src/excel/excel.controller.ts @@ -0,0 +1,14 @@ +import { Controller, Get } from '@nestjs/common'; +import { ExcelService } from './excel.service'; + +@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); + return { emails }; + } +} diff --git a/src/excel/excel.module.ts b/src/excel/excel.module.ts new file mode 100644 index 0000000..8522693 --- /dev/null +++ b/src/excel/excel.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { ExcelService } from './excel.service'; +import { ExcelController } from './excel.controller'; + + +@Module({ + providers: [ExcelService], // Servicio que maneja la lectura de Excel + controllers: [ExcelController], // Controlador con los endpoints + exports: [ExcelService], // Exportarlo si se usa en otros módulos +}) +export class ExcelModule {} diff --git a/src/excel/excel.service.ts b/src/excel/excel.service.ts new file mode 100644 index 0000000..949a88d --- /dev/null +++ b/src/excel/excel.service.ts @@ -0,0 +1,36 @@ +import * as fs from 'fs'; +import * as XLSX from 'xlsx'; +import { Injectable } from '@nestjs/common'; + + + +@Injectable() +export class ExcelService { + readEmailsFromExcel(filePath: string): string[] { + console.log(` Verificando archivo en: ${filePath}`); + + if (!fs.existsSync(filePath)) { + console.error(' Archivo Excel NO encontrado'); + throw new Error('Archivo Excel no encontrado'); + } else { + console.log('Archivo Excel encontrado'); + } + + const workbook = XLSX.readFile(filePath); + const sheetName = workbook.SheetNames[0]; + const sheet = workbook.Sheets[sheetName]; + + const jsonData = XLSX.utils.sheet_to_json(sheet); + + console.log(`Datos extraídos:`, jsonData); + + // Extraer correos de la columna "Correo" + const emails = jsonData + .map((row: any) => row['Correo']) + .filter(email => email); + + console.log(` Correos extraídos:`, emails); + + return emails; + } +} diff --git a/src/excel_Usuarios/usuarios_fake.xlsx b/src/excel_Usuarios/usuarios_fake.xlsx new file mode 100644 index 0000000..420b7d1 Binary files /dev/null and b/src/excel_Usuarios/usuarios_fake.xlsx differ diff --git a/src/mail/mail.controller.ts b/src/mail/mail.controller.ts index c96f6c8..c416da4 100644 --- a/src/mail/mail.controller.ts +++ b/src/mail/mail.controller.ts @@ -6,6 +6,7 @@ import { UseInterceptors, } 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'; @@ -15,7 +16,10 @@ import { ApiTags } from '@nestjs/swagger'; @ApiTags('Mail') // Grupo de endpoints @Controller('mail') export class MailController { - constructor(private readonly mailService: MailService) {} + constructor( + private readonly mailService: MailService, + private readonly excelService: ExcelService + ) {} // Endpoint para enviar correos a través de una solicitud POST @Post('send') @@ -26,6 +30,21 @@ export class MailController { return result; } + @Post('send-excel') + async sendMailExcel() { + + const emails=this.excelService.readEmailsFromExcel('./src/excel_Usuarios/usuarios_fake.xlsx'); + for (const email of emails) { + try { + await this.mailService.sendMail(email, "subject", "text"); + console.log(`📧 Enviado a: ${email}`); + } catch (error) { + console.error(`❌ Error enviando a ${email}:`, error.message); + } + } + } + + @Post('send-bulk') //@UseInterceptors(FileInterceptor('file')) @UseInterceptors( diff --git a/src/mail/mail.module.ts b/src/mail/mail.module.ts index c539103..bf01249 100644 --- a/src/mail/mail.module.ts +++ b/src/mail/mail.module.ts @@ -1,9 +1,11 @@ import { Module } from '@nestjs/common'; import { MailService } from './mail.service'; import { MailController } from './mail.controller'; +import { ExcelModule } from 'src/excel/excel.module'; @Module({ providers: [MailService], + imports: [ExcelModule], controllers: [MailController], exports: [MailService], // Exportar si otros módulos necesitan usar el MailService }) diff --git a/src/mail/mail.service.ts b/src/mail/mail.service.ts index c308ed3..7a65edd 100644 --- a/src/mail/mail.service.ts +++ b/src/mail/mail.service.ts @@ -1,6 +1,8 @@ import { Injectable } from '@nestjs/common'; import * as nodemailer from 'nodemailer'; import * as dotenv from 'dotenv'; + + dotenv.config(); @Injectable() diff --git a/votaciones b/votaciones new file mode 100644 index 0000000..84cec8f --- /dev/null +++ b/votaciones @@ -0,0 +1,29 @@ + +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# +# En la rama develop +# +# Confirmación inicial +# +# Cambios a ser confirmados: +# nuevos archivos: .gitignore +# nuevos archivos: .prettierrc +# nuevos archivos: README.md +# nuevos archivos: eslint.config.mjs +# nuevos archivos: nest-cli.json +# nuevos archivos: package-lock.json +# nuevos archivos: package.json +# nuevos archivos: src/app.controller.spec.ts +# nuevos archivos: src/app.controller.ts +# nuevos archivos: src/app.module.ts +# nuevos archivos: src/app.service.ts +# nuevos archivos: src/mail/mail.controller.ts +# nuevos archivos: src/mail/mail.module.ts +# nuevos archivos: src/mail/mail.service.ts +# nuevos archivos: src/main.ts +# nuevos archivos: test/app.e2e-spec.ts +# nuevos archivos: test/jest-e2e.json +# nuevos archivos: tsconfig.build.json +# nuevos archivos: tsconfig.json +#