180 lines
6.0 KiB
TypeScript
180 lines
6.0 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
|
import { verifyToken } from '@/lib/auth'
|
|
import { db } from '@/lib/database'
|
|
|
|
// GET /api/users/[id] - 查看用戶資料
|
|
export async function GET(request: NextRequest, { params }: { params: { id: string } }) {
|
|
try {
|
|
// 驗證管理員權限
|
|
const token = request.headers.get('authorization')?.replace('Bearer ', '')
|
|
if (!token) {
|
|
return NextResponse.json({ error: 'Authentication required' }, { status: 401 })
|
|
}
|
|
|
|
const decoded = verifyToken(token)
|
|
if (!decoded || decoded.role !== 'admin') {
|
|
return NextResponse.json({ error: 'Admin access required' }, { status: 403 })
|
|
}
|
|
|
|
const userId = await params.id
|
|
|
|
// 查詢用戶詳細資料
|
|
const user = await db.queryOne(`
|
|
SELECT
|
|
u.id,
|
|
u.name,
|
|
u.email,
|
|
u.avatar,
|
|
u.department,
|
|
u.role,
|
|
u.status,
|
|
u.join_date,
|
|
u.total_likes,
|
|
u.total_views,
|
|
u.created_at,
|
|
u.updated_at,
|
|
COUNT(DISTINCT a.id) as total_apps,
|
|
COUNT(DISTINCT js.id) as total_reviews
|
|
FROM users u
|
|
LEFT JOIN apps a ON u.id = a.creator_id
|
|
LEFT JOIN judge_scores js ON u.id = js.judge_id
|
|
WHERE u.id = ?
|
|
GROUP BY u.id
|
|
`, [userId])
|
|
|
|
if (!user) {
|
|
return NextResponse.json({ error: 'User not found' }, { status: 404 })
|
|
}
|
|
|
|
// 格式化日期函數
|
|
const formatDate = (dateString: string | null) => {
|
|
if (!dateString) return "-";
|
|
const date = new Date(dateString);
|
|
return date.toLocaleString('zh-TW', {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
hour12: false
|
|
}).replace(/\//g, '/');
|
|
};
|
|
|
|
// 計算登入天數(基於最後更新時間)
|
|
const loginDays = user.updated_at ?
|
|
Math.floor((Date.now() - new Date(user.updated_at).getTime()) / (1000 * 60 * 60 * 24)) : 0;
|
|
|
|
return NextResponse.json({
|
|
id: user.id,
|
|
name: user.name,
|
|
email: user.email,
|
|
avatar: user.avatar,
|
|
department: user.department,
|
|
role: user.role,
|
|
status: user.status || "active",
|
|
joinDate: formatDate(user.join_date),
|
|
lastLogin: formatDate(user.updated_at),
|
|
totalApps: user.total_apps || 0,
|
|
totalReviews: user.total_reviews || 0,
|
|
totalLikes: user.total_likes || 0,
|
|
loginDays: loginDays,
|
|
createdAt: formatDate(user.created_at),
|
|
updatedAt: formatDate(user.updated_at)
|
|
})
|
|
} catch (error) {
|
|
console.error('Error fetching user details:', error)
|
|
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
|
|
}
|
|
}
|
|
|
|
// PUT /api/users/[id] - 編輯用戶資料
|
|
export async function PUT(request: NextRequest, { params }: { params: { id: string } }) {
|
|
try {
|
|
// 驗證管理員權限
|
|
const token = request.headers.get('authorization')?.replace('Bearer ', '')
|
|
if (!token) {
|
|
return NextResponse.json({ error: 'Authentication required' }, { status: 401 })
|
|
}
|
|
|
|
const decoded = verifyToken(token)
|
|
if (!decoded || decoded.role !== 'admin') {
|
|
return NextResponse.json({ error: 'Admin access required' }, { status: 403 })
|
|
}
|
|
|
|
const userId = await params.id
|
|
const body = await request.json()
|
|
const { name, email, department, role, status } = body
|
|
|
|
// 驗證必填欄位
|
|
if (!name || !email) {
|
|
return NextResponse.json({ error: 'Name and email are required' }, { status: 400 })
|
|
}
|
|
|
|
// 驗證電子郵件格式
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
if (!emailRegex.test(email)) {
|
|
return NextResponse.json({ error: 'Invalid email format' }, { status: 400 })
|
|
}
|
|
|
|
// 檢查電子郵件唯一性(排除當前用戶)
|
|
const existingUser = await db.queryOne('SELECT id FROM users WHERE email = ? AND id != ?', [email, userId])
|
|
if (existingUser) {
|
|
return NextResponse.json({ error: 'Email already exists' }, { status: 409 })
|
|
}
|
|
|
|
// 更新用戶資料
|
|
await db.query(
|
|
'UPDATE users SET name = ?, email = ?, department = ?, role = ? WHERE id = ?',
|
|
[name, email, department, role, userId]
|
|
)
|
|
|
|
return NextResponse.json({ message: 'User updated successfully' })
|
|
} catch (error) {
|
|
console.error('Error updating user:', error)
|
|
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
|
|
}
|
|
}
|
|
|
|
// DELETE /api/users/[id] - 刪除用戶
|
|
export async function DELETE(request: NextRequest, { params }: { params: { id: string } }) {
|
|
try {
|
|
// 驗證管理員權限
|
|
const token = request.headers.get('authorization')?.replace('Bearer ', '')
|
|
if (!token) {
|
|
return NextResponse.json({ error: 'Authentication required' }, { status: 401 })
|
|
}
|
|
|
|
const decoded = verifyToken(token)
|
|
if (!decoded || decoded.role !== 'admin') {
|
|
return NextResponse.json({ error: 'Admin access required' }, { status: 403 })
|
|
}
|
|
|
|
const userId = await params.id
|
|
|
|
// 檢查用戶是否存在
|
|
const user = await db.queryOne('SELECT id FROM users WHERE id = ?', [userId])
|
|
if (!user) {
|
|
return NextResponse.json({ error: 'User not found' }, { status: 404 })
|
|
}
|
|
|
|
// 檢查是否為最後一個管理員
|
|
const adminCount = await db.queryOne('SELECT COUNT(*) as count FROM users WHERE role = "admin"')
|
|
const userRole = await db.queryOne('SELECT role FROM users WHERE id = ?', [userId])
|
|
|
|
if (adminCount?.count === 1 && userRole?.role === 'admin') {
|
|
return NextResponse.json({ error: 'Cannot delete the last admin user' }, { status: 400 })
|
|
}
|
|
|
|
// 級聯刪除相關資料
|
|
await db.query('DELETE FROM judge_scores WHERE judge_id = ?', [userId])
|
|
await db.query('DELETE FROM apps WHERE creator_id = ?', [userId])
|
|
|
|
// 刪除用戶
|
|
await db.query('DELETE FROM users WHERE id = ?', [userId])
|
|
|
|
return NextResponse.json({ message: 'User deleted successfully' })
|
|
} catch (error) {
|
|
console.error('Error deleting user:', error)
|
|
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
|
|
}
|
|
}
|