mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 07:11:12 -05:00
feat: Implement test data generation improvements
This commit is contained in:
@@ -8,11 +8,12 @@ const corsHeaders = {
|
||||
interface SeedOptions {
|
||||
preset: 'small' | 'medium' | 'large' | 'stress';
|
||||
entityTypes: string[];
|
||||
includeDependencies: boolean;
|
||||
includeConflicts: boolean;
|
||||
includeVersionChains: boolean;
|
||||
includeEscalated: boolean;
|
||||
includeExpiredLocks: boolean;
|
||||
fieldDensity?: 'mixed' | 'minimal' | 'standard' | 'maximum';
|
||||
includeDependencies?: boolean;
|
||||
includeConflicts?: boolean;
|
||||
includeVersionChains?: boolean;
|
||||
includeEscalated?: boolean;
|
||||
includeExpiredLocks?: boolean;
|
||||
}
|
||||
|
||||
interface SeedPlan {
|
||||
@@ -20,33 +21,65 @@ interface SeedPlan {
|
||||
rides: number;
|
||||
companies: number;
|
||||
rideModels: number;
|
||||
photos: number;
|
||||
}
|
||||
|
||||
const PRESETS: Record<string, SeedPlan> = {
|
||||
small: { parks: 5, rides: 10, companies: 3, rideModels: 2 },
|
||||
medium: { parks: 20, rides: 50, companies: 20, rideModels: 10 },
|
||||
large: { parks: 100, rides: 250, companies: 100, rideModels: 50 },
|
||||
stress: { parks: 400, rides: 1000, companies: 400, rideModels: 200 }
|
||||
small: { parks: 5, rides: 10, companies: 3, rideModels: 2, photos: 5 },
|
||||
medium: { parks: 20, rides: 50, companies: 20, rideModels: 10, photos: 25 },
|
||||
large: { parks: 100, rides: 250, companies: 100, rideModels: 50, photos: 100 },
|
||||
stress: { parks: 400, rides: 1000, companies: 400, rideModels: 200, photos: 500 }
|
||||
};
|
||||
|
||||
const CITIES = [
|
||||
{ city: 'Orlando', state: 'Florida', country: 'USA' },
|
||||
{ city: 'Anaheim', state: 'California', country: 'USA' },
|
||||
{ city: 'Paris', state: 'Île-de-France', country: 'France' },
|
||||
{ city: 'Tokyo', state: 'Tokyo', country: 'Japan' },
|
||||
{ city: 'Berlin', state: 'Berlin', country: 'Germany' }
|
||||
];
|
||||
|
||||
// Helper functions
|
||||
function randomInt(min: number, max: number): number {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function randomItem<T>(array: T[]): T {
|
||||
return array[randomInt(0, array.length - 1)];
|
||||
}
|
||||
|
||||
function randomDate(startYear: number, endYear: number): string {
|
||||
const year = randomInt(startYear, endYear);
|
||||
const month = randomInt(1, 12);
|
||||
const day = randomInt(1, 28);
|
||||
return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
function getPopulationLevel(fieldDensity: string, index: number): number {
|
||||
if (fieldDensity === 'mixed') {
|
||||
const rand = Math.random();
|
||||
if (rand < 0.1) return 0; // 10% minimal
|
||||
if (rand < 0.3) return 1; // 20% basic
|
||||
if (rand < 0.7) return 2; // 40% standard
|
||||
if (rand < 0.9) return 3; // 20% complete
|
||||
return 4; // 10% maximum
|
||||
}
|
||||
if (fieldDensity === 'minimal') return 0;
|
||||
if (fieldDensity === 'standard') return 2;
|
||||
if (fieldDensity === 'maximum') return 4;
|
||||
return 2;
|
||||
}
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
if (req.method === 'OPTIONS') {
|
||||
return new Response(null, { headers: corsHeaders });
|
||||
}
|
||||
|
||||
try {
|
||||
// SECURITY: Service Role Key Usage
|
||||
// ---------------------------------
|
||||
// This function uses the service role key to seed test data bypassing RLS.
|
||||
// This is required because:
|
||||
// 1. Test data generation needs to create entities in protected tables
|
||||
// 2. Moderator role is verified via is_moderator() RPC call before proceeding
|
||||
// Scope: Limited to moderators only, for test/development purposes
|
||||
const supabaseUrl = Deno.env.get('SUPABASE_URL')!;
|
||||
const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!;
|
||||
const supabase = createClient(supabaseUrl, supabaseServiceKey);
|
||||
|
||||
// Get auth header
|
||||
const authHeader = req.headers.get('Authorization');
|
||||
if (!authHeader) {
|
||||
return new Response(JSON.stringify({ error: 'No authorization header' }), {
|
||||
@@ -55,7 +88,6 @@ Deno.serve(async (req) => {
|
||||
});
|
||||
}
|
||||
|
||||
// Verify user is moderator
|
||||
const token = authHeader.replace('Bearer ', '');
|
||||
const { data: { user }, error: userError } = await supabase.auth.getUser(token);
|
||||
|
||||
@@ -67,25 +99,25 @@ Deno.serve(async (req) => {
|
||||
}
|
||||
|
||||
const { data: isMod, error: modError } = await supabase.rpc('is_moderator', { _user_id: user.id });
|
||||
if (modError) {
|
||||
console.error('Failed to check moderator status:', modError);
|
||||
return new Response(JSON.stringify({ error: 'Failed to verify permissions' }), {
|
||||
status: 500,
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
|
||||
});
|
||||
}
|
||||
|
||||
if (!isMod) {
|
||||
if (modError || !isMod) {
|
||||
return new Response(JSON.stringify({ error: 'Insufficient permissions. Moderator role required.' }), {
|
||||
status: 403,
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
|
||||
});
|
||||
}
|
||||
|
||||
// Parse request
|
||||
const { preset = 'small', entityTypes = [], includeDependencies = true, includeConflicts = false, includeVersionChains = false, includeEscalated = false, includeExpiredLocks = false }: SeedOptions = await req.json();
|
||||
const {
|
||||
preset = 'small',
|
||||
entityTypes = [],
|
||||
fieldDensity = 'mixed',
|
||||
includeDependencies = true,
|
||||
includeConflicts = false,
|
||||
includeVersionChains = false,
|
||||
includeEscalated = false,
|
||||
includeExpiredLocks = false
|
||||
}: SeedOptions = await req.json();
|
||||
|
||||
const plan = PRESETS[preset];
|
||||
|
||||
if (!plan) {
|
||||
return new Response(JSON.stringify({ error: 'Invalid preset' }), {
|
||||
status: 400,
|
||||
@@ -94,7 +126,7 @@ Deno.serve(async (req) => {
|
||||
}
|
||||
|
||||
const startTime = Date.now();
|
||||
const summary = { parks: 0, rides: 0, companies: 0, rideModels: 0, conflicts: 0, versionChains: 0 };
|
||||
const summary = { parks: 0, rides: 0, companies: 0, rideModels: 0, photos: 0, totalPhotoItems: 0, conflicts: 0, versionChains: 0 };
|
||||
const createdParks: string[] = [];
|
||||
const createdCompanies: Record<string, string[]> = { manufacturer: [], operator: [], designer: [], property_owner: [] };
|
||||
const createdParkSlugs: string[] = [];
|
||||
@@ -102,11 +134,6 @@ Deno.serve(async (req) => {
|
||||
|
||||
// Helper to create submission
|
||||
async function createSubmission(userId: string, type: string, itemData: any, options: { escalated?: boolean; expiredLock?: boolean } = {}) {
|
||||
// Ensure crypto.randomUUID is available
|
||||
if (typeof crypto === 'undefined' || typeof crypto.randomUUID !== 'function') {
|
||||
throw new Error('crypto.randomUUID is not available in this environment');
|
||||
}
|
||||
|
||||
const submissionId = crypto.randomUUID();
|
||||
const itemId = crypto.randomUUID();
|
||||
|
||||
@@ -115,12 +142,12 @@ Deno.serve(async (req) => {
|
||||
metadata: {
|
||||
is_test_data: true,
|
||||
generated_at: new Date().toISOString(),
|
||||
generator_version: '1.0.0',
|
||||
preset
|
||||
generator_version: '2.0.0',
|
||||
preset,
|
||||
fieldDensity
|
||||
}
|
||||
};
|
||||
|
||||
// Create content_submission
|
||||
const submissionData: any = {
|
||||
id: submissionId,
|
||||
user_id: userId,
|
||||
@@ -128,40 +155,32 @@ Deno.serve(async (req) => {
|
||||
status: 'pending',
|
||||
content: contentData,
|
||||
submitted_at: new Date().toISOString(),
|
||||
priority: options.escalated ? 10 : Math.floor(Math.random() * 5) + 1
|
||||
priority: options.escalated ? 10 : randomInt(1, 5)
|
||||
};
|
||||
|
||||
if (options.escalated) {
|
||||
submissionData.escalated = true;
|
||||
submissionData.escalation_reason = 'Test escalation';
|
||||
submissionData.escalation_reason = 'Test escalation for priority testing';
|
||||
}
|
||||
|
||||
if (options.expiredLock) {
|
||||
submissionData.assigned_to = userId;
|
||||
submissionData.locked_until = new Date(Date.now() - 1000 * 60 * 30).toISOString(); // 30 min ago
|
||||
submissionData.locked_until = new Date(Date.now() - 1000 * 60 * 30).toISOString();
|
||||
}
|
||||
|
||||
const { error: subError } = await supabase
|
||||
.from('content_submissions')
|
||||
.insert(submissionData);
|
||||
|
||||
const { error: subError } = await supabase.from('content_submissions').insert(submissionData);
|
||||
if (subError) throw subError;
|
||||
|
||||
// Create submission_item
|
||||
const { error: itemError } = await supabase
|
||||
.from('submission_items')
|
||||
.insert({
|
||||
id: itemId,
|
||||
submission_id: submissionId,
|
||||
item_type: type,
|
||||
item_data: itemData,
|
||||
status: 'pending',
|
||||
order_index: 0
|
||||
});
|
||||
|
||||
const { error: itemError } = await supabase.from('submission_items').insert({
|
||||
id: itemId,
|
||||
submission_id: submissionId,
|
||||
item_type: type,
|
||||
item_data: itemData,
|
||||
status: 'pending',
|
||||
order_index: 0
|
||||
});
|
||||
if (itemError) throw itemError;
|
||||
|
||||
// Create type-specific submission record
|
||||
const typeTableMap: Record<string, string> = {
|
||||
park: 'park_submissions',
|
||||
ride: 'ride_submissions',
|
||||
@@ -179,43 +198,68 @@ Deno.serve(async (req) => {
|
||||
typeData.company_type = type;
|
||||
}
|
||||
|
||||
const { error: typeError } = await supabase
|
||||
.from(table)
|
||||
.insert(typeData);
|
||||
|
||||
const { data: insertedData, error: typeError } = await supabase.from(table).insert(typeData).select('id').single();
|
||||
if (typeError) throw typeError;
|
||||
return { submissionId, typeId: insertedData?.id };
|
||||
}
|
||||
|
||||
return submissionId;
|
||||
return { submissionId, typeId: null };
|
||||
}
|
||||
|
||||
// Create parks
|
||||
if (entityTypes.includes('parks')) {
|
||||
for (let i = 0; i < plan.parks; i++) {
|
||||
// Determine if this should be a conflict or version chain
|
||||
const level = getPopulationLevel(fieldDensity, i);
|
||||
const shouldConflict = includeConflicts && createdParkSlugs.length > 0 && Math.random() < 0.15;
|
||||
const shouldVersionChain = includeVersionChains && createdParkSlugs.length > 0 && Math.random() < 0.15;
|
||||
|
||||
let slug = `test-park-${i + 1}`;
|
||||
if (shouldConflict) {
|
||||
// Reuse an existing slug to create a conflict
|
||||
slug = createdParkSlugs[Math.floor(Math.random() * createdParkSlugs.length)];
|
||||
slug = randomItem(createdParkSlugs);
|
||||
summary.conflicts++;
|
||||
} else if (shouldVersionChain) {
|
||||
// Reuse an existing slug for a version chain with different data
|
||||
slug = createdParkSlugs[Math.floor(Math.random() * createdParkSlugs.length)];
|
||||
slug = randomItem(createdParkSlugs);
|
||||
summary.versionChains++;
|
||||
}
|
||||
|
||||
const parkData = {
|
||||
const parkData: any = {
|
||||
name: shouldVersionChain ? `Test Park ${slug} (Updated)` : `Test Park ${i + 1}`,
|
||||
slug: slug,
|
||||
description: shouldVersionChain ? 'Updated test park description' : 'Test park description',
|
||||
park_type: ['theme_park', 'amusement_park', 'water_park'][Math.floor(Math.random() * 3)],
|
||||
status: 'operating',
|
||||
opening_date: '2000-01-01'
|
||||
park_type: randomItem(['theme_park', 'amusement_park', 'water_park']),
|
||||
status: 'operating'
|
||||
};
|
||||
|
||||
if (level >= 1) {
|
||||
parkData.opening_date = randomDate(1950, 2024);
|
||||
parkData.description = `A ${parkData.park_type === 'theme_park' ? 'themed' : 'exciting'} park for all ages with various attractions.`;
|
||||
}
|
||||
|
||||
if (level >= 2) {
|
||||
parkData.website_url = `https://test-park-${i + 1}.example.com`;
|
||||
parkData.phone = `+1-555-${randomInt(100, 999)}-${randomInt(1000, 9999)}`;
|
||||
}
|
||||
|
||||
if (level >= 3 && createdCompanies.operator.length > 0) {
|
||||
const { data: operatorData } = await supabase.from('companies').select('id').eq('slug', randomItem(createdCompanies.operator)).maybeSingle();
|
||||
if (operatorData) parkData.operator_id = operatorData.id;
|
||||
parkData.email = `info@test-park-${i + 1}.example.com`;
|
||||
parkData.card_image_id = `test-park-card-${i + 1}`;
|
||||
parkData.card_image_url = `https://imagedelivery.net/test/park-${i + 1}/card`;
|
||||
}
|
||||
|
||||
if (level >= 4) {
|
||||
if (createdCompanies.property_owner.length > 0) {
|
||||
const { data: ownerData } = await supabase.from('companies').select('id').eq('slug', randomItem(createdCompanies.property_owner)).maybeSingle();
|
||||
if (ownerData) parkData.property_owner_id = ownerData.id;
|
||||
}
|
||||
if (Math.random() > 0.9) {
|
||||
parkData.closing_date = randomDate(2000, 2024);
|
||||
parkData.status = 'closed';
|
||||
}
|
||||
parkData.banner_image_id = `test-park-banner-${i + 1}`;
|
||||
parkData.banner_image_url = `https://imagedelivery.net/test/park-${i + 1}/banner`;
|
||||
}
|
||||
|
||||
const options = {
|
||||
escalated: includeEscalated && Math.random() < 0.1,
|
||||
expiredLock: includeExpiredLocks && Math.random() < 0.1
|
||||
@@ -233,18 +277,39 @@ Deno.serve(async (req) => {
|
||||
// Create companies
|
||||
const companyTypes = ['manufacturer', 'operator', 'designer', 'property_owner'];
|
||||
for (const compType of companyTypes) {
|
||||
if (entityTypes.includes(compType)) {
|
||||
if (entityTypes.includes(compType + 's') || entityTypes.includes(compType === 'manufacturer' ? 'manufacturers' : compType === 'property_owner' ? 'property_owners' : compType + 's')) {
|
||||
const count = Math.floor(plan.companies / 4);
|
||||
for (let i = 0; i < count; i++) {
|
||||
const companyData = {
|
||||
name: `Test ${compType} ${i + 1}`,
|
||||
const level = getPopulationLevel(fieldDensity, i);
|
||||
const companyData: any = {
|
||||
name: `Test ${compType.replace('_', ' ')} ${i + 1}`,
|
||||
slug: `test-${compType}-${i + 1}`,
|
||||
description: `Test ${compType} description`,
|
||||
company_type: compType,
|
||||
person_type: 'company',
|
||||
founded_year: 2000
|
||||
company_type: compType
|
||||
};
|
||||
|
||||
if (level >= 1) {
|
||||
companyData.description = `Leading ${compType.replace('_', ' ')} in the amusement industry.`;
|
||||
companyData.person_type = compType === 'designer' && Math.random() > 0.5 ? 'individual' : 'company';
|
||||
}
|
||||
|
||||
if (level >= 2) {
|
||||
companyData.founded_year = randomInt(1950, 2020);
|
||||
const location = randomItem(CITIES);
|
||||
companyData.headquarters_location = `${location.city}, ${location.country}`;
|
||||
}
|
||||
|
||||
if (level >= 3) {
|
||||
companyData.website_url = `https://test-${compType}-${i + 1}.example.com`;
|
||||
companyData.logo_url = `https://imagedelivery.net/test/${compType}-${i + 1}/logo`;
|
||||
}
|
||||
|
||||
if (level >= 4) {
|
||||
companyData.card_image_id = `test-${compType}-card-${i + 1}`;
|
||||
companyData.card_image_url = `https://imagedelivery.net/test/${compType}-${i + 1}/card`;
|
||||
companyData.banner_image_id = `test-${compType}-banner-${i + 1}`;
|
||||
companyData.banner_image_url = `https://imagedelivery.net/test/${compType}-${i + 1}/banner`;
|
||||
}
|
||||
|
||||
await createSubmission(user.id, compType, companyData);
|
||||
createdCompanies[compType].push(`test-${compType}-${i + 1}`);
|
||||
summary.companies++;
|
||||
@@ -252,41 +317,112 @@ Deno.serve(async (req) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Create rides (with dependencies if enabled)
|
||||
// Create rides
|
||||
if (entityTypes.includes('rides') && includeDependencies && createdParks.length > 0) {
|
||||
for (let i = 0; i < plan.rides; i++) {
|
||||
// Determine if this should be a conflict or version chain
|
||||
const level = getPopulationLevel(fieldDensity, i);
|
||||
const shouldConflict = includeConflicts && createdRideSlugs.length > 0 && Math.random() < 0.15;
|
||||
const shouldVersionChain = includeVersionChains && createdRideSlugs.length > 0 && Math.random() < 0.15;
|
||||
|
||||
let slug = `test-ride-${i + 1}`;
|
||||
if (shouldConflict) {
|
||||
slug = createdRideSlugs[Math.floor(Math.random() * createdRideSlugs.length)];
|
||||
slug = randomItem(createdRideSlugs);
|
||||
summary.conflicts++;
|
||||
} else if (shouldVersionChain) {
|
||||
slug = createdRideSlugs[Math.floor(Math.random() * createdRideSlugs.length)];
|
||||
slug = randomItem(createdRideSlugs);
|
||||
summary.versionChains++;
|
||||
}
|
||||
|
||||
// Get random park ID from database
|
||||
const parkSlug = createdParks[Math.floor(Math.random() * createdParks.length)];
|
||||
const { data: parkData } = await supabase
|
||||
.from('parks')
|
||||
.select('id')
|
||||
.eq('slug', parkSlug)
|
||||
.maybeSingle();
|
||||
const parkSlug = randomItem(createdParks);
|
||||
const { data: parkData } = await supabase.from('parks').select('id').eq('slug', parkSlug).maybeSingle();
|
||||
|
||||
const rideData = {
|
||||
const category = randomItem(['roller_coaster', 'flat_ride', 'water_ride', 'dark_ride']);
|
||||
const rideData: any = {
|
||||
name: shouldVersionChain ? `Test Ride ${slug} (Updated)` : `Test Ride ${i + 1}`,
|
||||
slug: slug,
|
||||
description: shouldVersionChain ? 'Updated test ride description' : 'Test ride description',
|
||||
category: ['roller_coaster', 'flat_ride', 'water_ride'][Math.floor(Math.random() * 3)],
|
||||
category: category,
|
||||
status: 'operating',
|
||||
park_id: parkData?.id || null,
|
||||
opening_date: '2010-01-01'
|
||||
park_id: parkData?.id || null
|
||||
};
|
||||
|
||||
await createSubmission(user.id, 'ride', rideData);
|
||||
if (level >= 1) {
|
||||
rideData.opening_date = randomDate(2000, 2024);
|
||||
rideData.description = `An exciting ${category.replace('_', ' ')} attraction.`;
|
||||
rideData.height_requirement = randomInt(100, 140);
|
||||
}
|
||||
|
||||
if (level >= 2) {
|
||||
rideData.max_speed_kmh = randomInt(40, 120);
|
||||
rideData.max_height_meters = randomInt(20, 100);
|
||||
rideData.duration_seconds = randomInt(60, 240);
|
||||
rideData.capacity_per_hour = randomInt(500, 2000);
|
||||
rideData.intensity_level = randomItem(['family', 'moderate', 'high', 'extreme']);
|
||||
}
|
||||
|
||||
if (level >= 3) {
|
||||
if (createdCompanies.manufacturer.length > 0) {
|
||||
const { data: mfgData } = await supabase.from('companies').select('id').eq('slug', randomItem(createdCompanies.manufacturer)).maybeSingle();
|
||||
if (mfgData) rideData.manufacturer_id = mfgData.id;
|
||||
}
|
||||
if (category === 'roller_coaster') {
|
||||
rideData.inversions = randomInt(0, 7);
|
||||
rideData.coaster_type = randomItem(['steel', 'wooden', 'hybrid']);
|
||||
rideData.seating_type = randomItem(['sit_down', 'inverted', 'flying', 'stand_up']);
|
||||
}
|
||||
rideData.card_image_id = `test-ride-card-${i + 1}`;
|
||||
rideData.card_image_url = `https://imagedelivery.net/test/ride-${i + 1}/card`;
|
||||
}
|
||||
|
||||
if (level >= 4) {
|
||||
if (createdCompanies.designer.length > 0) {
|
||||
const { data: designerData } = await supabase.from('companies').select('id').eq('slug', randomItem(createdCompanies.designer)).maybeSingle();
|
||||
if (designerData) rideData.designer_id = designerData.id;
|
||||
}
|
||||
rideData.length_meters = randomInt(500, 2000);
|
||||
rideData.drop_height_meters = randomInt(10, 80);
|
||||
rideData.max_g_force = (Math.random() * 4 + 2).toFixed(1);
|
||||
rideData.banner_image_id = `test-ride-banner-${i + 1}`;
|
||||
rideData.banner_image_url = `https://imagedelivery.net/test/ride-${i + 1}/banner`;
|
||||
}
|
||||
|
||||
const { submissionId, typeId } = await createSubmission(user.id, 'ride', rideData);
|
||||
|
||||
// Add technical specs and stats for level 4
|
||||
if (level >= 4 && typeId && category === 'roller_coaster') {
|
||||
// Add coaster stats
|
||||
for (let s = 0; s < randomInt(2, 3); s++) {
|
||||
await supabase.from('ride_submission_coaster_statistics').insert({
|
||||
ride_submission_id: typeId,
|
||||
stat_name: randomItem(['Airtime Duration', 'Zero-G Time', 'Track Gauge']),
|
||||
stat_value: Math.random() * 100,
|
||||
unit: randomItem(['seconds', 'mm']),
|
||||
category: 'technical'
|
||||
});
|
||||
}
|
||||
|
||||
// Add technical specs
|
||||
for (let t = 0; t < randomInt(3, 5); t++) {
|
||||
await supabase.from('ride_submission_technical_specifications').insert({
|
||||
ride_submission_id: typeId,
|
||||
spec_name: randomItem(['Lift System', 'Brake System', 'Train Count', 'Track Material']),
|
||||
spec_value: randomItem(['Chain lift', 'Magnetic brakes', '3 trains', 'Steel tubular']),
|
||||
spec_type: 'system',
|
||||
display_order: t
|
||||
});
|
||||
}
|
||||
|
||||
// Add former name
|
||||
if (Math.random() > 0.7) {
|
||||
await supabase.from('ride_submission_name_history').insert({
|
||||
ride_submission_id: typeId,
|
||||
former_name: `Original Name ${i + 1}`,
|
||||
date_changed: randomDate(2010, 2020),
|
||||
reason: 'Rebranding',
|
||||
order_index: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldConflict && !shouldVersionChain) {
|
||||
createdRideSlugs.push(slug);
|
||||
}
|
||||
@@ -297,43 +433,128 @@ Deno.serve(async (req) => {
|
||||
// Create ride models
|
||||
if (entityTypes.includes('ride_models') && includeDependencies && createdCompanies.manufacturer.length > 0) {
|
||||
for (let i = 0; i < plan.rideModels; i++) {
|
||||
const mfgSlug = createdCompanies.manufacturer[Math.floor(Math.random() * createdCompanies.manufacturer.length)];
|
||||
const { data: mfgData } = await supabase
|
||||
.from('companies')
|
||||
.select('id')
|
||||
.eq('slug', mfgSlug)
|
||||
.maybeSingle();
|
||||
const level = getPopulationLevel(fieldDensity, i);
|
||||
const { data: mfgData } = await supabase.from('companies').select('id').eq('slug', randomItem(createdCompanies.manufacturer)).maybeSingle();
|
||||
|
||||
const modelData = {
|
||||
const category = randomItem(['roller_coaster', 'flat_ride', 'water_ride']);
|
||||
const modelData: any = {
|
||||
name: `Test Model ${i + 1}`,
|
||||
slug: `test-model-${i + 1}`,
|
||||
manufacturer_id: mfgData?.id || null,
|
||||
category: 'roller_coaster',
|
||||
ride_type: 'steel',
|
||||
description: 'Test ride model'
|
||||
category: category,
|
||||
manufacturer_id: mfgData?.id || null
|
||||
};
|
||||
|
||||
if (level >= 1) {
|
||||
modelData.description = `Popular ${category.replace('_', ' ')} model.`;
|
||||
modelData.ride_type = randomItem(['spinning', 'launch', 'suspended', 'family']);
|
||||
}
|
||||
|
||||
if (level >= 2) {
|
||||
modelData.card_image_id = `test-model-card-${i + 1}`;
|
||||
modelData.card_image_url = `https://imagedelivery.net/test/model-${i + 1}/card`;
|
||||
}
|
||||
|
||||
if (level >= 3) {
|
||||
modelData.banner_image_id = `test-model-banner-${i + 1}`;
|
||||
modelData.banner_image_url = `https://imagedelivery.net/test/model-${i + 1}/banner`;
|
||||
}
|
||||
|
||||
await createSubmission(user.id, 'ride_model', modelData);
|
||||
summary.rideModels++;
|
||||
}
|
||||
}
|
||||
|
||||
const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(2);
|
||||
// Create photo submissions
|
||||
if (entityTypes.includes('photos') && plan.photos > 0) {
|
||||
const { data: approvedParks } = await supabase.from('parks').select('id').limit(Math.min(20, plan.photos));
|
||||
const { data: approvedRides } = await supabase.from('rides').select('id, park_id').limit(Math.min(20, plan.photos));
|
||||
|
||||
for (let i = 0; i < plan.photos; i++) {
|
||||
const photoCount = randomInt(1, Math.min(10, Math.ceil(plan.photos / 50) + 3));
|
||||
const submissionId = crypto.randomUUID();
|
||||
const photoSubmissionId = crypto.randomUUID();
|
||||
|
||||
let entityType = 'park';
|
||||
let entityId = null;
|
||||
let parentId = null;
|
||||
|
||||
if (Math.random() > 0.5 && approvedParks && approvedParks.length > 0) {
|
||||
entityType = 'park';
|
||||
entityId = randomItem(approvedParks).id;
|
||||
} else if (approvedRides && approvedRides.length > 0) {
|
||||
entityType = 'ride';
|
||||
const ride = randomItem(approvedRides);
|
||||
entityId = ride.id;
|
||||
parentId = ride.park_id;
|
||||
}
|
||||
|
||||
if (!entityId) continue;
|
||||
|
||||
// Create content_submission
|
||||
await supabase.from('content_submissions').insert({
|
||||
id: submissionId,
|
||||
user_id: user.id,
|
||||
submission_type: 'photo',
|
||||
status: 'pending',
|
||||
content: {
|
||||
action: 'create',
|
||||
metadata: {
|
||||
is_test_data: true,
|
||||
generated_at: new Date().toISOString(),
|
||||
generator_version: '2.0.0',
|
||||
preset
|
||||
}
|
||||
},
|
||||
submitted_at: new Date().toISOString()
|
||||
});
|
||||
|
||||
// Create photo_submission
|
||||
await supabase.from('photo_submissions').insert({
|
||||
id: photoSubmissionId,
|
||||
submission_id: submissionId,
|
||||
entity_type: entityType,
|
||||
entity_id: entityId,
|
||||
parent_id: parentId,
|
||||
title: Math.random() > 0.5 ? `${entityType} Photos Collection ${i + 1}` : null
|
||||
});
|
||||
|
||||
// Create photo_submission_items
|
||||
for (let p = 0; p < photoCount; p++) {
|
||||
const imageId = `test-photo-${crypto.randomUUID()}`;
|
||||
await supabase.from('photo_submission_items').insert({
|
||||
photo_submission_id: photoSubmissionId,
|
||||
cloudflare_image_id: imageId,
|
||||
cloudflare_image_url: `https://imagedelivery.net/test/${imageId}/public`,
|
||||
caption: Math.random() > 0.3 ? `Test photo ${p + 1} - Great view of the ${entityType}` : null,
|
||||
title: Math.random() > 0.7 ? `Photo ${p + 1}` : null,
|
||||
filename: `photo-${p + 1}.jpg`,
|
||||
order_index: p,
|
||||
file_size: randomInt(500000, 5000000),
|
||||
mime_type: 'image/jpeg',
|
||||
date_taken: Math.random() > 0.5 ? randomDate(2015, 2024) : null
|
||||
});
|
||||
summary.totalPhotoItems++;
|
||||
}
|
||||
|
||||
summary.photos++;
|
||||
}
|
||||
}
|
||||
|
||||
const executionTime = Date.now() - startTime;
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
summary,
|
||||
time: elapsedTime
|
||||
time: (executionTime / 1000).toFixed(2)
|
||||
}),
|
||||
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Seed error:', error);
|
||||
const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred';
|
||||
return new Response(
|
||||
JSON.stringify({ error: errorMessage }),
|
||||
JSON.stringify({ error: error.message }),
|
||||
{ status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user