239 lines
6.0 KiB
TypeScript
239 lines
6.0 KiB
TypeScript
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||
import * as nodemailer from 'nodemailer';
|
||
import { InjectRepository } from '@nestjs/typeorm';
|
||
import { Repository } from 'typeorm';
|
||
import { Correo, Sistema, Status } from '../typeorm/entidades';
|
||
import { SistemaService } from 'src/sistema/sistema.service';
|
||
import { SendCorreoDto } from 'src/mail/dto/send-email.dto';
|
||
import { AuthService } from 'src/auth/auth.service';
|
||
import { decrypt } from '../crypto/crypto.util';
|
||
|
||
|
||
|
||
@Injectable()
|
||
export class MailService {
|
||
|
||
|
||
constructor(
|
||
private readonly sistemaService: SistemaService,
|
||
private readonly authService: AuthService,
|
||
@InjectRepository(Correo) private readonly correoRepository: Repository<Correo>,
|
||
@InjectRepository(Status) private readonly statusRepository: Repository<Status>,
|
||
@InjectRepository(Sistema) private readonly sistemaRepositosistemaRepositoryry: Repository<Sistema>
|
||
|
||
|
||
) {
|
||
|
||
|
||
|
||
/* this.transporter = nodemailer.createTransport({
|
||
host: 'smtp-relay.gmail.com',
|
||
port: 587,
|
||
secure: false,
|
||
requireTLS: true,
|
||
auth: {
|
||
user: process.env.USER_GMAIL,
|
||
pass: process.env.PASS_GMAIL,
|
||
},
|
||
}); */
|
||
|
||
|
||
/*
|
||
this.transporter = nodemailer.createTransport({
|
||
host: 'smtp.gmail.com', // o smtp‑relay.gmail.com (ver punto 2)
|
||
port: 587,
|
||
secure: false,
|
||
requireTLS: true, // TLS STARTTLS
|
||
auth: { user: process.env.USER_GMAIL, pass: process.env.PASS_GMAIL },
|
||
pool: true, // <‑‑ activa reuse
|
||
maxConnections: 1, // una sola conexión viva
|
||
maxMessages: 100, // reabrir después de 100 envíos
|
||
rateDelta: 2000, // ventana 1 s
|
||
rateLimit: 1 // máx. 5 mensajes/seg
|
||
});
|
||
|
||
|
||
*/
|
||
|
||
/*
|
||
this.transporter = nodemailer.createTransport({
|
||
host: 'localhost',
|
||
port: 1025,
|
||
ignoreTLS: true,
|
||
});
|
||
*/
|
||
}
|
||
|
||
|
||
|
||
async findAllBySistema(TOKEN:string,nombreSistema:string){
|
||
|
||
|
||
if (!TOKEN) {
|
||
throw new UnauthorizedException('Header "Password" es requerido');
|
||
}
|
||
|
||
|
||
|
||
const sistem=await this.sistemaService.acceso(TOKEN)
|
||
if(!sistem){
|
||
throw new UnauthorizedException('Password incorrecto');
|
||
}
|
||
|
||
|
||
const result= await this.correoRepository.find({where:{
|
||
id_sistema:{nombre_sistema:nombreSistema}
|
||
},
|
||
relations: {
|
||
id_sistema: true,
|
||
id_status: true,
|
||
},}
|
||
)
|
||
return result
|
||
}
|
||
|
||
async sendMail(sendEmail:SendCorreoDto,token:string) {
|
||
|
||
let payload
|
||
|
||
payload = await this.authService.verificarToken(token);
|
||
|
||
|
||
if (!payload || !payload.nombre) {
|
||
throw new UnauthorizedException('Token inválido o incompleto');
|
||
}
|
||
|
||
const sistem= await this.sistemaService.findByNombre(payload.nombre)
|
||
|
||
|
||
if(!sistem){
|
||
throw new UnauthorizedException('sistema No encontrado');
|
||
}
|
||
|
||
|
||
|
||
|
||
const decryptedPassword = decrypt(
|
||
sistem.email_password_encrypted,
|
||
sistem.email_password_iv
|
||
);
|
||
|
||
const decryptedToken = decrypt(
|
||
sistem.refreshToken_encrypted,
|
||
sistem.refreshToken_iv
|
||
);
|
||
|
||
|
||
|
||
|
||
|
||
const transporter = nodemailer.createTransport({
|
||
/* host: 'smtp.gmail.com', // o smtp‑relay.gmail.com (ver punto 2)
|
||
port: 587,
|
||
secure: false,
|
||
requireTLS: true, // TLS STARTTLS
|
||
auth: { user:sistem.email, pass:decryptedPassword},
|
||
pool: true, // <‑‑ activa reuse
|
||
maxConnections: 1, // una sola conexión viva
|
||
maxMessages: 100, // reabrir después de 100 envíos
|
||
rateDelta: 2000, // ventana 1 s
|
||
rateLimit: 1 // máx. 5 mensajes/seg
|
||
*/
|
||
|
||
service: 'gmail',
|
||
auth: {
|
||
type: 'OAuth2',
|
||
user: sistem.email,
|
||
clientId: sistem.clientId,
|
||
clientSecret: decryptedPassword,
|
||
refreshToken: decryptedToken,
|
||
//accessToken: sistem.accessToken, // opcional
|
||
},
|
||
pool: true,
|
||
maxConnections: 1,
|
||
maxMessages: 100,
|
||
rateDelta: 2000,
|
||
rateLimit: 1
|
||
|
||
|
||
});
|
||
|
||
|
||
|
||
console.log("estos son los archivos adjuntos en el service",sendEmail.adjuntos);
|
||
|
||
|
||
|
||
const mailOptions = {
|
||
from: sistem.email,
|
||
to:sendEmail.to,
|
||
subject:sendEmail.subject,
|
||
text: sendEmail.text,
|
||
html:sendEmail.html,
|
||
|
||
// OJO: nodemailer usa 'attachments', no 'adjuntos'
|
||
attachments: (sendEmail.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 <img src="cid:..."/>
|
||
contentType: 'image/png' // recomendable para que sepa que es PNG
|
||
};
|
||
})
|
||
|
||
|
||
};
|
||
|
||
|
||
console.log(mailOptions);
|
||
|
||
|
||
|
||
|
||
let resMail = await transporter.sendMail(mailOptions);
|
||
if(!resMail) throw new Error("")
|
||
|
||
|
||
const statusTexto = resMail.accepted.length > 0 ? "Enviado" : "Fallido";
|
||
|
||
|
||
let status = await this.statusRepository.findOne({ where: { status: statusTexto } });
|
||
|
||
|
||
if (!status) {
|
||
status = this.statusRepository.create({ status: statusTexto });
|
||
await this.statusRepository.save(status);
|
||
}
|
||
|
||
const info= this.correoRepository.create({
|
||
id_status: status,
|
||
id_sistema: sistem,
|
||
fecha_recibido: sendEmail.fecha_recibido,
|
||
fecha_enviado: new Date(),
|
||
destinatario: sendEmail.to,
|
||
remitente: sistem.email,
|
||
|
||
});
|
||
|
||
|
||
if(!resMail){
|
||
throw new Error("fallo")
|
||
}
|
||
this.correoRepository.save(info);
|
||
|
||
|
||
|
||
return (statusTexto);
|
||
}
|
||
|
||
|
||
|
||
}
|