Files
hope-events/backend/scripts/seed-users.js
T
joshua 3d381944d2 Initial commit
Next.js + Express event management app for Hope Family Church.
2026-07-23 15:26:47 +02:00

134 lines
4.6 KiB
JavaScript

/**
* Seed script: inserts 75 demo users (mix of roles, ~25 inactive)
* Run: node scripts/seed-users.js
*/
const { PrismaClient } = require('@prisma/client');
const bcrypt = require('bcryptjs');
const prisma = new PrismaClient();
const firstNames = [
'Liam', 'Olivia', 'Noah', 'Emma', 'James', 'Ava', 'Elijah', 'Sophia',
'Lucas', 'Isabella', 'Mason', 'Mia', 'Logan', 'Charlotte', 'Ethan',
'Amelia', 'Aiden', 'Harper', 'Jackson', 'Evelyn', 'Thabo', 'Zanele',
'Sipho', 'Nomsa', 'Lebo', 'Thandeka', 'Kagiso', 'Palesa', 'Bongani',
'Ayanda', 'Pieter', 'Anri', 'Francois', 'Elizma', 'Hendrik', 'Marius',
'Chloé', 'Dylan', 'Amber', 'Caleb', 'Zoe', 'Hunter', 'Lily', 'Owen',
'Grace', 'Ryan', 'Chloe', 'Nathan', 'Stella', 'Connor', 'Hazel',
'Miles', 'Violet', 'Eli', 'Aurora', 'Isaiah', 'Luna', 'Nolan',
'Scarlett', 'Wyatt', 'Penelope', 'Sebastian', 'Layla', 'Asher',
'Riley', 'Oliver', 'Zoey', 'Ezra', 'Nora', 'Micah', 'Hannah',
'Jonah', 'Leah', 'Aaron', 'Aubrey', 'Charles',
];
const lastNames = [
'Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller',
'Davis', 'Wilson', 'Moore', 'Taylor', 'Anderson', 'Thomas', 'Jackson',
'White', 'Harris', 'Martin', 'Thompson', 'Robinson', 'Lewis',
'Dlamini', 'Nkosi', 'Mokoena', 'Ndlovu', 'Mthembu', 'Zulu', 'Nxumalo',
'du Plessis', 'van der Berg', 'Botha', 'Steyn', 'Fourie', 'Pretorius',
'Venter', 'Coetzee', 'van Niekerk', 'Lombard', 'Janse van Rensburg',
'Walker', 'Hall', 'Allen', 'Young', 'Hernandez', 'King', 'Wright',
'Scott', 'Green', 'Baker', 'Adams', 'Nelson', 'Carter', 'Mitchell',
'Perez', 'Roberts', 'Turner', 'Phillips', 'Campbell', 'Parker', 'Evans',
'Edwards', 'Collins', 'Stewart', 'Morris', 'Reed', 'Cook', 'Morgan',
];
function pick(arr) {
return arr[Math.floor(Math.random() * arr.length)];
}
function randomPhone() {
// SA mobile format: 07x/08x xxxxxxx
const prefixes = ['071', '072', '073', '074', '076', '078', '079', '081', '082', '083', '084'];
return `${pick(prefixes)}${String(Math.floor(Math.random() * 9000000) + 1000000)}`;
}
async function main() {
const passwordHash = await bcrypt.hash('Demo@1234', 10);
// Role distribution: ~55 user, ~15 staff, ~5 supervisor
const rolePool = [
...Array(55).fill('user'),
...Array(15).fill('staff'),
...Array(5).fill('supervisor'),
];
const notifPool = ['email', 'email', 'email', 'whatsapp', 'both'];
const usedEmails = new Set();
const usedPhones = new Set();
const users = [];
// Build 75 user records
while (users.length < 75) {
const first = pick(firstNames);
const last = pick(lastNames);
const tag = Math.floor(Math.random() * 999) + 1;
const email = `${first.toLowerCase().replace(/ /g, '')}.${last.toLowerCase().replace(/ /g, '').replace(/'/g, '')}${tag}@demo.church`;
if (usedEmails.has(email)) continue;
usedEmails.add(email);
// ~60% of users have a phone number
let phone = null;
if (Math.random() < 0.6) {
let attempt = randomPhone();
let tries = 0;
while (usedPhones.has(attempt) && tries < 20) {
attempt = randomPhone();
tries++;
}
if (!usedPhones.has(attempt)) {
usedPhones.add(attempt);
phone = attempt;
}
}
users.push({
name: `${first} ${last}`,
email,
password: passwordHash,
role: pick(rolePool),
isActive: true, // will override 25 below
phoneNumber: phone,
notificationPreference: pick(notifPool),
});
}
// Mark exactly 25 as inactive (spread across the list)
const inactiveIndexes = new Set();
while (inactiveIndexes.size < 25) {
inactiveIndexes.add(Math.floor(Math.random() * 75));
}
inactiveIndexes.forEach(i => { users[i].isActive = false; });
console.log(`Inserting ${users.length} users…`);
console.log(` Active: ${users.filter(u => u.isActive).length}`);
console.log(` Inactive: ${users.filter(u => !u.isActive).length}`);
console.log(` Roles: user=${users.filter(u => u.role === 'user').length}, staff=${users.filter(u => u.role === 'staff').length}, supervisor=${users.filter(u => u.role === 'supervisor').length}`);
let created = 0;
let skipped = 0;
for (const user of users) {
try {
await prisma.user.create({ data: user });
created++;
} catch (err) {
if (err.code === 'P2002') {
skipped++;
} else {
throw err;
}
}
}
console.log(`Done. Created: ${created}, Skipped (duplicate): ${skipped}`);
console.log('Default password for all demo users: Demo@1234');
}
main()
.catch(err => { console.error(err); process.exit(1); })
.finally(() => prisma.$disconnect());