export const dynamic = 'force-dynamic'; import { NextRequest, NextResponse } from 'next/server'; import { supabase } from '@/lib/supabase'; import { ensureAdmin, ensureAuthenticated, getAuthContext } from '@/lib/access-control'; export async function GET(request: NextRequest) { const ctx = await getAuthContext(request); const auth = ensureAuthenticated(ctx); if (!auth.ok) { return NextResponse.json({ error: auth.error }, { status: auth.status }); } if (ctx!.isAdmin) { const { data, error } = await supabase .from('users') .select('id,name,role,avatar_url,username,created_at,updated_at') .order('created_at', { ascending: true }); if (error) { return NextResponse.json({ error: error.message }, { status: 500 }); } return NextResponse.json(data); } const projectIds = ctx!.accessibleProjectIds; const allowedUserIds = new Set([ctx!.user.id]); if (projectIds.length > 0) { const [membersRes, projectsRes] = await Promise.all([ supabase.from('project_members').select('user_id').in('project_id', projectIds), supabase.from('projects').select('owner_id,pm_id').in('id', projectIds), ]); if (membersRes.data) { for (const row of membersRes.data as Array<{ user_id: string }>) { allowedUserIds.add(row.user_id); } } if (projectsRes.data) { for (const row of projectsRes.data as Array<{ owner_id: string | null; pm_id: string | null }>) { if (row.owner_id) allowedUserIds.add(row.owner_id); if (row.pm_id) allowedUserIds.add(row.pm_id); } } } const ids = Array.from(allowedUserIds); const { data, error } = await supabase .from('users') .select('id,name,role,avatar_url,username,created_at,updated_at') .in('id', ids) .order('created_at', { ascending: true }); if (error) { return NextResponse.json({ error: error.message }, { status: 500 }); } return NextResponse.json(data); } export async function POST(request: NextRequest) { const ctx = await getAuthContext(request); const auth = ensureAdmin(ctx); if (!auth.ok) { return NextResponse.json({ error: auth.error }, { status: auth.status }); } const body = await request.json(); const { name, role, avatar_url, username, password } = body; if (!name || !role) { return NextResponse.json({ error: '名称和角色为必填项' }, { status: 400 }); } let password_hash: string | null = null; if (password) { const { hashPassword } = await import('@/lib/password'); password_hash = hashPassword(String(password)); } const { data, error } = await supabase .from('users') .insert({ name, role, avatar_url, username: username || null, password_hash, }) .select('id,name,role,avatar_url,username,created_at,updated_at') .single(); if (error) { return NextResponse.json({ error: error.message }, { status: 500 }); } return NextResponse.json(data, { status: 201 }); }