feat: 重构用户角色系统为管理员标识
- 将用户角色字段从role改为is_admin布尔值 - 更新相关API权限检查逻辑 - 修改数据库schema和迁移文件 - 调整前端用户显示逻辑 - 添加API响应工具函数 - 优化权限检查中间件 - 重构英雄组件为原子组件
This commit is contained in:
@@ -129,8 +129,7 @@ export default function AdminLayout({
|
||||
{session?.user?.name}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 truncate">
|
||||
{session?.user?.role === 'admin' ? '管理员' :
|
||||
session?.user?.role === 'editor' ? '编辑' : '查看者'}
|
||||
{session?.user?.isAdmin ? '管理员' : '用户'}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { NextRequest } from 'next/server';
|
||||
import { db } from '@/db';
|
||||
import { siteConfig } from '@/db/schema';
|
||||
import { auth } from '@/lib/auth';
|
||||
import { hasPermission } from '@/lib/auth/permissions';
|
||||
import { checkIsAdmin, getAdminUserId } from '@/lib/auth/check-permission';
|
||||
import { forbidden, success, notFound, validationError, badRequest, handleApiError } from '@/lib/api-response';
|
||||
import { eq, and } from 'drizzle-orm';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const session = await auth();
|
||||
const { isAdmin } = await checkIsAdmin();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'config', 'read')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
if (!isAdmin) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url);
|
||||
@@ -32,10 +26,10 @@ export async function GET(request: NextRequest) {
|
||||
.limit(1);
|
||||
|
||||
if (config.length === 0) {
|
||||
return NextResponse.json({ error: '配置不存在' }, { status: 404 });
|
||||
return notFound('配置不存在');
|
||||
}
|
||||
|
||||
return NextResponse.json(config[0]);
|
||||
return success(config[0]);
|
||||
}
|
||||
|
||||
const conditions = [];
|
||||
@@ -61,35 +55,29 @@ export async function GET(request: NextRequest) {
|
||||
return acc;
|
||||
}, {} as Record<string, typeof configs>);
|
||||
|
||||
return NextResponse.json({
|
||||
return success({
|
||||
configs: groupedConfigs,
|
||||
flat: configs,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取配置失败:', error);
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const session = await auth();
|
||||
const { isAdmin } = await checkIsAdmin();
|
||||
const userId = await getAdminUserId();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'config', 'update')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
if (!isAdmin || !userId) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { key, value, category, description } = body;
|
||||
|
||||
if (!key || !value || !category) {
|
||||
return NextResponse.json({ error: '缺少必要字段' }, { status: 400 });
|
||||
return validationError('缺少必要字段', { required: ['key', 'value', 'category'] });
|
||||
}
|
||||
|
||||
const existing = await db
|
||||
@@ -107,12 +95,12 @@ export async function POST(request: NextRequest) {
|
||||
value,
|
||||
description: description || existing[0]!.description,
|
||||
updatedAt: now,
|
||||
updatedBy: session.user.id,
|
||||
updatedBy: userId,
|
||||
})
|
||||
.where(eq(siteConfig.key, key))
|
||||
.returning();
|
||||
|
||||
return NextResponse.json(updated[0]);
|
||||
return success(updated[0], 200);
|
||||
}
|
||||
|
||||
const newConfig = await db
|
||||
@@ -124,36 +112,30 @@ export async function POST(request: NextRequest) {
|
||||
category,
|
||||
description: description || null,
|
||||
updatedAt: now,
|
||||
updatedBy: session.user.id,
|
||||
updatedBy: userId,
|
||||
})
|
||||
.returning();
|
||||
|
||||
return NextResponse.json(newConfig[0], { status: 201 });
|
||||
return success(newConfig[0], 201);
|
||||
} catch (error) {
|
||||
console.error('创建/更新配置失败:', error);
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function PUT(request: NextRequest) {
|
||||
try {
|
||||
const session = await auth();
|
||||
const { isAdmin } = await checkIsAdmin();
|
||||
const userId = await getAdminUserId();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'config', 'update')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
if (!isAdmin || !userId) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { configs } = body as { configs: Array<{ key: string; value: unknown; description?: string }> };
|
||||
|
||||
if (!Array.isArray(configs)) {
|
||||
return NextResponse.json({ error: '无效的数据格式' }, { status: 400 });
|
||||
return badRequest('无效的数据格式');
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
@@ -173,7 +155,7 @@ export async function PUT(request: NextRequest) {
|
||||
value: config.value,
|
||||
description: config.description || existing[0]!.description,
|
||||
updatedAt: now,
|
||||
updatedBy: session.user.id,
|
||||
updatedBy: userId,
|
||||
})
|
||||
.where(eq(siteConfig.key, config.key))
|
||||
.returning();
|
||||
@@ -188,16 +170,50 @@ export async function PUT(request: NextRequest) {
|
||||
category: 'general',
|
||||
description: config.description || null,
|
||||
updatedAt: now,
|
||||
updatedBy: session.user.id,
|
||||
updatedBy: userId,
|
||||
})
|
||||
.returning();
|
||||
results.push(created[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, updated: results.length });
|
||||
return success(results);
|
||||
} catch (error) {
|
||||
console.error('批量更新配置失败:', error);
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(request: NextRequest) {
|
||||
try {
|
||||
const { isAdmin } = await checkIsAdmin();
|
||||
|
||||
if (!isAdmin) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url);
|
||||
const key = searchParams.get('key');
|
||||
|
||||
if (!key) {
|
||||
return badRequest('缺少 key 参数');
|
||||
}
|
||||
|
||||
const existing = await db
|
||||
.select()
|
||||
.from(siteConfig)
|
||||
.where(eq(siteConfig.key, key))
|
||||
.limit(1);
|
||||
|
||||
if (existing.length === 0) {
|
||||
return notFound('配置不存在');
|
||||
}
|
||||
|
||||
await db
|
||||
.delete(siteConfig)
|
||||
.where(eq(siteConfig.key, key));
|
||||
|
||||
return success({ success: true });
|
||||
} catch (error) {
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { NextRequest } from 'next/server';
|
||||
import { db } from '@/db';
|
||||
import { content, contentVersions } from '@/db/schema';
|
||||
import { auth } from '@/lib/auth';
|
||||
import { hasPermission } from '@/lib/auth/permissions';
|
||||
import { checkIsAdmin, getAdminUserId } from '@/lib/auth/check-permission';
|
||||
import { createAuditLog } from '@/lib/audit';
|
||||
import { forbidden, notFound, success, handleApiError } from '@/lib/api-response';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
@@ -12,16 +12,10 @@ export async function GET(
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await auth();
|
||||
const { isAdmin } = await checkIsAdmin();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'content', 'read')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
if (!isAdmin) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
@@ -33,7 +27,7 @@ export async function GET(
|
||||
.limit(1);
|
||||
|
||||
if (item.length === 0) {
|
||||
return NextResponse.json({ error: '内容不存在' }, { status: 404 });
|
||||
return notFound('内容不存在');
|
||||
}
|
||||
|
||||
const versions = await db
|
||||
@@ -42,13 +36,12 @@ export async function GET(
|
||||
.where(eq(contentVersions.contentId, id))
|
||||
.orderBy(contentVersions.version);
|
||||
|
||||
return NextResponse.json({
|
||||
return success({
|
||||
...item[0],
|
||||
versions,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取内容详情失败:', error);
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,16 +50,11 @@ export async function PUT(
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await auth();
|
||||
const { isAdmin } = await checkIsAdmin();
|
||||
const userId = await getAdminUserId();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'content', 'update')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
if (!isAdmin || !userId) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
@@ -79,7 +67,7 @@ export async function PUT(
|
||||
.limit(1);
|
||||
|
||||
if (existingContent.length === 0) {
|
||||
return NextResponse.json({ error: '内容不存在' }, { status: 404 });
|
||||
return notFound('内容不存在');
|
||||
}
|
||||
|
||||
const current = existingContent[0]!;
|
||||
@@ -107,7 +95,7 @@ export async function PUT(
|
||||
},
|
||||
to: body,
|
||||
},
|
||||
changedBy: session.user.id,
|
||||
changedBy: userId,
|
||||
changedAt: now,
|
||||
});
|
||||
|
||||
@@ -138,7 +126,7 @@ export async function PUT(
|
||||
.returning();
|
||||
|
||||
await createAuditLog({
|
||||
userId: session.user.id,
|
||||
userId,
|
||||
action: 'update',
|
||||
resourceType: 'content',
|
||||
resourceId: id,
|
||||
@@ -147,10 +135,9 @@ export async function PUT(
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(updated[0]);
|
||||
return success(updated[0]);
|
||||
} catch (error) {
|
||||
console.error('更新内容失败:', error);
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,16 +146,11 @@ export async function DELETE(
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await auth();
|
||||
const { isAdmin } = await checkIsAdmin();
|
||||
const userId = await getAdminUserId();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'content', 'delete')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
if (!isAdmin || !userId) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
@@ -180,14 +162,14 @@ export async function DELETE(
|
||||
.limit(1);
|
||||
|
||||
if (existingContent.length === 0) {
|
||||
return NextResponse.json({ error: '内容不存在' }, { status: 404 });
|
||||
return notFound('内容不存在');
|
||||
}
|
||||
|
||||
await db.delete(contentVersions).where(eq(contentVersions.contentId, id));
|
||||
await db.delete(content).where(eq(content.id, id));
|
||||
|
||||
await createAuditLog({
|
||||
userId: session.user.id,
|
||||
userId,
|
||||
action: 'delete',
|
||||
resourceType: 'content',
|
||||
resourceId: id,
|
||||
@@ -196,9 +178,8 @@ export async function DELETE(
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
return success({ success: true });
|
||||
} catch (error) {
|
||||
console.error('删除内容失败:', error);
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { NextRequest } from 'next/server';
|
||||
import { db } from '@/db';
|
||||
import { content } from '@/db/schema';
|
||||
import { auth } from '@/lib/auth';
|
||||
import { hasPermission } from '@/lib/auth/permissions';
|
||||
import { checkIsAdmin, getAdminUserId } from '@/lib/auth/check-permission';
|
||||
import { createAuditLog } from '@/lib/audit';
|
||||
import { forbidden, badRequest, success, handleApiError, validationError } from '@/lib/api-response';
|
||||
import { eq, desc, and, like, sql } from 'drizzle-orm';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const session = await auth();
|
||||
const { isAdmin } = await checkIsAdmin();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'content', 'read')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
if (!isAdmin) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url);
|
||||
@@ -61,7 +55,7 @@ export async function GET(request: NextRequest) {
|
||||
|
||||
const total = countResult[0]?.count || 0;
|
||||
|
||||
return NextResponse.json({
|
||||
return success({
|
||||
items,
|
||||
pagination: {
|
||||
page,
|
||||
@@ -71,30 +65,24 @@ export async function GET(request: NextRequest) {
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取内容列表失败:', error);
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const session = await auth();
|
||||
const { isAdmin } = await checkIsAdmin();
|
||||
const userId = await getAdminUserId();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'content', 'create')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
if (!isAdmin || !userId) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { type, title, slug, excerpt, contentBody, coverImage, category, tags, status: contentStatus, metadata } = body;
|
||||
|
||||
if (!type || !title || !slug) {
|
||||
return NextResponse.json({ error: '缺少必要字段' }, { status: 400 });
|
||||
return validationError('缺少必要字段', { required: ['type', 'title', 'slug'] });
|
||||
}
|
||||
|
||||
const existingContent = await db
|
||||
@@ -104,7 +92,7 @@ export async function POST(request: NextRequest) {
|
||||
.limit(1);
|
||||
|
||||
if (existingContent.length > 0) {
|
||||
return NextResponse.json({ error: 'Slug 已存在' }, { status: 400 });
|
||||
return badRequest('Slug 已存在');
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
@@ -122,7 +110,7 @@ export async function POST(request: NextRequest) {
|
||||
tags: tags || [],
|
||||
status: contentStatus || 'draft',
|
||||
publishedAt: contentStatus === 'published' ? now : null,
|
||||
authorId: session.user.id,
|
||||
authorId: userId,
|
||||
metadata: metadata || null,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
@@ -130,7 +118,7 @@ export async function POST(request: NextRequest) {
|
||||
.returning();
|
||||
|
||||
await createAuditLog({
|
||||
userId: session.user.id,
|
||||
userId,
|
||||
action: 'create',
|
||||
resourceType: 'content',
|
||||
resourceId: newContent[0]!.id,
|
||||
@@ -141,9 +129,8 @@ export async function POST(request: NextRequest) {
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(newContent[0], { status: 201 });
|
||||
return success(newContent[0], 201);
|
||||
} catch (error) {
|
||||
console.error('创建内容失败:', error);
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { auth } from '@/lib/auth';
|
||||
import { hasPermission } from '@/lib/auth/permissions';
|
||||
import { NextRequest } from 'next/server';
|
||||
import { checkIsAdmin, getAdminUserId } from '@/lib/auth/check-permission';
|
||||
import { createAuditLog } from '@/lib/audit';
|
||||
import { uploadFile, deleteFile } from '@/lib/upload';
|
||||
import { forbidden, badRequest, notFound, success, handleApiError } from '@/lib/api-response';
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const session = await auth();
|
||||
const { isAdmin } = await checkIsAdmin();
|
||||
const userId = await getAdminUserId();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'content', 'create')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
if (!isAdmin || !userId) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const formData = await request.formData();
|
||||
@@ -23,16 +18,16 @@ export async function POST(request: NextRequest) {
|
||||
const type = (formData.get('type') as 'image' | 'document') || 'image';
|
||||
|
||||
if (!file) {
|
||||
return NextResponse.json({ error: '未找到文件' }, { status: 400 });
|
||||
return badRequest('未找到文件');
|
||||
}
|
||||
|
||||
const result = await uploadFile(file, {
|
||||
type,
|
||||
userId: session.user.id,
|
||||
userId,
|
||||
});
|
||||
|
||||
await createAuditLog({
|
||||
userId: session.user.id,
|
||||
userId,
|
||||
action: 'upload',
|
||||
resourceType: 'file',
|
||||
resourceId: result.id,
|
||||
@@ -44,7 +39,7 @@ export async function POST(request: NextRequest) {
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
return success({
|
||||
success: true,
|
||||
file: result,
|
||||
});
|
||||
@@ -52,43 +47,38 @@ export async function POST(request: NextRequest) {
|
||||
console.error('文件上传失败:', error);
|
||||
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ error: error.message }, { status: 400 });
|
||||
return badRequest(error.message);
|
||||
}
|
||||
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(request: NextRequest) {
|
||||
try {
|
||||
const session = await auth();
|
||||
const { isAdmin } = await checkIsAdmin();
|
||||
const userId = await getAdminUserId();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'content', 'delete')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
if (!isAdmin || !userId) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url);
|
||||
const fileUrl = searchParams.get('url');
|
||||
|
||||
if (!fileUrl) {
|
||||
return NextResponse.json({ error: '缺少文件 URL' }, { status: 400 });
|
||||
return badRequest('缺少文件 URL');
|
||||
}
|
||||
|
||||
const success = await deleteFile(fileUrl);
|
||||
const result = await deleteFile(fileUrl);
|
||||
|
||||
if (!success) {
|
||||
return NextResponse.json({ error: '文件不存在或删除失败' }, { status: 404 });
|
||||
if (!result) {
|
||||
return notFound('文件不存在或删除失败');
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
return success({ success: true });
|
||||
} catch (error) {
|
||||
console.error('文件删除失败:', error);
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { NextRequest } from 'next/server';
|
||||
import { db } from '@/db';
|
||||
import { users } from '@/db/schema';
|
||||
import { auth } from '@/lib/auth';
|
||||
import { hasPermission } from '@/lib/auth/permissions';
|
||||
import { checkIsAdmin } from '@/lib/auth/check-permission';
|
||||
import { forbidden, notFound, success, handleApiError } from '@/lib/api-response';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import bcrypt from 'bcryptjs';
|
||||
|
||||
@@ -11,26 +11,24 @@ export async function GET(
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await auth();
|
||||
const { isAdmin, userId } = await checkIsAdmin();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'users', 'read')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
if (!isAdmin) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
|
||||
if (id !== userId) {
|
||||
return forbidden('只能查看自己的信息');
|
||||
}
|
||||
|
||||
const user = await db
|
||||
.select({
|
||||
id: users.id,
|
||||
email: users.email,
|
||||
name: users.name,
|
||||
role: users.role,
|
||||
isAdmin: users.isAdmin,
|
||||
createdAt: users.createdAt,
|
||||
updatedAt: users.updatedAt,
|
||||
})
|
||||
@@ -39,13 +37,12 @@ export async function GET(
|
||||
.limit(1);
|
||||
|
||||
if (user.length === 0) {
|
||||
return NextResponse.json({ error: '用户不存在' }, { status: 404 });
|
||||
return notFound('用户不存在');
|
||||
}
|
||||
|
||||
return NextResponse.json({ user: user[0] });
|
||||
return success({ user: user[0] });
|
||||
} catch (error) {
|
||||
console.error('获取用户详情失败:', error);
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,21 +51,20 @@ export async function PUT(
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await auth();
|
||||
const { isAdmin, userId } = await checkIsAdmin();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'users', 'update')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
if (!isAdmin) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
|
||||
if (id !== userId) {
|
||||
return forbidden('只能修改自己的信息');
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { email, name, password, role } = body;
|
||||
const { email, name, password } = body;
|
||||
|
||||
const existingUser = await db
|
||||
.select()
|
||||
@@ -77,16 +73,15 @@ export async function PUT(
|
||||
.limit(1);
|
||||
|
||||
if (existingUser.length === 0) {
|
||||
return NextResponse.json({ error: '用户不存在' }, { status: 404 });
|
||||
return notFound('用户不存在');
|
||||
}
|
||||
|
||||
const updateData: Record<string, any> = {
|
||||
const updateData: Record<string, unknown> = {
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
if (email) updateData.email = email;
|
||||
if (name) updateData.name = name;
|
||||
if (role) updateData.role = role;
|
||||
if (password) {
|
||||
updateData.passwordHash = await bcrypt.hash(password, 10);
|
||||
}
|
||||
@@ -97,18 +92,16 @@ export async function PUT(
|
||||
.where(eq(users.id, id))
|
||||
.returning();
|
||||
|
||||
return NextResponse.json({
|
||||
return success({
|
||||
user: {
|
||||
id: updated[0]!.id,
|
||||
email: updated[0]!.email,
|
||||
name: updated[0]!.name,
|
||||
role: updated[0]!.role,
|
||||
createdAt: updated[0]!.createdAt,
|
||||
}
|
||||
isAdmin: updated[0]!.isAdmin,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新用户失败:', error);
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,39 +110,24 @@ export async function DELETE(
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await auth();
|
||||
const { isAdmin, userId } = await checkIsAdmin();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'users', 'delete')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
if (!isAdmin) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
|
||||
if (session.user.id === id) {
|
||||
return NextResponse.json({ error: '不能删除自己的账号' }, { status: 400 });
|
||||
if (id !== userId) {
|
||||
return forbidden('不能删除其他用户');
|
||||
}
|
||||
|
||||
const existingUser = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, id))
|
||||
.limit(1);
|
||||
await db
|
||||
.delete(users)
|
||||
.where(eq(users.id, id));
|
||||
|
||||
if (existingUser.length === 0) {
|
||||
return NextResponse.json({ error: '用户不存在' }, { status: 404 });
|
||||
}
|
||||
|
||||
await db.delete(users).where(eq(users.id, id));
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
return success({ success: true });
|
||||
} catch (error) {
|
||||
console.error('删除用户失败:', error);
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,16 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { NextRequest } from 'next/server';
|
||||
import { db } from '@/db';
|
||||
import { users } from '@/db/schema';
|
||||
import { auth } from '@/lib/auth';
|
||||
import { hasPermission } from '@/lib/auth/permissions';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { nanoid } from 'nanoid';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import { checkIsAdmin } from '@/lib/auth/check-permission';
|
||||
import { forbidden, success, handleApiError } from '@/lib/api-response';
|
||||
import { desc } from 'drizzle-orm';
|
||||
|
||||
export async function GET(_request: NextRequest) {
|
||||
try {
|
||||
const session = await auth();
|
||||
const { isAdmin } = await checkIsAdmin();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'users', 'read')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
if (!isAdmin) {
|
||||
return forbidden();
|
||||
}
|
||||
|
||||
const allUsers = await db
|
||||
@@ -26,77 +18,16 @@ export async function GET(_request: NextRequest) {
|
||||
id: users.id,
|
||||
email: users.email,
|
||||
name: users.name,
|
||||
role: users.role,
|
||||
isAdmin: users.isAdmin,
|
||||
createdAt: users.createdAt,
|
||||
updatedAt: users.updatedAt,
|
||||
})
|
||||
.from(users)
|
||||
.orderBy(users.createdAt);
|
||||
.orderBy(desc(users.createdAt));
|
||||
|
||||
return NextResponse.json({ users: allUsers });
|
||||
return success({ users: allUsers });
|
||||
} catch (error) {
|
||||
console.error('获取用户列表失败:', error);
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const userRole = session.user.role as 'admin' | 'editor' | 'viewer';
|
||||
|
||||
if (!hasPermission(userRole, 'users', 'create')) {
|
||||
return NextResponse.json({ error: '无权限' }, { status: 403 });
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { email, name, password, role } = body;
|
||||
|
||||
if (!email || !name || !password || !role) {
|
||||
return NextResponse.json({ error: '缺少必填字段' }, { status: 400 });
|
||||
}
|
||||
|
||||
const existingUser = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.email, email))
|
||||
.limit(1);
|
||||
|
||||
if (existingUser.length > 0) {
|
||||
return NextResponse.json({ error: '邮箱已被使用' }, { status: 400 });
|
||||
}
|
||||
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
|
||||
const newUser = await db
|
||||
.insert(users)
|
||||
.values({
|
||||
id: nanoid(),
|
||||
email,
|
||||
name,
|
||||
passwordHash: hashedPassword,
|
||||
role,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.returning();
|
||||
|
||||
return NextResponse.json({
|
||||
user: {
|
||||
id: newUser[0]!.id,
|
||||
email: newUser[0]!.email,
|
||||
name: newUser[0]!.name,
|
||||
role: newUser[0]!.role,
|
||||
createdAt: newUser[0]!.createdAt,
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('创建用户失败:', error);
|
||||
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
|
||||
return handleApiError(error);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user