const SUPABASE_URL = process.env.SUPABASE_URL || 'https://hwithddwaapyhnfwcesj.supabase.co'; const SUPABASE_SERVICE_KEY = process.env.SUPABASE_SERVICE_KEY; const SUPABASE_ANON_KEY = 'sb_publishable_fGXkh0bSrAOqSk2jWKAzSg_NJD9YPCv'; const ALLOWED_ORIGIN = 'https://craze-data-check.vercel.app'; const MASTER_USERS = new Set([ 'christian.vidal@craze-group.com', 'jingying.shi@craze-group.com', ]); function setCors(req, res) { const origin = req.headers.origin; if (origin === ALLOWED_ORIGIN || (origin && (origin.startsWith('http://localhost:') || origin.startsWith('http://127.0.0.1:')))) { res.setHeader('Access-Control-Allow-Origin', origin); } res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, apikey'); res.setHeader('Access-Control-Max-Age', '86400'); res.setHeader('Vary', 'Origin'); } export default async function handler(req, res) { setCors(req, res); if (req.method === 'OPTIONS') { return res.status(204).end(); } try { if (req.method !== 'POST') { return res.status(405).json({ error: 'Method not allowed' }); } // 1. Authenticate caller const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { return res.status(401).json({ error: 'Unauthorized: Missing token' }); } const token = authHeader.split(' ')[1]; const userRes = await fetch(`${SUPABASE_URL}/auth/v1/user`, { headers: { 'apikey': SUPABASE_ANON_KEY, 'Authorization': `Bearer ${token}` } }); if (!userRes.ok) { return res.status(401).json({ error: 'Unauthorized: Invalid token' }); } const user = await userRes.json(); const callerEmail = user.email; const callerId = user.id; if (!callerEmail) { return res.status(401).json({ error: 'Unauthorized: Invalid user payload' }); } const isMaster = MASTER_USERS.has(callerEmail.toLowerCase()); const { action } = req.body; if (!action) { return res.status(400).json({ error: 'Missing action' }); } // --- Action: Check Validation Status --- if (action === 'check-status') { if (isMaster) { return res.json({ validated: true }); } const approvalsRes = await fetch(`${SUPABASE_URL}/rest/v1/user_approvals?id=eq.${callerId}&select=validated`, { headers: { 'apikey': SUPABASE_SERVICE_KEY, 'Authorization': `Bearer ${SUPABASE_SERVICE_KEY}` } }); if (!approvalsRes.ok) { const errText = await approvalsRes.text(); console.error('Failed to query user approvals:', errText); return res.status(500).json({ error: 'Failed to query database' }); } const approvals = await approvalsRes.json(); const isApproved = approvals.length > 0 && approvals[0].validated === true; return res.json({ validated: isApproved }); } // --- Admin-only Actions --- if (!isMaster) { return res.status(403).json({ error: 'Forbidden: Admin access required' }); } if (action === 'list') { // Fetch all users from GoTrue Admin API const usersRes = await fetch(`${SUPABASE_URL}/auth/v1/admin/users`, { headers: { 'apikey': SUPABASE_SERVICE_KEY, 'Authorization': `Bearer ${SUPABASE_SERVICE_KEY}` } }); if (!usersRes.ok) { const errText = await usersRes.text(); console.error('Failed to fetch auth users:', errText); return res.status(500).json({ error: 'Failed to fetch users from authentication' }); } const usersData = await usersRes.json(); const authUsers = usersData.users || []; // Fetch validation mappings from public.user_approvals const approvalsRes = await fetch(`${SUPABASE_URL}/rest/v1/user_approvals?select=*`, { headers: { 'apikey': SUPABASE_SERVICE_KEY, 'Authorization': `Bearer ${SUPABASE_SERVICE_KEY}` } }); if (!approvalsRes.ok) { const errText = await approvalsRes.text(); console.error('Failed to fetch approvals:', errText); return res.status(500).json({ error: 'Failed to fetch user approvals' }); } const approvals = await approvalsRes.json(); const approvalMap = new Map(approvals.map(a => [a.id, a.validated])); const mergedUsers = authUsers.map(u => { const email = u.email; const id = u.id; const createdAt = u.created_at; let status = 'Pending'; if (MASTER_USERS.has(email?.toLowerCase())) { status = 'Master'; } else if (approvalMap.has(id)) { status = approvalMap.get(id) ? 'Validated' : 'Pending'; } return { id, email, created_at: createdAt, status }; }); return res.json({ users: mergedUsers }); } if (action === 'validate') { const { targetUserId, email, validated } = req.body; if (!targetUserId || !email) { return res.status(400).json({ error: 'Missing targetUserId or email' }); } // Upsert into user_approvals table const upsertRes = await fetch(`${SUPABASE_URL}/rest/v1/user_approvals`, { method: 'POST', headers: { 'apikey': SUPABASE_SERVICE_KEY, 'Authorization': `Bearer ${SUPABASE_SERVICE_KEY}`, 'Content-Type': 'application/json', 'Prefer': 'resolution=merge-duplicates,return=representation' }, body: JSON.stringify({ id: targetUserId, email, validated, created_at: new Date().toISOString() }) }); if (!upsertRes.ok) { const errText = await upsertRes.text(); console.error('Failed to upsert approval:', errText); return res.status(500).json({ error: 'Failed to update approval status' }); } return res.json({ success: true }); } if (action === 'delete') { const { targetUserId } = req.body; if (!targetUserId) { return res.status(400).json({ error: 'Missing targetUserId' }); } // Prevent master user self-deletion via API const { data: targetUserRes } = await fetch(`${SUPABASE_URL}/auth/v1/admin/users/${targetUserId}`, { headers: { 'apikey': SUPABASE_SERVICE_KEY, 'Authorization': `Bearer ${SUPABASE_SERVICE_KEY}` } }).then(r => r.json().catch(() => ({}))); if (targetUserRes && MASTER_USERS.has(targetUserRes.email?.toLowerCase())) { return res.status(400).json({ error: 'Cannot delete a master user account' }); } // 1. Delete user from auth const deleteAuthRes = await fetch(`${SUPABASE_URL}/auth/v1/admin/users/${targetUserId}`, { method: 'DELETE', headers: { 'apikey': SUPABASE_SERVICE_KEY, 'Authorization': `Bearer ${SUPABASE_SERVICE_KEY}` } }); if (!deleteAuthRes.ok) { const errText = await deleteAuthRes.text(); console.error('Failed to delete auth user:', errText); return res.status(500).json({ error: 'Failed to delete user from authentication' }); } // 2. Delete user approval record from public.user_approvals if exists await fetch(`${SUPABASE_URL}/rest/v1/user_approvals?id=eq.${targetUserId}`, { method: 'DELETE', headers: { 'apikey': SUPABASE_SERVICE_KEY, 'Authorization': `Bearer ${SUPABASE_SERVICE_KEY}` } }); return res.json({ success: true }); } return res.status(400).json({ error: 'Invalid action' }); } catch (err) { console.error('Error in users-admin function:', err); return res.status(500).json({ error: err.message || 'Internal server error' }); } }