feat: add test accounts and secure event slugs
Security improvements: - Add @default(cuid()) to Event.slug for auto-generated random slugs - Prevent ID enumeration attacks (no more predictable slugs like "warsaw-dance-festival-2025") - Event slugs now generated as secure cuid strings (e.g., "cmhz3lcgb00018vbn34v4phoi") Test accounts: - Add 3 test users to seed (john_dancer, sarah_swings, mike_blues) - All users checked in to Warsaw Dance Festival 2025 - Pre-configured heats for testing matchmaking system - Full profiles with WSDC IDs, social media, and locations Seed improvements: - Add bcryptjs for password hashing - Add Prisma seed configuration to package.json - Use worldsdcId for event upsert (instead of slug) - Auto-generate event slugs via Prisma default Documentation: - Add test account credentials to SESSION_CONTEXT.md - Document event slug security model - Include sample heats for each test user
This commit is contained in:
@@ -1,10 +1,70 @@
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
const bcrypt = require('bcryptjs');
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('🌱 Seeding database...');
|
||||
|
||||
// Create test users
|
||||
const testUsers = await Promise.all([
|
||||
prisma.user.upsert({
|
||||
where: { email: 'john@example.com' },
|
||||
update: {},
|
||||
create: {
|
||||
username: 'john_dancer',
|
||||
email: 'john@example.com',
|
||||
passwordHash: await bcrypt.hash('Dance123!', 10),
|
||||
firstName: 'John',
|
||||
lastName: 'Smith',
|
||||
wsdcId: '12345',
|
||||
emailVerified: true,
|
||||
country: 'United States',
|
||||
city: 'Los Angeles',
|
||||
instagramUrl: 'https://instagram.com/johndancer',
|
||||
youtubeUrl: 'https://youtube.com/@johndancer',
|
||||
},
|
||||
}),
|
||||
prisma.user.upsert({
|
||||
where: { email: 'sarah@example.com' },
|
||||
update: {},
|
||||
create: {
|
||||
username: 'sarah_swings',
|
||||
email: 'sarah@example.com',
|
||||
passwordHash: await bcrypt.hash('Swing456!', 10),
|
||||
firstName: 'Sarah',
|
||||
lastName: 'Johnson',
|
||||
wsdcId: '23456',
|
||||
emailVerified: true,
|
||||
country: 'United Kingdom',
|
||||
city: 'London',
|
||||
tiktokUrl: 'https://tiktok.com/@sarahswings',
|
||||
facebookUrl: 'https://facebook.com/sarah.swings',
|
||||
},
|
||||
}),
|
||||
prisma.user.upsert({
|
||||
where: { email: 'mike@example.com' },
|
||||
update: {},
|
||||
create: {
|
||||
username: 'mike_blues',
|
||||
email: 'mike@example.com',
|
||||
passwordHash: await bcrypt.hash('Blues789!', 10),
|
||||
firstName: 'Mike',
|
||||
lastName: 'Williams',
|
||||
wsdcId: '34567',
|
||||
emailVerified: true,
|
||||
country: 'Sweden',
|
||||
city: 'Stockholm',
|
||||
instagramUrl: 'https://instagram.com/mikeblues',
|
||||
youtubeUrl: 'https://youtube.com/@mikeblues',
|
||||
tiktokUrl: 'https://tiktok.com/@mikeblues',
|
||||
facebookUrl: 'https://facebook.com/mike.blues',
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
console.log(`✅ Created ${testUsers.length} test users`);
|
||||
|
||||
// Create divisions
|
||||
const divisions = await Promise.all([
|
||||
prisma.division.upsert({
|
||||
@@ -57,13 +117,12 @@ async function main() {
|
||||
|
||||
console.log(`✅ Created ${competitionTypes.length} competition types`);
|
||||
|
||||
// Create events
|
||||
// Create events (slug will be auto-generated as cuid for security)
|
||||
const events = await Promise.all([
|
||||
prisma.event.upsert({
|
||||
where: { slug: 'warsaw-dance-festival-2025' },
|
||||
where: { worldsdcId: 'wdf-2025' },
|
||||
update: {},
|
||||
create: {
|
||||
slug: 'warsaw-dance-festival-2025',
|
||||
name: 'Warsaw Dance Festival 2025',
|
||||
location: 'Warsaw, Poland',
|
||||
startDate: new Date('2025-03-15'),
|
||||
@@ -74,10 +133,9 @@ async function main() {
|
||||
},
|
||||
}),
|
||||
prisma.event.upsert({
|
||||
where: { slug: 'swing-camp-barcelona-2025' },
|
||||
where: { worldsdcId: 'scb-2025' },
|
||||
update: {},
|
||||
create: {
|
||||
slug: 'swing-camp-barcelona-2025',
|
||||
name: 'Swing Camp Barcelona 2025',
|
||||
location: 'Barcelona, Spain',
|
||||
startDate: new Date('2025-04-20'),
|
||||
@@ -88,10 +146,9 @@ async function main() {
|
||||
},
|
||||
}),
|
||||
prisma.event.upsert({
|
||||
where: { slug: 'blues-week-herrang-2025' },
|
||||
where: { worldsdcId: 'bwh-2025' },
|
||||
update: {},
|
||||
create: {
|
||||
slug: 'blues-week-herrang-2025',
|
||||
name: 'Blues Week Herräng 2025',
|
||||
location: 'Herräng, Sweden',
|
||||
startDate: new Date('2025-07-14'),
|
||||
@@ -102,10 +159,9 @@ async function main() {
|
||||
},
|
||||
}),
|
||||
prisma.event.upsert({
|
||||
where: { slug: 'krakow-swing-connection-2025' },
|
||||
where: { worldsdcId: 'ksc-2025' },
|
||||
update: {},
|
||||
create: {
|
||||
slug: 'krakow-swing-connection-2025',
|
||||
name: 'Krakow Swing Connection 2025',
|
||||
location: 'Krakow, Poland',
|
||||
startDate: new Date('2025-05-10'),
|
||||
@@ -133,13 +189,161 @@ async function main() {
|
||||
|
||||
console.log(`✅ Created ${chatRooms.length} event chat rooms`);
|
||||
|
||||
// Add test users as event participants (check-in)
|
||||
const warsawEvent = events[0]; // Warsaw Dance Festival
|
||||
const barcelonaEvent = events[1]; // Swing Camp Barcelona
|
||||
|
||||
const eventParticipants = await Promise.all([
|
||||
// John participates in Warsaw
|
||||
prisma.eventParticipant.upsert({
|
||||
where: {
|
||||
userId_eventId: {
|
||||
userId: testUsers[0].id,
|
||||
eventId: warsawEvent.id,
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
userId: testUsers[0].id,
|
||||
eventId: warsawEvent.id,
|
||||
},
|
||||
}),
|
||||
// Sarah participates in Warsaw
|
||||
prisma.eventParticipant.upsert({
|
||||
where: {
|
||||
userId_eventId: {
|
||||
userId: testUsers[1].id,
|
||||
eventId: warsawEvent.id,
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
userId: testUsers[1].id,
|
||||
eventId: warsawEvent.id,
|
||||
},
|
||||
}),
|
||||
// Mike participates in Warsaw
|
||||
prisma.eventParticipant.upsert({
|
||||
where: {
|
||||
userId_eventId: {
|
||||
userId: testUsers[2].id,
|
||||
eventId: warsawEvent.id,
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
userId: testUsers[2].id,
|
||||
eventId: warsawEvent.id,
|
||||
},
|
||||
}),
|
||||
// John also in Barcelona
|
||||
prisma.eventParticipant.upsert({
|
||||
where: {
|
||||
userId_eventId: {
|
||||
userId: testUsers[0].id,
|
||||
eventId: barcelonaEvent.id,
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
userId: testUsers[0].id,
|
||||
eventId: barcelonaEvent.id,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
console.log(`✅ Added ${eventParticipants.length} event participants`);
|
||||
|
||||
// Create sample heats for test users in Warsaw event
|
||||
const jjType = competitionTypes[0]; // Jack & Jill
|
||||
const strType = competitionTypes[1]; // Strictly
|
||||
const novDiv = divisions[1]; // Novice
|
||||
const intDiv = divisions[2]; // Intermediate
|
||||
const advDiv = divisions[3]; // Advanced
|
||||
|
||||
const heats = await Promise.all([
|
||||
// John: J&J Novice Heat 1 (Leader), Strictly Intermediate Heat 2 (Leader)
|
||||
prisma.eventUserHeat.create({
|
||||
data: {
|
||||
userId: testUsers[0].id,
|
||||
eventId: warsawEvent.id,
|
||||
divisionId: novDiv.id,
|
||||
competitionTypeId: jjType.id,
|
||||
heatNumber: 1,
|
||||
role: 'Leader',
|
||||
},
|
||||
}),
|
||||
prisma.eventUserHeat.create({
|
||||
data: {
|
||||
userId: testUsers[0].id,
|
||||
eventId: warsawEvent.id,
|
||||
divisionId: intDiv.id,
|
||||
competitionTypeId: strType.id,
|
||||
heatNumber: 2,
|
||||
role: 'Leader',
|
||||
},
|
||||
}),
|
||||
// Sarah: J&J Novice Heat 1 (Follower), J&J Advanced Heat 3
|
||||
prisma.eventUserHeat.create({
|
||||
data: {
|
||||
userId: testUsers[1].id,
|
||||
eventId: warsawEvent.id,
|
||||
divisionId: novDiv.id,
|
||||
competitionTypeId: jjType.id,
|
||||
heatNumber: 1,
|
||||
role: 'Follower',
|
||||
},
|
||||
}),
|
||||
prisma.eventUserHeat.create({
|
||||
data: {
|
||||
userId: testUsers[1].id,
|
||||
eventId: warsawEvent.id,
|
||||
divisionId: advDiv.id,
|
||||
competitionTypeId: jjType.id,
|
||||
heatNumber: 3,
|
||||
role: null,
|
||||
},
|
||||
}),
|
||||
// Mike: J&J Intermediate Heat 5 (Leader), Strictly Advanced Heat 1 (Follower)
|
||||
prisma.eventUserHeat.create({
|
||||
data: {
|
||||
userId: testUsers[2].id,
|
||||
eventId: warsawEvent.id,
|
||||
divisionId: intDiv.id,
|
||||
competitionTypeId: jjType.id,
|
||||
heatNumber: 5,
|
||||
role: 'Leader',
|
||||
},
|
||||
}),
|
||||
prisma.eventUserHeat.create({
|
||||
data: {
|
||||
userId: testUsers[2].id,
|
||||
eventId: warsawEvent.id,
|
||||
divisionId: advDiv.id,
|
||||
competitionTypeId: strType.id,
|
||||
heatNumber: 1,
|
||||
role: 'Follower',
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
console.log(`✅ Created ${heats.length} sample heats`);
|
||||
|
||||
console.log('🎉 Seeding completed successfully!');
|
||||
console.log('');
|
||||
console.log('Created:');
|
||||
console.log(` - ${testUsers.length} test users`);
|
||||
console.log(` - ${divisions.length} divisions`);
|
||||
console.log(` - ${competitionTypes.length} competition types`);
|
||||
console.log(` - ${events.length} events`);
|
||||
console.log(` - ${chatRooms.length} chat rooms`);
|
||||
console.log(` - ${eventParticipants.length} event participants`);
|
||||
console.log(` - ${heats.length} sample heats`);
|
||||
console.log('');
|
||||
console.log('Test accounts:');
|
||||
console.log(' 1. john_dancer / Dance123!');
|
||||
console.log(' 2. sarah_swings / Swing456!');
|
||||
console.log(' 3. mike_blues / Blues789!');
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user