feat: update ESLint and TypeScript configurations across frontend and backend; enhance component structure and improve data handling in various modules

This commit is contained in:
2025-12-02 16:36:02 -03:00
parent f48d28067c
commit d79e6959c3
215 changed files with 29474 additions and 28173 deletions

View File

@@ -1,233 +1,216 @@
"use node";
'use node';
import { action } from "../_generated/server";
import { v } from "convex/values";
import { internal } from "../_generated/api";
import { decryptSMTPPasswordNode } from "./utils/nodeCrypto";
import nodemailer from "nodemailer";
import { action } from '../_generated/server';
import { v } from 'convex/values';
import { internal } from '../_generated/api';
import { decryptSMTPPasswordNode } from './utils/nodeCrypto';
import nodemailer from 'nodemailer';
export const enviar = action({
args: {
emailId: v.id("notificacoesEmail"),
},
returns: v.object({ sucesso: v.boolean(), erro: v.optional(v.string()) }),
handler: async (ctx, args) => {
"use node";
args: {
emailId: v.id('notificacoesEmail')
},
returns: v.object({ sucesso: v.boolean(), erro: v.optional(v.string()) }),
handler: async (ctx, args) => {
'use node';
let email;
try {
// Buscar email da fila
email = await ctx.runQuery(internal.email.getEmailById, {
emailId: args.emailId,
});
let email;
try {
// Buscar email da fila
email = await ctx.runQuery(internal.email.getEmailById, {
emailId: args.emailId
});
if (!email) {
return { sucesso: false, erro: "Email não encontrado" };
}
if (!email) {
return { sucesso: false, erro: 'Email não encontrado' };
}
// Buscar configuração SMTP ativa
const configRaw = await ctx.runQuery(
internal.email.getActiveEmailConfig,
{}
);
// Buscar configuração SMTP ativa
const configRaw = await ctx.runQuery(internal.email.getActiveEmailConfig, {});
if (!configRaw) {
console.error(
"❌ Configuração SMTP não encontrada ou inativa para email:",
email.destinatario
);
return {
sucesso: false,
erro: "Configuração de email não encontrada ou inativa. Verifique as configurações SMTP no painel de TI.",
};
}
if (!configRaw) {
console.error(
'❌ Configuração SMTP não encontrada ou inativa para email:',
email.destinatario
);
return {
sucesso: false,
erro: 'Configuração de email não encontrada ou inativa. Verifique as configurações SMTP no painel de TI.'
};
}
console.log("📧 Tentando enviar email:", {
para: email.destinatario,
assunto: email.assunto,
servidor: configRaw.servidor,
porta: configRaw.porta,
});
console.log('📧 Tentando enviar email:', {
para: email.destinatario,
assunto: email.assunto,
servidor: configRaw.servidor,
porta: configRaw.porta
});
// Descriptografar senha usando função compatível com Node.js
let senhaDescriptografada: string;
try {
senhaDescriptografada = await decryptSMTPPasswordNode(
configRaw.senhaHash
);
} catch (decryptError) {
const decryptErrorMessage =
decryptError instanceof Error
? decryptError.message
: String(decryptError);
console.error(
"Erro ao descriptografar senha SMTP:",
decryptErrorMessage
);
return {
sucesso: false,
erro: `Erro ao descriptografar senha SMTP: ${decryptErrorMessage}`,
};
}
// Descriptografar senha usando função compatível com Node.js
let senhaDescriptografada: string;
try {
senhaDescriptografada = await decryptSMTPPasswordNode(configRaw.senhaHash);
} catch (decryptError) {
const decryptErrorMessage =
decryptError instanceof Error ? decryptError.message : String(decryptError);
console.error('Erro ao descriptografar senha SMTP:', decryptErrorMessage);
return {
sucesso: false,
erro: `Erro ao descriptografar senha SMTP: ${decryptErrorMessage}`
};
}
const config = {
...configRaw,
senha: senhaDescriptografada,
};
const config = {
...configRaw,
senha: senhaDescriptografada
};
// Config já foi validado acima
// Config já foi validado acima
// Avisar mas não bloquear se não foi testado
if (!config.testadoEm) {
console.warn(
"⚠️ Configuração SMTP não foi testada. Tentando enviar mesmo assim..."
);
}
// Avisar mas não bloquear se não foi testado
if (!config.testadoEm) {
console.warn('⚠️ Configuração SMTP não foi testada. Tentando enviar mesmo assim...');
}
// Marcar como enviando
await ctx.runMutation(internal.email.markEmailEnviando, {
emailId: args.emailId,
});
// Marcar como enviando
await ctx.runMutation(internal.email.markEmailEnviando, {
emailId: args.emailId
});
// Criar transporter do nodemailer com configuração melhorada
const transporterOptions: {
host: string;
port: number;
secure: boolean;
requireTLS?: boolean;
auth: {
user: string;
pass: string;
};
tls?: {
rejectUnauthorized: boolean;
ciphers?: string;
};
connectionTimeout: number;
greetingTimeout: number;
socketTimeout: number;
pool?: boolean;
maxConnections?: number;
maxMessages?: number;
} = {
host: config.servidor,
port: config.porta,
secure: config.usarSSL,
auth: {
user: config.usuario,
pass: config.senha, // Senha já descriptografada
},
connectionTimeout: 15000, // 15 segundos
greetingTimeout: 15000,
socketTimeout: 15000,
pool: true, // Usar pool de conexões
maxConnections: 5,
maxMessages: 100,
};
// Criar transporter do nodemailer com configuração melhorada
const transporterOptions: {
host: string;
port: number;
secure: boolean;
requireTLS?: boolean;
auth: {
user: string;
pass: string;
};
tls?: {
rejectUnauthorized: boolean;
ciphers?: string;
};
connectionTimeout: number;
greetingTimeout: number;
socketTimeout: number;
pool?: boolean;
maxConnections?: number;
maxMessages?: number;
} = {
host: config.servidor,
port: config.porta,
secure: config.usarSSL,
auth: {
user: config.usuario,
pass: config.senha // Senha já descriptografada
},
connectionTimeout: 15000, // 15 segundos
greetingTimeout: 15000,
socketTimeout: 15000,
pool: true, // Usar pool de conexões
maxConnections: 5,
maxMessages: 100
};
// Adicionar TLS apenas se necessário
if (config.usarTLS) {
transporterOptions.requireTLS = true;
transporterOptions.tls = {
rejectUnauthorized: false, // Permitir certificados autoassinados
};
} else if (config.usarSSL) {
transporterOptions.tls = {
rejectUnauthorized: false,
};
}
// Adicionar TLS apenas se necessário
if (config.usarTLS) {
transporterOptions.requireTLS = true;
transporterOptions.tls = {
rejectUnauthorized: false // Permitir certificados autoassinados
};
} else if (config.usarSSL) {
transporterOptions.tls = {
rejectUnauthorized: false
};
}
const transporter = nodemailer.createTransport(transporterOptions);
const transporter = nodemailer.createTransport(transporterOptions);
// Verificar conexão antes de enviar
try {
await transporter.verify();
console.log("✅ Conexão SMTP verificada com sucesso");
} catch (verifyError) {
const verifyErrorMessage =
verifyError instanceof Error
? verifyError.message
: String(verifyError);
console.warn(
"⚠️ Falha na verificação SMTP, mas tentando enviar mesmo assim:",
verifyErrorMessage
);
// Não bloquear envio por falha na verificação, apenas avisar
}
// Verificar conexão antes de enviar
try {
await transporter.verify();
console.log('✅ Conexão SMTP verificada com sucesso');
} catch (verifyError) {
const verifyErrorMessage =
verifyError instanceof Error ? verifyError.message : String(verifyError);
console.warn(
'⚠️ Falha na verificação SMTP, mas tentando enviar mesmo assim:',
verifyErrorMessage
);
// Não bloquear envio por falha na verificação, apenas avisar
}
// Validar email destinatário antes de enviar
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email.destinatario)) {
throw new Error(`Email destinatário inválido: ${email.destinatario}`);
}
// Validar email destinatário antes de enviar
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email.destinatario)) {
throw new Error(`Email destinatário inválido: ${email.destinatario}`);
}
// Criar versão texto do HTML (remover tags e decodificar entidades básicas)
const textoPlano = email.corpo
.replace(/<[^>]*>/g, "") // Remover tags HTML
.replace(/&nbsp;/g, " ")
.replace(/&amp;/g, "&")
.replace(/&lt;/g, "<")
.replace(/&gt;/g, ">")
.replace(/&quot;/g, '"')
.replace(/&#39;/g, "'")
.trim();
// Criar versão texto do HTML (remover tags e decodificar entidades básicas)
const textoPlano = email.corpo
.replace(/<[^>]*>/g, '') // Remover tags HTML
.replace(/&nbsp;/g, ' ')
.replace(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&quot;/g, '"')
.replace(/&#39;/g, "'")
.trim();
// Enviar email
const info = await transporter.sendMail({
from: `"${config.nomeRemetente}" <${config.emailRemetente}>`,
to: email.destinatario,
subject: email.assunto,
html: email.corpo,
text: textoPlano || email.assunto, // Versão texto para clientes que não suportam HTML
headers: {
"X-Mailer": "SGSE-Sistema-de-Gerenciamento-de-Secretaria",
"X-Priority": "3",
},
});
// Enviar email
const info = await transporter.sendMail({
from: `"${config.nomeRemetente}" <${config.emailRemetente}>`,
to: email.destinatario,
subject: email.assunto,
html: email.corpo,
text: textoPlano || email.assunto, // Versão texto para clientes que não suportam HTML
headers: {
'X-Mailer': 'SGSE-Sistema-de-Gerenciamento-de-Secretaria',
'X-Priority': '3'
}
});
interface MessageInfo {
messageId?: string;
response?: string;
}
interface MessageInfo {
messageId?: string;
response?: string;
}
const messageInfo = info as MessageInfo;
const messageInfo = info as MessageInfo;
console.log("✅ Email enviado com sucesso!", {
para: email.destinatario,
assunto: email.assunto,
messageId: messageInfo.messageId,
response: messageInfo.response,
});
console.log('✅ Email enviado com sucesso!', {
para: email.destinatario,
assunto: email.assunto,
messageId: messageInfo.messageId,
response: messageInfo.response
});
// Marcar como enviado
await ctx.runMutation(internal.email.markEmailEnviado, {
emailId: args.emailId,
});
// Marcar como enviado
await ctx.runMutation(internal.email.markEmailEnviado, {
emailId: args.emailId
});
return { sucesso: true };
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : String(error);
const errorStack = error instanceof Error ? error.stack : undefined;
return { sucesso: true };
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
const errorStack = error instanceof Error ? error.stack : undefined;
console.error("❌ Erro ao enviar email:", {
emailId: args.emailId,
destinatario: email?.destinatario,
erro: errorMessage,
stack: errorStack,
});
console.error('❌ Erro ao enviar email:', {
emailId: args.emailId,
destinatario: email?.destinatario,
erro: errorMessage,
stack: errorStack
});
// Marcar como falha com detalhes completos
const erroCompleto = errorStack
? `${errorMessage}\n\nStack: ${errorStack}`
: errorMessage;
// Marcar como falha com detalhes completos
const erroCompleto = errorStack ? `${errorMessage}\n\nStack: ${errorStack}` : errorMessage;
await ctx.runMutation(internal.email.markEmailFalha, {
emailId: args.emailId,
erro: erroCompleto.substring(0, 2000), // Limitar tamanho do erro
});
await ctx.runMutation(internal.email.markEmailFalha, {
emailId: args.emailId,
erro: erroCompleto.substring(0, 2000) // Limitar tamanho do erro
});
return { sucesso: false, erro: errorMessage };
}
},
return { sucesso: false, erro: errorMessage };
}
}
});