Bunch of buag fixes and updates
This commit is contained in:
@@ -50,10 +50,23 @@ class AuthController {
|
||||
|
||||
// Update last login time
|
||||
try {
|
||||
const userId = user.Id || user.id;
|
||||
await nocodbService.updateUser(userId, {
|
||||
'Last Login': new Date().toISOString()
|
||||
// Debug: Log user object structure
|
||||
console.log('User object keys:', Object.keys(user));
|
||||
console.log('User ID candidates:', {
|
||||
ID: user.ID,
|
||||
Id: user.Id,
|
||||
id: user.id
|
||||
});
|
||||
|
||||
const userId = user.ID || user.Id || user.id;
|
||||
|
||||
if (userId) {
|
||||
await nocodbService.updateUser(userId, {
|
||||
'Last Login': new Date().toISOString()
|
||||
});
|
||||
} else {
|
||||
console.warn('No valid user ID found for updating last login time');
|
||||
}
|
||||
} catch (updateError) {
|
||||
console.warn('Failed to update last login time:', updateError.message);
|
||||
// Don't fail the login
|
||||
@@ -61,7 +74,7 @@ class AuthController {
|
||||
|
||||
// Set session
|
||||
req.session.authenticated = true;
|
||||
req.session.userId = user.Id || user.id;
|
||||
req.session.userId = user.ID || user.Id || user.id;
|
||||
req.session.userEmail = user.Email || user.email;
|
||||
req.session.userName = user.Name || user.name;
|
||||
req.session.isAdmin = user.Admin || user.admin || false;
|
||||
|
||||
@@ -3,6 +3,30 @@ const emailService = require('../services/email');
|
||||
const representAPI = require('../services/represent-api');
|
||||
const { generateSlug, validateSlug } = require('../utils/validators');
|
||||
|
||||
// Helper function to cache representatives
|
||||
async function cacheRepresentatives(postalCode, representatives, representData) {
|
||||
try {
|
||||
// Cache the postal code info
|
||||
await nocoDB.storePostalCodeInfo({
|
||||
postal_code: postalCode,
|
||||
city: representData.city,
|
||||
province: representData.province
|
||||
});
|
||||
|
||||
// Cache representatives using the existing method
|
||||
const result = await nocoDB.storeRepresentatives(postalCode, representatives);
|
||||
|
||||
if (result.success) {
|
||||
console.log(`Successfully cached ${result.count} representatives for ${postalCode}`);
|
||||
} else {
|
||||
console.log(`Partial success caching representatives for ${postalCode}: ${result.error || 'unknown error'}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`Failed to cache representatives for ${postalCode}:`, error.message);
|
||||
// Don't throw - caching is optional and should never break the main flow
|
||||
}
|
||||
}
|
||||
|
||||
class CampaignsController {
|
||||
// Get all campaigns (for admin panel)
|
||||
async getAllCampaigns(req, res, next) {
|
||||
@@ -31,6 +55,7 @@ class CampaignsController {
|
||||
allow_mailto_link: campaign['Allow Mailto Link'] || campaign.allow_mailto_link,
|
||||
collect_user_info: campaign['Collect User Info'] || campaign.collect_user_info,
|
||||
show_email_count: campaign['Show Email Count'] || campaign.show_email_count,
|
||||
allow_email_editing: campaign['Allow Email Editing'] || campaign.allow_email_editing,
|
||||
target_government_levels: campaign['Target Government Levels'] || campaign.target_government_levels,
|
||||
created_at: campaign.CreatedAt || campaign.created_at,
|
||||
updated_at: campaign.UpdatedAt || campaign.updated_at,
|
||||
@@ -91,6 +116,7 @@ class CampaignsController {
|
||||
allow_mailto_link: campaign['Allow Mailto Link'] || campaign.allow_mailto_link,
|
||||
collect_user_info: campaign['Collect User Info'] || campaign.collect_user_info,
|
||||
show_email_count: campaign['Show Email Count'] || campaign.show_email_count,
|
||||
allow_email_editing: campaign['Allow Email Editing'] || campaign.allow_email_editing,
|
||||
target_government_levels: campaign['Target Government Levels'] || campaign.target_government_levels,
|
||||
created_at: campaign.CreatedAt || campaign.created_at,
|
||||
updated_at: campaign.UpdatedAt || campaign.updated_at,
|
||||
@@ -153,6 +179,7 @@ class CampaignsController {
|
||||
allow_mailto_link: campaign['Allow Mailto Link'] || campaign.allow_mailto_link,
|
||||
collect_user_info: campaign['Collect User Info'] || campaign.collect_user_info,
|
||||
show_email_count: campaign['Show Email Count'] || campaign.show_email_count,
|
||||
allow_email_editing: campaign['Allow Email Editing'] || campaign.allow_email_editing,
|
||||
target_government_levels: Array.isArray(campaign['Target Government Levels'] || campaign.target_government_levels)
|
||||
? (campaign['Target Government Levels'] || campaign.target_government_levels)
|
||||
: (typeof (campaign['Target Government Levels'] || campaign.target_government_levels) === 'string' && (campaign['Target Government Levels'] || campaign.target_government_levels).length > 0
|
||||
@@ -181,10 +208,12 @@ class CampaignsController {
|
||||
email_subject,
|
||||
email_body,
|
||||
call_to_action,
|
||||
status = 'draft',
|
||||
allow_smtp_email = true,
|
||||
allow_mailto_link = true,
|
||||
collect_user_info = true,
|
||||
show_email_count = true,
|
||||
allow_email_editing = false,
|
||||
target_government_levels = ['Federal', 'Provincial', 'Municipal']
|
||||
} = req.body;
|
||||
|
||||
@@ -206,11 +235,12 @@ class CampaignsController {
|
||||
email_subject,
|
||||
email_body,
|
||||
call_to_action,
|
||||
status: 'draft',
|
||||
status,
|
||||
allow_smtp_email,
|
||||
allow_mailto_link,
|
||||
collect_user_info,
|
||||
show_email_count,
|
||||
allow_email_editing,
|
||||
// NocoDB MultiSelect expects an array of values
|
||||
target_government_levels: Array.isArray(target_government_levels)
|
||||
? target_government_levels
|
||||
@@ -237,6 +267,7 @@ class CampaignsController {
|
||||
allow_mailto_link: campaign['Allow Mailto Link'] || campaign.allow_mailto_link,
|
||||
collect_user_info: campaign['Collect User Info'] || campaign.collect_user_info,
|
||||
show_email_count: campaign['Show Email Count'] || campaign.show_email_count,
|
||||
allow_email_editing: campaign['Allow Email Editing'] || campaign.allow_email_editing,
|
||||
target_government_levels: campaign['Target Government Levels'] || campaign.target_government_levels,
|
||||
created_at: campaign.CreatedAt || campaign.created_at,
|
||||
updated_at: campaign.UpdatedAt || campaign.updated_at
|
||||
@@ -356,7 +387,9 @@ class CampaignsController {
|
||||
recipientName,
|
||||
recipientTitle,
|
||||
recipientLevel,
|
||||
emailMethod = 'smtp'
|
||||
emailMethod = 'smtp',
|
||||
customEmailSubject,
|
||||
customEmailBody
|
||||
} = req.body;
|
||||
|
||||
// Get campaign
|
||||
@@ -392,8 +425,14 @@ class CampaignsController {
|
||||
});
|
||||
}
|
||||
|
||||
const subject = campaign['Email Subject'] || campaign.email_subject;
|
||||
const message = campaign['Email Body'] || campaign.email_body;
|
||||
// Use custom email content if provided (when email editing is enabled), otherwise use campaign defaults
|
||||
const allowEmailEditing = campaign['Allow Email Editing'] || campaign.allow_email_editing;
|
||||
const subject = (allowEmailEditing && customEmailSubject)
|
||||
? customEmailSubject
|
||||
: (campaign['Email Subject'] || campaign.email_subject);
|
||||
const message = (allowEmailEditing && customEmailBody)
|
||||
? customEmailBody
|
||||
: (campaign['Email Body'] || campaign.email_body);
|
||||
|
||||
let emailResult = { success: true };
|
||||
|
||||
@@ -539,20 +578,46 @@ class CampaignsController {
|
||||
});
|
||||
}
|
||||
|
||||
// Get representatives
|
||||
const result = await representAPI.getRepresentativesByPostalCode(postalCode);
|
||||
|
||||
// Process representatives from both concordance and centroid
|
||||
// First check cache for representatives
|
||||
const formattedPostalCode = postalCode.replace(/\s/g, '').toUpperCase();
|
||||
let representatives = [];
|
||||
let result = null;
|
||||
|
||||
// Add concordance representatives (if any)
|
||||
if (result.representatives_concordance && result.representatives_concordance.length > 0) {
|
||||
representatives = representatives.concat(result.representatives_concordance);
|
||||
// Try to check cached data first, but don't fail if NocoDB is down
|
||||
let cachedData = [];
|
||||
try {
|
||||
cachedData = await nocoDB.getRepresentativesByPostalCode(formattedPostalCode);
|
||||
console.log(`Cache check for ${formattedPostalCode}: found ${cachedData.length} records`);
|
||||
|
||||
if (cachedData && cachedData.length > 0) {
|
||||
representatives = cachedData;
|
||||
console.log(`Using cached representatives for ${formattedPostalCode}`);
|
||||
}
|
||||
} catch (cacheError) {
|
||||
console.log(`Cache unavailable for ${formattedPostalCode}, proceeding with API call:`, cacheError.message);
|
||||
}
|
||||
|
||||
// Add centroid representatives (if any) - these are the actual elected officials
|
||||
if (result.representatives_centroid && result.representatives_centroid.length > 0) {
|
||||
representatives = representatives.concat(result.representatives_centroid);
|
||||
|
||||
// If not in cache, fetch from Represent API
|
||||
if (representatives.length === 0) {
|
||||
console.log(`Fetching representatives from Represent API for ${formattedPostalCode}`);
|
||||
result = await representAPI.getRepresentativesByPostalCode(postalCode);
|
||||
|
||||
// Process representatives from both concordance and centroid
|
||||
// Add concordance representatives (if any)
|
||||
if (result.representatives_concordance && result.representatives_concordance.length > 0) {
|
||||
representatives = representatives.concat(result.representatives_concordance);
|
||||
}
|
||||
|
||||
// Add centroid representatives (if any) - these are the actual elected officials
|
||||
if (result.representatives_centroid && result.representatives_centroid.length > 0) {
|
||||
representatives = representatives.concat(result.representatives_centroid);
|
||||
}
|
||||
|
||||
// Cache the results if we got them from the API
|
||||
if (representatives.length > 0 && result) {
|
||||
console.log(`Attempting to cache ${representatives.length} representatives for ${formattedPostalCode}`);
|
||||
await cacheRepresentatives(formattedPostalCode, representatives, result);
|
||||
}
|
||||
}
|
||||
|
||||
if (representatives.length === 0) {
|
||||
@@ -561,8 +626,8 @@ class CampaignsController {
|
||||
message: 'No representatives found for this postal code',
|
||||
representatives: [],
|
||||
location: {
|
||||
city: result.city,
|
||||
province: result.province
|
||||
city: result?.city || 'Alberta',
|
||||
province: result?.province || 'AB'
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -602,8 +667,8 @@ class CampaignsController {
|
||||
success: true,
|
||||
representatives: filteredRepresentatives,
|
||||
location: {
|
||||
city: result.city,
|
||||
province: result.province
|
||||
city: result?.city || cachedData[0]?.city || 'Alberta',
|
||||
province: result?.province || cachedData[0]?.province || 'AB'
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ const nocoDB = require('../services/nocodb');
|
||||
class EmailsController {
|
||||
async sendEmail(req, res, next) {
|
||||
try {
|
||||
const { recipientEmail, senderName, senderEmail, subject, message, postalCode } = req.body;
|
||||
const { recipientEmail, senderName, senderEmail, subject, message, postalCode, recipientName } = req.body;
|
||||
|
||||
// Send the email using template system
|
||||
const emailResult = await emailService.sendRepresentativeEmail(
|
||||
@@ -13,7 +13,8 @@ class EmailsController {
|
||||
senderEmail,
|
||||
subject,
|
||||
message,
|
||||
postalCode
|
||||
postalCode,
|
||||
recipientName
|
||||
);
|
||||
|
||||
// Log the email send event
|
||||
@@ -22,6 +23,7 @@ class EmailsController {
|
||||
senderName,
|
||||
senderEmail,
|
||||
subject,
|
||||
message,
|
||||
postalCode,
|
||||
status: emailResult.success ? 'sent' : 'failed',
|
||||
timestamp: new Date().toISOString(),
|
||||
@@ -53,13 +55,14 @@ class EmailsController {
|
||||
|
||||
async previewEmail(req, res, next) {
|
||||
try {
|
||||
const { recipientEmail, subject, message, senderName, senderEmail, postalCode } = req.body;
|
||||
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'
|
||||
POSTAL_CODE: postalCode || 'Unknown',
|
||||
RECIPIENT_NAME: recipientName || 'Representative'
|
||||
};
|
||||
|
||||
const emailOptions = {
|
||||
@@ -74,6 +77,23 @@ class EmailsController {
|
||||
|
||||
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,
|
||||
|
||||
@@ -12,12 +12,16 @@ async function cacheRepresentatives(postalCode, representatives, representData)
|
||||
});
|
||||
|
||||
// Cache representatives using the existing method
|
||||
await nocoDB.storeRepresentatives(postalCode, representatives);
|
||||
const result = await nocoDB.storeRepresentatives(postalCode, representatives);
|
||||
|
||||
console.log(`Successfully cached representatives for ${postalCode}`);
|
||||
if (result.success) {
|
||||
console.log(`Successfully cached ${result.count} representatives for ${postalCode}`);
|
||||
} else {
|
||||
console.log(`Partial success caching representatives for ${postalCode}: ${result.error || 'unknown error'}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`Failed to cache representatives for ${postalCode}:`, error.message);
|
||||
// Don't throw - caching is optional
|
||||
// Don't throw - caching is optional and should never break the main flow
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +52,16 @@ class RepresentativesController {
|
||||
|
||||
if (cachedData && cachedData.length > 0) {
|
||||
return res.json({
|
||||
source: 'cache',
|
||||
postalCode: formattedPostalCode,
|
||||
representatives: cachedData
|
||||
success: true,
|
||||
source: 'Local Cache',
|
||||
data: {
|
||||
postalCode: formattedPostalCode,
|
||||
location: {
|
||||
city: cachedData[0]?.city || 'Alberta',
|
||||
province: 'AB'
|
||||
},
|
||||
representatives: cachedData
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (cacheError) {
|
||||
@@ -85,6 +96,9 @@ class RepresentativesController {
|
||||
if (representData.representatives_centroid && representData.representatives_centroid.length > 0) {
|
||||
representatives = representatives.concat(representData.representatives_centroid);
|
||||
}
|
||||
|
||||
// Representatives already include office information, no need for additional API calls
|
||||
console.log('Using representatives data with existing office information');
|
||||
|
||||
console.log(`Representatives concordance count: ${representData.boundaries_concordance ? representData.boundaries_concordance.length : 0}`);
|
||||
console.log(`Representatives centroid count: ${representData.representatives_centroid ? representData.representatives_centroid.length : 0}`);
|
||||
@@ -111,6 +125,7 @@ class RepresentativesController {
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
source: 'Open North',
|
||||
data: {
|
||||
postalCode,
|
||||
location: {
|
||||
@@ -151,7 +166,7 @@ class RepresentativesController {
|
||||
await nocoDB.storeRepresentatives(formattedPostalCode, representData.representatives_concordance);
|
||||
|
||||
res.json({
|
||||
source: 'refreshed',
|
||||
source: 'Open North',
|
||||
postalCode: formattedPostalCode,
|
||||
representatives: representData.representatives_concordance,
|
||||
city: representData.city,
|
||||
|
||||
Reference in New Issue
Block a user