417 lines
13 KiB
JavaScript
417 lines
13 KiB
JavaScript
const emailService = require('../services/email');
|
|
const nocoDB = require('../services/nocodb');
|
|
const crypto = require('crypto');
|
|
|
|
class EmailsController {
|
|
async sendEmail(req, res, next) {
|
|
try {
|
|
const { recipientEmail, senderName, senderEmail, subject, message, postalCode, recipientName } = req.body;
|
|
|
|
// Send the email using template system
|
|
const emailResult = await emailService.sendRepresentativeEmail(
|
|
recipientEmail,
|
|
senderName,
|
|
senderEmail,
|
|
subject,
|
|
message,
|
|
postalCode,
|
|
recipientName
|
|
);
|
|
|
|
// Log the email send event
|
|
await nocoDB.logEmailSend({
|
|
recipientEmail,
|
|
senderName,
|
|
senderEmail,
|
|
subject,
|
|
message,
|
|
postalCode,
|
|
status: emailResult.success ? 'sent' : 'failed',
|
|
timestamp: new Date().toISOString(),
|
|
senderIP: req.ip || req.connection.remoteAddress
|
|
});
|
|
|
|
if (emailResult.success) {
|
|
res.json({
|
|
success: true,
|
|
message: 'Email sent successfully',
|
|
messageId: emailResult.messageId
|
|
});
|
|
} else {
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to send email',
|
|
message: emailResult.error
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('Send email error:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to send email',
|
|
message: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async previewEmail(req, res, next) {
|
|
try {
|
|
const { recipientEmail, subject, message, senderName, senderEmail, postalCode, recipientName } = req.body;
|
|
|
|
const templateVariables = {
|
|
MESSAGE: message,
|
|
SENDER_NAME: senderName || 'Anonymous',
|
|
SENDER_EMAIL: senderEmail || 'unknown@example.com',
|
|
POSTAL_CODE: postalCode || 'Unknown',
|
|
RECIPIENT_NAME: recipientName || 'Representative'
|
|
};
|
|
|
|
const emailOptions = {
|
|
to: recipientEmail,
|
|
from: {
|
|
email: process.env.SMTP_FROM_EMAIL,
|
|
name: process.env.SMTP_FROM_NAME
|
|
},
|
|
replyTo: senderEmail || process.env.SMTP_FROM_EMAIL,
|
|
subject: subject
|
|
};
|
|
|
|
const preview = await emailService.previewTemplatedEmail('representative-contact', templateVariables, emailOptions);
|
|
|
|
// Log the email preview event (non-blocking)
|
|
try {
|
|
await nocoDB.logEmailPreview({
|
|
recipientEmail,
|
|
senderName,
|
|
senderEmail,
|
|
subject,
|
|
message,
|
|
postalCode,
|
|
timestamp: new Date().toISOString(),
|
|
senderIP: req.ip || req.connection.remoteAddress
|
|
});
|
|
} catch (loggingError) {
|
|
console.error('Failed to log email preview:', loggingError);
|
|
// Don't fail the preview if logging fails
|
|
}
|
|
|
|
res.json({
|
|
success: true,
|
|
preview: preview,
|
|
html: emailOptions.html
|
|
});
|
|
} catch (error) {
|
|
console.error('Email preview error:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to generate email preview',
|
|
message: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async sendTestEmail(req, res, next) {
|
|
try {
|
|
const { subject, message } = req.body;
|
|
|
|
const testRecipient = process.env.TEST_EMAIL_RECIPIENT || req.user?.email || 'admin@example.com';
|
|
|
|
const emailResult = await emailService.sendTestEmail(subject, message, testRecipient);
|
|
|
|
if (emailResult.success) {
|
|
res.json({
|
|
success: true,
|
|
message: 'Test email sent successfully',
|
|
messageId: emailResult.messageId,
|
|
sentTo: testRecipient,
|
|
testMode: emailResult.testMode
|
|
});
|
|
} else {
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to send test email',
|
|
message: emailResult.error
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('Send test email error:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to send test email',
|
|
message: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async getEmailLogs(req, res, next) {
|
|
try {
|
|
const { status, senderEmail, postalCode } = req.query;
|
|
|
|
if (!process.env.NOCODB_TABLE_EMAILS) {
|
|
return res.status(500).json({
|
|
success: false,
|
|
error: 'Email logging not configured'
|
|
});
|
|
}
|
|
|
|
const filters = {};
|
|
if (status) filters.status = status;
|
|
if (senderEmail) filters.senderEmail = senderEmail;
|
|
if (postalCode) filters.postalCode = postalCode;
|
|
|
|
const logs = await nocoDB.getEmailLogs(filters);
|
|
|
|
res.json({
|
|
success: true,
|
|
logs: logs || []
|
|
});
|
|
} catch (error) {
|
|
console.error('Get email logs error:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to retrieve email logs',
|
|
message: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async testSMTPConnection(req, res, next) {
|
|
try {
|
|
const testResult = await emailService.testConnection();
|
|
|
|
res.json({
|
|
success: testResult.success,
|
|
message: testResult.message,
|
|
error: testResult.error
|
|
});
|
|
} catch (error) {
|
|
console.error('SMTP test error:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to test SMTP connection',
|
|
message: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async testSMTPConnection(req, res, next) {
|
|
try {
|
|
const result = await emailService.testConnection();
|
|
|
|
res.json({
|
|
success: result.success,
|
|
message: result.message,
|
|
error: result.error
|
|
});
|
|
} catch (error) {
|
|
console.error('SMTP test error:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to test SMTP connection',
|
|
message: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async initiateEmailToCampaign(req, res, next) {
|
|
try {
|
|
const { email, subject, message, postalCode, senderName } = req.body;
|
|
|
|
// Check if email verification is enabled
|
|
const verificationEnabled = process.env.EMAIL_VERIFICATION_ENABLED !== 'false';
|
|
if (!verificationEnabled) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Email verification is not enabled'
|
|
});
|
|
}
|
|
|
|
// Generate verification token
|
|
const token = crypto.randomBytes(32).toString('hex');
|
|
const expiryHours = parseInt(process.env.EMAIL_VERIFICATION_EXPIRY) || 24;
|
|
const expiresAt = new Date(Date.now() + expiryHours * 60 * 60 * 1000);
|
|
|
|
// Store token and campaign data
|
|
await nocoDB.createEmailVerification({
|
|
token,
|
|
email,
|
|
temp_campaign_data: JSON.stringify({
|
|
subject,
|
|
message,
|
|
postalCode,
|
|
senderName
|
|
}),
|
|
created_at: new Date().toISOString(),
|
|
expires_at: expiresAt.toISOString(),
|
|
used: false
|
|
});
|
|
|
|
// Send verification email
|
|
const appUrl = process.env.APP_URL || 'http://localhost:3333';
|
|
const verificationUrl = `${appUrl}/verify-email.html?token=${token}`;
|
|
await emailService.sendEmailVerification(email, verificationUrl, senderName || 'there');
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Verification email sent. Please check your inbox.'
|
|
});
|
|
} catch (error) {
|
|
console.error('Email to campaign conversion error:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to initiate campaign conversion',
|
|
message: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async verifyEmailToken(req, res, next) {
|
|
try {
|
|
const { token } = req.params;
|
|
|
|
// Find verification record
|
|
const verification = await nocoDB.getEmailVerificationByToken(token);
|
|
|
|
if (!verification) {
|
|
return res.status(404).json({
|
|
success: false,
|
|
error: 'Invalid or expired verification link'
|
|
});
|
|
}
|
|
|
|
// Check if already used
|
|
if (verification.used) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'This verification link has already been used'
|
|
});
|
|
}
|
|
|
|
// Check if expired
|
|
const now = new Date();
|
|
const expiresAt = new Date(verification.expires_at || verification.expiresAt || verification['Expires At']);
|
|
if (now > expiresAt) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'This verification link has expired'
|
|
});
|
|
}
|
|
|
|
// Mark as used
|
|
const verificationId = verification.id || verification.Id || verification.ID;
|
|
await nocoDB.updateEmailVerification(verificationId, { used: true });
|
|
|
|
// Parse campaign data
|
|
const campaignDataStr = verification.temp_campaign_data || verification.tempCampaignData || verification['Temp Campaign Data'];
|
|
const campaignData = JSON.parse(campaignDataStr);
|
|
|
|
// Check if user exists
|
|
const userEmail = verification.email || verification.Email;
|
|
const existingUser = await nocoDB.getUserByEmail(userEmail);
|
|
|
|
if (existingUser) {
|
|
// User exists, log them in automatically
|
|
req.session.authenticated = true;
|
|
req.session.userId = existingUser.ID || existingUser.Id || existingUser.id;
|
|
req.session.userEmail = existingUser.Email || existingUser.email;
|
|
req.session.userName = existingUser.Name || existingUser.name;
|
|
req.session.isAdmin = existingUser.Admin || existingUser.admin || false;
|
|
req.session.userType = existingUser['User Type'] || existingUser.UserType || existingUser.userType || 'user';
|
|
|
|
req.session.save((err) => {
|
|
if (err) {
|
|
console.error('Session save error:', err);
|
|
return res.status(500).json({
|
|
success: false,
|
|
error: 'Session error'
|
|
});
|
|
}
|
|
|
|
res.json({
|
|
success: true,
|
|
needsAccount: false,
|
|
campaignData: campaignData,
|
|
redirectTo: '/dashboard.html'
|
|
});
|
|
});
|
|
} else {
|
|
// User doesn't exist - create a new user account automatically
|
|
try {
|
|
// Generate a temporary password (user can change it later)
|
|
const tempPassword = crypto.randomBytes(16).toString('hex');
|
|
|
|
// Extract name from campaign data or use email prefix
|
|
const userName = campaignData.senderName || userEmail.split('@')[0];
|
|
|
|
// Create new user
|
|
const newUser = await nocoDB.createUser({
|
|
'Name': userName,
|
|
'Email': userEmail,
|
|
'Password': tempPassword,
|
|
'Admin': false,
|
|
'User Type': 'user'
|
|
});
|
|
|
|
const userId = newUser.ID || newUser.Id || newUser.id || newUser;
|
|
|
|
// Send login credentials email to the new user
|
|
try {
|
|
await emailService.sendLoginDetails({
|
|
Name: userName,
|
|
Email: userEmail,
|
|
Password: tempPassword,
|
|
admin: false
|
|
});
|
|
console.log('Welcome email with credentials sent to:', userEmail);
|
|
} catch (emailError) {
|
|
console.error('Failed to send welcome email:', emailError);
|
|
// Don't fail the whole process if email sending fails
|
|
}
|
|
|
|
// Log the new user in automatically
|
|
req.session.authenticated = true;
|
|
req.session.userId = userId;
|
|
req.session.userEmail = userEmail;
|
|
req.session.userName = userName;
|
|
req.session.isAdmin = false;
|
|
req.session.userType = 'user';
|
|
|
|
req.session.save((err) => {
|
|
if (err) {
|
|
console.error('Session save error:', err);
|
|
return res.status(500).json({
|
|
success: false,
|
|
error: 'Session error'
|
|
});
|
|
}
|
|
|
|
res.json({
|
|
success: true,
|
|
needsAccount: false,
|
|
isNewUser: true,
|
|
campaignData: campaignData,
|
|
redirectTo: '/dashboard.html',
|
|
message: 'Account created successfully! Check your email for login credentials.'
|
|
});
|
|
});
|
|
} catch (createError) {
|
|
console.error('Error creating user account:', createError);
|
|
return res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to create user account',
|
|
message: createError.message
|
|
});
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Email verification error:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to verify email',
|
|
message: error.message
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = new EmailsController(); |