freealberta/scripts/update-campaigns.js

189 lines
7.9 KiB
JavaScript

#!/usr/bin/env node
/**
* Script to update campaign call-to-action text with correct minister titles
* Run with: node scripts/update-campaigns.js
*/
const https = require('https');
// NocoDB Configuration
const NOCODB_API_URL = 'https://db.freealberta.org';
const NOCODB_API_TOKEN = 'H3z5PEgvrC25LDRuvRpF1wuzsByG9PCem5DHyjPj';
const PROJECT_ID = 'plc0u50kgobr2xh';
const CAMPAIGNS_TABLE_ID = 'mh98emvhot9gjrg';
// Campaign updates - mapping slug to correct call-to-action text
const campaignUpdates = [
// Indigenous Relations - now Rajan Sawhney
{ slug: 'indigenous-relations', call_to_action: 'Email Minister of Indigenous Relations' },
{ slug: 'land-rights', call_to_action: 'Email Minister of Indigenous Relations' },
{ slug: 'landback', call_to_action: 'Email Minister Responsible for Landback' },
// Municipal Affairs - now Dan Williams
{ slug: 'land-use', call_to_action: 'Email Minister of Municipal Affairs' },
{ slug: 'municipal-transit', call_to_action: 'Email Minister of Municipal Affairs' },
{ slug: 'gathering-spaces-municipal', call_to_action: 'Email Minister of Municipal Affairs' },
// Environment - now Grant Hunter
{ slug: 'environment-protection', call_to_action: 'Email Minister of Environment and Protected Areas' },
{ slug: 'water-protection', call_to_action: 'Email Minister of Environment and Protected Areas' },
{ slug: 'air-quality-protection', call_to_action: 'Email Minister of Environment and Protected Areas' },
// Mental Health and Addiction - now Rick Wilson
{ slug: 'mental-health', call_to_action: 'Email Minister of Mental Health and Addiction' },
{ slug: 'mental-health-rest', call_to_action: 'Email Minister of Mental Health and Addiction' },
{ slug: 'love-williams', call_to_action: 'Email Minister of Mental Health and Addiction' },
// Advanced Education - now Myles McDougall
{ slug: 'higher-education', call_to_action: 'Email Minister of Advanced Education' },
{ slug: 'higher-learning', call_to_action: 'Email Minister of Advanced Education' },
// Jobs, Economy, Trade and Immigration - now Joseph Schow
{ slug: 'economic-reform', call_to_action: 'Email Minister of Jobs, Economy, Trade and Immigration' },
{ slug: 'career-transition', call_to_action: 'Email Minister of Jobs, Economy, Trade and Immigration' },
{ slug: 'work-life', call_to_action: 'Email Minister of Jobs, Economy, Trade and Immigration' },
{ slug: 'association-rights-jobs', call_to_action: 'Email Minister of Jobs, Economy, Trade and Immigration' },
// Tourism and Sport - now Andrew Boitchenko
{ slug: 'corporate-oversight', call_to_action: 'Email Minister of Tourism and Sport' },
{ slug: 'public-spaces', call_to_action: 'Email Minister of Tourism and Sport' },
{ slug: 'recreation-tourism', call_to_action: 'Email Minister of Tourism and Sport' },
// Assisted Living and Social Services - now Jason Nixon (updated title)
{ slug: 'social-support', call_to_action: 'Email Minister of Assisted Living and Social Services' },
{ slug: 'food-access', call_to_action: 'Email Minister of Assisted Living and Social Services' },
{ slug: 'water-access', call_to_action: 'Email Minister of Assisted Living and Social Services' },
{ slug: 'seniors-housing', call_to_action: 'Email Minister of Assisted Living and Social Services' },
// Associate Minister of Multiculturalism - Muhammad Yaseen (not full minister)
{ slug: 'immigration-rights', call_to_action: 'Email Associate Minister of Multiculturalism' },
{ slug: 'cultural-association-rights', call_to_action: 'Email Associate Minister of Multiculturalism' },
// Public Safety and Emergency Services - Mike Ellis (updated title)
{ slug: 'police-accountability', call_to_action: 'Email Minister of Public Safety and Emergency Services' },
{ slug: 'anti-corruption', call_to_action: 'Email Minister of Public Safety and Emergency Services' },
{ slug: 'assembly-rights', call_to_action: 'Email Minister of Public Safety and Emergency Services' },
// Energy and Minerals - Brian Jean (updated title)
{ slug: 'clean-energy', call_to_action: 'Email Minister of Energy and Minerals' },
{ slug: 'energy-reform', call_to_action: 'Email Minister of Energy and Minerals' },
// Education and Childcare - Demetrios Nicolaides (updated title)
{ slug: 'education-reform', call_to_action: 'Email Minister of Education and Childcare' },
{ slug: 'learning-access', call_to_action: 'Email Minister of Education and Childcare' },
// Transportation and Economic Corridors - Devin Dreeshen (updated title)
{ slug: 'transport-reform', call_to_action: 'Email Minister of Transportation and Economic Corridors' },
// Agriculture and Irrigation - RJ Sigurdson (updated title)
{ slug: 'food-security', call_to_action: 'Email Minister of Agriculture and Irrigation' },
// Service Alberta and Red Tape Reduction - Dale Nally (updated title)
{ slug: 'public-services-reform', call_to_action: 'Email Minister of Service Alberta and Red Tape Reduction' },
{ slug: 'telecom-reform', call_to_action: 'Email Minister of Service Alberta and Red Tape Reduction' },
// Affordability and Utilities - Nathan Neudorf
{ slug: 'utilities-reform', call_to_action: 'Email Minister of Affordability and Utilities' },
];
// Get campaign by slug
async function getCampaignBySlug(slug) {
return new Promise((resolve, reject) => {
const options = {
hostname: 'db.freealberta.org',
port: 443,
path: `/api/v1/db/data/v1/${PROJECT_ID}/${CAMPAIGNS_TABLE_ID}?where=(Campaign%20Slug,eq,${slug})`,
method: 'GET',
headers: {
'xc-token': NOCODB_API_TOKEN
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
try {
const result = JSON.parse(data);
resolve(result.list && result.list.length > 0 ? result.list[0] : null);
} catch (e) {
reject(e);
}
});
});
req.on('error', reject);
req.end();
});
}
// Update campaign
async function updateCampaign(id, updates) {
return new Promise((resolve, reject) => {
const postData = JSON.stringify(updates);
const options = {
hostname: 'db.freealberta.org',
port: 443,
path: `/api/v1/db/data/v1/${PROJECT_ID}/${CAMPAIGNS_TABLE_ID}/${id}`,
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'xc-token': NOCODB_API_TOKEN,
'Content-Length': Buffer.byteLength(postData)
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve({ success: true });
} else {
reject(new Error(`Failed: ${res.statusCode} - ${data}`));
}
});
});
req.on('error', reject);
req.write(postData);
req.end();
});
}
async function main() {
console.log(`Updating ${campaignUpdates.length} campaigns with correct minister info...`);
console.log('='.repeat(60));
let successCount = 0;
let failCount = 0;
let notFoundCount = 0;
for (const update of campaignUpdates) {
try {
const campaign = await getCampaignBySlug(update.slug);
if (!campaign) {
console.log(`⚠ Not found: ${update.slug}`);
notFoundCount++;
continue;
}
const id = campaign.Id || campaign.ID || campaign.id;
await updateCampaign(id, { 'Call to Action': update.call_to_action });
console.log(`✓ Updated: ${update.slug} → "${update.call_to_action}"`);
successCount++;
// Small delay
await new Promise(resolve => setTimeout(resolve, 100));
} catch (error) {
console.error(`✗ Failed: ${update.slug} - ${error.message}`);
failCount++;
}
}
console.log('='.repeat(60));
console.log(`Done! Updated: ${successCount}, Failed: ${failCount}, Not found: ${notFoundCount}`);
}
main().catch(console.error);