282 lines
9.0 KiB
JavaScript
282 lines
9.0 KiB
JavaScript
const representAPI = require('../services/represent-api');
|
|
const nocoDB = require('../services/nocodb');
|
|
|
|
// 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 RepresentativesController {
|
|
async testConnection(req, res, next) {
|
|
try {
|
|
const result = await representAPI.testConnection();
|
|
res.json(result);
|
|
} catch (error) {
|
|
console.error('Test connection error:', error);
|
|
res.status(500).json({
|
|
error: 'Failed to test connection',
|
|
message: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async getByPostalCode(req, res, next) {
|
|
try {
|
|
const { postalCode } = req.params;
|
|
const formattedPostalCode = postalCode.replace(/\s/g, '').toUpperCase();
|
|
|
|
// 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) {
|
|
return res.json({
|
|
success: true,
|
|
source: 'Local Cache',
|
|
data: {
|
|
postalCode: formattedPostalCode,
|
|
location: {
|
|
city: cachedData[0]?.city || 'Alberta',
|
|
province: 'AB'
|
|
},
|
|
representatives: cachedData
|
|
}
|
|
});
|
|
}
|
|
} catch (cacheError) {
|
|
console.log(`Cache unavailable for ${formattedPostalCode}, proceeding with API call:`, cacheError.message);
|
|
}
|
|
|
|
// If not in cache, fetch from Represent API
|
|
console.log(`Fetching representatives from Represent API for ${postalCode}`);
|
|
const representData = await representAPI.getRepresentativesByPostalCode(postalCode);
|
|
|
|
if (!representData) {
|
|
return res.json({
|
|
success: false,
|
|
message: 'No data found for this postal code',
|
|
data: {
|
|
postalCode,
|
|
location: null,
|
|
representatives: []
|
|
}
|
|
});
|
|
}
|
|
|
|
// Process representatives from both concordance and centroid
|
|
let representatives = [];
|
|
|
|
// Add concordance representatives (if any)
|
|
if (representData.boundaries_concordance && representData.boundaries_concordance.length > 0) {
|
|
representatives = representatives.concat(representData.boundaries_concordance);
|
|
}
|
|
|
|
// Add centroid representatives (if any) - these are the actual elected officials
|
|
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}`);
|
|
console.log(`Total representatives found: ${representatives.length}`);
|
|
|
|
if (representatives.length === 0) {
|
|
return res.json({
|
|
success: false,
|
|
message: 'No representatives found for this postal code',
|
|
data: {
|
|
postalCode,
|
|
location: {
|
|
city: representData.city,
|
|
province: representData.province
|
|
},
|
|
representatives: []
|
|
}
|
|
});
|
|
}
|
|
|
|
// Try to cache the results (will fail gracefully if NocoDB is down)
|
|
console.log(`Attempting to cache ${representatives.length} representatives for ${postalCode}`);
|
|
await cacheRepresentatives(postalCode, representatives, representData);
|
|
|
|
res.json({
|
|
success: true,
|
|
source: 'Open North',
|
|
data: {
|
|
postalCode,
|
|
location: {
|
|
city: representData.city,
|
|
province: representData.province
|
|
},
|
|
representatives
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('Get representatives error:', error);
|
|
res.status(500).json({
|
|
error: 'Failed to fetch representatives',
|
|
message: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async refreshPostalCode(req, res, next) {
|
|
try {
|
|
const { postalCode } = req.params;
|
|
const formattedPostalCode = postalCode.replace(/\s/g, '').toUpperCase();
|
|
|
|
// Clear cached data
|
|
await nocoDB.clearRepresentativesByPostalCode(formattedPostalCode);
|
|
|
|
// Fetch fresh data from API
|
|
const representData = await representAPI.getRepresentativesByPostalCode(formattedPostalCode);
|
|
|
|
if (!representData || !representData.representatives_concordance) {
|
|
return res.status(404).json({
|
|
error: 'No representatives found for this postal code',
|
|
postalCode: formattedPostalCode
|
|
});
|
|
}
|
|
|
|
// Cache the fresh results
|
|
await nocoDB.storeRepresentatives(formattedPostalCode, representData.representatives_concordance);
|
|
|
|
res.json({
|
|
source: 'Open North',
|
|
postalCode: formattedPostalCode,
|
|
representatives: representData.representatives_concordance,
|
|
city: representData.city,
|
|
province: representData.province
|
|
});
|
|
} catch (error) {
|
|
console.error('Refresh representatives error:', error);
|
|
res.status(500).json({
|
|
error: 'Failed to refresh representatives',
|
|
message: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async trackCall(req, res, next) {
|
|
try {
|
|
const {
|
|
representativeName,
|
|
representativeTitle,
|
|
phoneNumber,
|
|
officeType,
|
|
userEmail,
|
|
userName,
|
|
postalCode
|
|
} = req.body;
|
|
|
|
// Validate required fields
|
|
if (!representativeName || !phoneNumber) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Representative name and phone number are required'
|
|
});
|
|
}
|
|
|
|
// Log the call
|
|
await nocoDB.logCall({
|
|
representativeName,
|
|
representativeTitle: representativeTitle || null,
|
|
phoneNumber,
|
|
officeType: officeType || null,
|
|
callerName: userName || null,
|
|
callerEmail: userEmail || null,
|
|
postalCode: postalCode || null,
|
|
campaignId: null,
|
|
campaignSlug: null,
|
|
callerIP: req.ip || req.connection?.remoteAddress || null,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Call tracked successfully'
|
|
});
|
|
} catch (error) {
|
|
console.error('Track call error:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to track call',
|
|
message: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async geocodeAddress(req, res, next) {
|
|
try {
|
|
const { address } = req.body;
|
|
const axios = require('axios');
|
|
|
|
console.log(`Geocoding address: ${address}`);
|
|
|
|
// Use Nominatim API (OpenStreetMap)
|
|
const encodedAddress = encodeURIComponent(address);
|
|
const url = `https://nominatim.openstreetmap.org/search?format=json&q=${encodedAddress}&limit=1&countrycodes=ca`;
|
|
|
|
const response = await axios.get(url, {
|
|
headers: {
|
|
'User-Agent': 'BNKops-Influence-Tool/1.0'
|
|
},
|
|
timeout: 5000
|
|
});
|
|
|
|
if (response.data && response.data.length > 0 && response.data[0].lat && response.data[0].lon) {
|
|
const result = {
|
|
lat: parseFloat(response.data[0].lat),
|
|
lng: parseFloat(response.data[0].lon),
|
|
display_name: response.data[0].display_name
|
|
};
|
|
|
|
console.log(`Geocoded "${address}" to:`, result);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: result
|
|
});
|
|
} else {
|
|
console.log(`No geocoding results for: ${address}`);
|
|
res.json({
|
|
success: false,
|
|
message: 'No results found for this address'
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('Geocoding error:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Geocoding failed',
|
|
message: error.message
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = new RepresentativesController(); |