RLS policies implementeren, Demo auth flow
This commit is contained in:
63
scripts/check-demo-users.ts
Normal file
63
scripts/check-demo-users.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Check Demo Users Script
|
||||
* Verify that demo users exist and are properly configured
|
||||
*/
|
||||
|
||||
import { config } from 'dotenv'
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import type { Database } from '@/lib/database.types'
|
||||
|
||||
config({ path: '.env.local' })
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || ''
|
||||
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY || ''
|
||||
|
||||
const supabase = createClient<Database>(supabaseUrl, supabaseServiceKey)
|
||||
|
||||
async function checkDemoUsers() {
|
||||
console.log('🔍 Checking demo users...\n')
|
||||
|
||||
// Check demo_users table
|
||||
const { data, error } = await supabase
|
||||
.from('demo_users')
|
||||
.select('*')
|
||||
.order('created_at')
|
||||
|
||||
if (error) {
|
||||
console.error('❌ Error:', error.message)
|
||||
return
|
||||
}
|
||||
|
||||
console.log(`✅ Found ${data.length} demo users in database:\n`)
|
||||
|
||||
data.forEach((user, index) => {
|
||||
console.log(`${index + 1}. Demo User`)
|
||||
console.log(` User ID: ${user.user_id}`)
|
||||
console.log(` Access Level: ${user.access_level}`)
|
||||
console.log(` Notes: ${user.notes}`)
|
||||
console.log(` Expires: ${user.expires_at || 'Never'}`)
|
||||
console.log(` Usage Count: ${user.usage_count}`)
|
||||
console.log('')
|
||||
})
|
||||
|
||||
// Also check auth.users (need to match emails)
|
||||
const { data: authUsers } = await supabase.auth.admin.listUsers()
|
||||
const demoEmails = authUsers.users
|
||||
.filter(u => u.email?.includes('mini-ecd.demo'))
|
||||
.map(u => ({ email: u.email, id: u.id }))
|
||||
|
||||
console.log('📧 Demo emails in auth.users:')
|
||||
demoEmails.forEach(u => {
|
||||
console.log(` ${u.email} (${u.id})`)
|
||||
})
|
||||
}
|
||||
|
||||
checkDemoUsers()
|
||||
.then(() => {
|
||||
console.log('\n✨ Done!')
|
||||
process.exit(0)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('💥 Error:', error)
|
||||
process.exit(1)
|
||||
})
|
||||
82
scripts/run-migration.ts
Normal file
82
scripts/run-migration.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Run Supabase Migration
|
||||
*
|
||||
* This script executes pending migrations on the Supabase database.
|
||||
* Run with: npx tsx scripts/run-migration.ts
|
||||
*/
|
||||
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
|
||||
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY!
|
||||
|
||||
if (!supabaseUrl || !supabaseServiceKey) {
|
||||
console.error('❌ Missing Supabase credentials')
|
||||
console.error('Make sure NEXT_PUBLIC_SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY are set in .env.local')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const supabase = createClient(supabaseUrl, supabaseServiceKey)
|
||||
|
||||
async function runMigrations() {
|
||||
console.log('🚀 Starting migrations...\n')
|
||||
|
||||
const migrationsDir = path.join(process.cwd(), 'supabase', 'migrations')
|
||||
const files = fs.readdirSync(migrationsDir).filter(f => f.endsWith('.sql')).sort()
|
||||
|
||||
if (files.length === 0) {
|
||||
console.log('ℹ️ No migration files found')
|
||||
return
|
||||
}
|
||||
|
||||
console.log(`Found ${files.length} migration(s):\n`)
|
||||
|
||||
for (const file of files) {
|
||||
const filePath = path.join(migrationsDir, file)
|
||||
const sql = fs.readFileSync(filePath, 'utf-8')
|
||||
|
||||
console.log(`⏳ Running: ${file}`)
|
||||
|
||||
try {
|
||||
const { error } = await supabase.rpc('exec_sql', { sql })
|
||||
|
||||
if (error) {
|
||||
// Try direct query if RPC doesn't exist
|
||||
const lines = sql.split(';').filter(line => line.trim())
|
||||
|
||||
for (const line of lines) {
|
||||
if (!line.trim()) continue
|
||||
|
||||
const { error: queryError } = await supabase.from('_migrations').select('*').limit(0)
|
||||
|
||||
if (queryError) {
|
||||
// Fallback: manual execution needed
|
||||
console.error(`❌ Error executing ${file}:`, error.message)
|
||||
console.log('\n📋 Please execute this migration manually in Supabase dashboard:')
|
||||
console.log(`\nFile: ${file}`)
|
||||
console.log('Navigate to: https://supabase.com/dashboard/project/dqugbrpwtisgyxscpefg/sql')
|
||||
console.log('\nOr copy the SQL from:')
|
||||
console.log(filePath)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ Success: ${file}\n`)
|
||||
} catch (err) {
|
||||
console.error(`❌ Failed: ${file}`)
|
||||
console.error(err)
|
||||
console.log('\n📋 Manual execution required.')
|
||||
console.log(`Navigate to: https://supabase.com/dashboard/project/dqugbrpwtisgyxscpefg/sql`)
|
||||
console.log(`\nCopy and paste the SQL from: ${filePath}`)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✨ All migrations completed!\n')
|
||||
}
|
||||
|
||||
// Run migrations
|
||||
runMigrations().catch(console.error)
|
||||
158
scripts/seed-demo-users.ts
Normal file
158
scripts/seed-demo-users.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* Seed Demo Users Script
|
||||
*
|
||||
* Creates demo user accounts in Supabase Auth
|
||||
* Run this script once after deployment to set up demo accounts
|
||||
*
|
||||
* Usage:
|
||||
* tsx scripts/seed-demo-users.ts
|
||||
*/
|
||||
|
||||
import { config } from 'dotenv'
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import type { Database } from '@/lib/database.types'
|
||||
|
||||
// Load environment variables from .env.local
|
||||
config({ path: '.env.local' })
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
|
||||
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY!
|
||||
|
||||
if (!supabaseUrl || !supabaseServiceKey) {
|
||||
console.error('❌ Missing environment variables!')
|
||||
console.error('Required: NEXT_PUBLIC_SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Create Supabase client with service role (bypasses RLS)
|
||||
const supabase = createClient<Database>(supabaseUrl, supabaseServiceKey, {
|
||||
auth: {
|
||||
autoRefreshToken: false,
|
||||
persistSession: false
|
||||
}
|
||||
})
|
||||
|
||||
// Demo users to create
|
||||
const demoUsers = [
|
||||
{
|
||||
email: 'demo@mini-ecd.demo',
|
||||
password: 'Demo2024!',
|
||||
access_level: 'interactive' as const,
|
||||
notes: 'Main interactive demo account - full CRUD access for presentations'
|
||||
},
|
||||
{
|
||||
email: 'readonly@mini-ecd.demo',
|
||||
password: 'Demo2024!',
|
||||
access_level: 'read_only' as const,
|
||||
notes: 'Read-only demo account - view only access for public demos'
|
||||
},
|
||||
{
|
||||
email: 'presenter@mini-ecd.demo',
|
||||
password: 'Demo2024!',
|
||||
access_level: 'presenter' as const,
|
||||
notes: 'Presenter account for live demo sessions with special features'
|
||||
}
|
||||
]
|
||||
|
||||
async function seedDemoUsers() {
|
||||
console.log('🌱 Starting demo user seed...\n')
|
||||
|
||||
for (const user of demoUsers) {
|
||||
console.log(`Creating user: ${user.email}...`)
|
||||
|
||||
try {
|
||||
// Step 1: Create auth user
|
||||
const { data: authData, error: authError } = await supabase.auth.admin.createUser({
|
||||
email: user.email,
|
||||
password: user.password,
|
||||
email_confirm: true, // Auto-confirm email
|
||||
user_metadata: {
|
||||
access_level: user.access_level,
|
||||
is_demo: true
|
||||
}
|
||||
})
|
||||
|
||||
if (authError) {
|
||||
// Check if user already exists
|
||||
if (authError.message.includes('already registered')) {
|
||||
console.log(` ℹ️ User already exists, fetching existing user...`)
|
||||
|
||||
// Get existing user
|
||||
const { data: existingUsers } = await supabase.auth.admin.listUsers()
|
||||
const existingUser = existingUsers.users.find(u => u.email === user.email)
|
||||
|
||||
if (!existingUser) {
|
||||
throw new Error('User exists but cannot be found')
|
||||
}
|
||||
|
||||
// Step 2: Upsert to demo_users table
|
||||
const { error: demoError } = await supabase
|
||||
.from('demo_users')
|
||||
.upsert({
|
||||
user_id: existingUser.id,
|
||||
access_level: user.access_level,
|
||||
notes: user.notes,
|
||||
expires_at: null, // No expiration for main demo accounts
|
||||
usage_count: 0
|
||||
}, {
|
||||
onConflict: 'user_id'
|
||||
})
|
||||
|
||||
if (demoError) throw demoError
|
||||
|
||||
console.log(` ✅ Updated demo_users entry for ${user.email}`)
|
||||
} else {
|
||||
throw authError
|
||||
}
|
||||
} else {
|
||||
console.log(` ✅ Created auth user: ${authData.user.id}`)
|
||||
|
||||
// Step 2: Insert into demo_users table
|
||||
const { error: demoError } = await supabase
|
||||
.from('demo_users')
|
||||
.insert({
|
||||
user_id: authData.user.id,
|
||||
access_level: user.access_level,
|
||||
notes: user.notes,
|
||||
expires_at: null, // No expiration for main demo accounts
|
||||
usage_count: 0
|
||||
})
|
||||
|
||||
if (demoError) {
|
||||
// Cleanup auth user if demo_users insert fails
|
||||
await supabase.auth.admin.deleteUser(authData.user.id)
|
||||
throw demoError
|
||||
}
|
||||
|
||||
console.log(` ✅ Created demo_users entry`)
|
||||
}
|
||||
|
||||
console.log(` ✨ ${user.email} ready!\n`)
|
||||
|
||||
} catch (error: any) {
|
||||
console.error(` ❌ Failed to create ${user.email}:`, error.message)
|
||||
console.error('')
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✅ Demo user seed complete!\n')
|
||||
console.log('📋 Demo Credentials:')
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
|
||||
demoUsers.forEach(user => {
|
||||
console.log(`Email: ${user.email}`)
|
||||
console.log(`Password: ${user.password}`)
|
||||
console.log(`Access: ${user.access_level}`)
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
|
||||
})
|
||||
}
|
||||
|
||||
// Run the seed
|
||||
seedDemoUsers()
|
||||
.then(() => {
|
||||
console.log('✨ Done!')
|
||||
process.exit(0)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('💥 Fatal error:', error)
|
||||
process.exit(1)
|
||||
})
|
||||
Reference in New Issue
Block a user