feat: 修复测试套件问题并添加Woodpecker CI配置

- 修复API测试认证问题:创建全局认证设置,更新Playwright配置
- 优化回归测试稳定性:增加超时时间到15秒,修复定位器
- 创建Woodpecker CI工作流:CI、部署和质量门禁配置
- 添加Jest配置和测试脚本
- 移除登录页面的默认账号密码显示(安全问题修复)
This commit is contained in:
张翔
2026-03-09 10:26:02 +08:00
parent 96c96fe75d
commit 6d92024b63
68 changed files with 5584 additions and 167 deletions
+94
View File
@@ -0,0 +1,94 @@
import { NextRequest, NextResponse } from 'next/server';
import { auth } from '@/lib/auth';
import { hasPermission } from '@/lib/auth/permissions';
import { createAuditLog } from '@/lib/audit';
import { uploadFile, deleteFile } from '@/lib/upload';
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, 'content', 'create')) {
return NextResponse.json({ error: '无权限' }, { status: 403 });
}
const formData = await request.formData();
const file = formData.get('file') as File | null;
const type = (formData.get('type') as 'image' | 'document') || 'image';
if (!file) {
return NextResponse.json({ error: '未找到文件' }, { status: 400 });
}
const result = await uploadFile(file, {
type,
userId: session.user.id,
});
await createAuditLog({
userId: session.user.id,
action: 'upload',
resourceType: 'file',
resourceId: result.id,
details: {
fileName: result.name,
fileType: result.type,
fileSize: result.size,
url: result.url,
},
});
return NextResponse.json({
success: true,
file: result,
});
} catch (error) {
console.error('文件上传失败:', error);
if (error instanceof Error) {
return NextResponse.json({ error: error.message }, { status: 400 });
}
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
}
}
export async function DELETE(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, 'content', 'delete')) {
return NextResponse.json({ error: '无权限' }, { status: 403 });
}
const { searchParams } = new URL(request.url);
const fileUrl = searchParams.get('url');
if (!fileUrl) {
return NextResponse.json({ error: '缺少文件 URL' }, { status: 400 });
}
const success = await deleteFile(fileUrl);
if (!success) {
return NextResponse.json({ error: '文件不存在或删除失败' }, { status: 404 });
}
return NextResponse.json({ success: true });
} catch (error) {
console.error('文件删除失败:', error);
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
}
}