feat(设置): 实现用户级别设置隔离
- 设置 API 改为基于当前登录用户 - 注册时自动创建默认用户设置 - API Key 加密后存储到数据库 - 添加默认设置常量和格式化函数
This commit is contained in:
parent
2e8033a8ae
commit
058ea85daa
@ -122,9 +122,19 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
.returning();
|
||||
|
||||
// 创建默认用户设置
|
||||
// 创建默认用户设置(API Key 为空,需要用户自行配置)
|
||||
await db.insert(userSettings).values({
|
||||
userId,
|
||||
cchUrl: process.env.CCH_DEFAULT_URL || 'https://claude.leocoder.cn/',
|
||||
cchApiKey: null,
|
||||
cchApiKeyConfigured: false,
|
||||
defaultModel: 'claude-sonnet-4-20250514',
|
||||
defaultTools: ['web_search', 'code_execution', 'web_fetch'],
|
||||
theme: 'light',
|
||||
language: 'zh-CN',
|
||||
fontSize: 15,
|
||||
enableThinking: false,
|
||||
saveChatHistory: true,
|
||||
});
|
||||
|
||||
// 生成 JWT Token
|
||||
|
||||
@ -2,18 +2,12 @@ import { NextResponse } from 'next/server';
|
||||
import { db } from '@/drizzle/db';
|
||||
import { userSettings } from '@/drizzle/schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { getCurrentUser } from '@/lib/auth';
|
||||
import { encryptApiKey } from '@/lib/crypto';
|
||||
|
||||
// GET /api/settings - 获取用户设置
|
||||
export async function GET() {
|
||||
try {
|
||||
const settings = await db.query.userSettings.findFirst({
|
||||
where: eq(userSettings.id, 1),
|
||||
});
|
||||
|
||||
if (!settings) {
|
||||
// 如果没有设置,返回默认值
|
||||
return NextResponse.json({
|
||||
cchUrl: process.env.CCH_DEFAULT_URL || 'http://localhost:13500',
|
||||
// 默认设置值
|
||||
const DEFAULT_SETTINGS = {
|
||||
cchUrl: process.env.CCH_DEFAULT_URL || 'https://claude.leocoder.cn/',
|
||||
cchApiKeyConfigured: false,
|
||||
defaultModel: 'claude-sonnet-4-20250514',
|
||||
defaultTools: ['web_search', 'code_execution', 'web_fetch'],
|
||||
@ -24,23 +18,65 @@ export async function GET() {
|
||||
fontSize: 15,
|
||||
enableThinking: false,
|
||||
saveChatHistory: true,
|
||||
});
|
||||
};
|
||||
|
||||
// 格式化设置响应(不返回 API Key 本身)
|
||||
function formatSettingsResponse(settings: typeof userSettings.$inferSelect | null) {
|
||||
if (!settings) {
|
||||
return DEFAULT_SETTINGS;
|
||||
}
|
||||
|
||||
// 不返回 API Key 本身,只返回是否已配置
|
||||
return NextResponse.json({
|
||||
cchUrl: settings.cchUrl,
|
||||
cchApiKeyConfigured: settings.cchApiKeyConfigured,
|
||||
defaultModel: settings.defaultModel,
|
||||
defaultTools: settings.defaultTools,
|
||||
return {
|
||||
cchUrl: settings.cchUrl || DEFAULT_SETTINGS.cchUrl,
|
||||
cchApiKeyConfigured: settings.cchApiKeyConfigured || false,
|
||||
defaultModel: settings.defaultModel || DEFAULT_SETTINGS.defaultModel,
|
||||
defaultTools: settings.defaultTools || DEFAULT_SETTINGS.defaultTools,
|
||||
systemPrompt: settings.systemPrompt || '',
|
||||
temperature: settings.temperature || '0.7',
|
||||
theme: settings.theme,
|
||||
language: settings.language,
|
||||
theme: settings.theme || DEFAULT_SETTINGS.theme,
|
||||
language: settings.language || DEFAULT_SETTINGS.language,
|
||||
fontSize: settings.fontSize || 15,
|
||||
enableThinking: settings.enableThinking,
|
||||
saveChatHistory: settings.saveChatHistory,
|
||||
enableThinking: settings.enableThinking || false,
|
||||
saveChatHistory: settings.saveChatHistory ?? true,
|
||||
};
|
||||
}
|
||||
|
||||
// GET /api/settings - 获取当前用户的设置
|
||||
export async function GET() {
|
||||
try {
|
||||
// 1. 获取当前登录用户
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
// 未登录用户返回默认设置(允许查看但无法保存)
|
||||
return NextResponse.json(DEFAULT_SETTINGS);
|
||||
}
|
||||
|
||||
// 2. 查询该用户的设置
|
||||
const settings = await db.query.userSettings.findFirst({
|
||||
where: eq(userSettings.userId, user.userId),
|
||||
});
|
||||
|
||||
// 3. 如果没有设置记录,创建默认设置
|
||||
if (!settings) {
|
||||
const newSettings = await db
|
||||
.insert(userSettings)
|
||||
.values({
|
||||
userId: user.userId,
|
||||
cchUrl: DEFAULT_SETTINGS.cchUrl,
|
||||
defaultModel: DEFAULT_SETTINGS.defaultModel,
|
||||
defaultTools: DEFAULT_SETTINGS.defaultTools,
|
||||
theme: DEFAULT_SETTINGS.theme,
|
||||
language: DEFAULT_SETTINGS.language,
|
||||
fontSize: DEFAULT_SETTINGS.fontSize,
|
||||
enableThinking: DEFAULT_SETTINGS.enableThinking,
|
||||
saveChatHistory: DEFAULT_SETTINGS.saveChatHistory,
|
||||
})
|
||||
.returning();
|
||||
|
||||
return NextResponse.json(formatSettingsResponse(newSettings[0]));
|
||||
}
|
||||
|
||||
return NextResponse.json(formatSettingsResponse(settings));
|
||||
} catch (error) {
|
||||
console.error('Failed to get settings:', error);
|
||||
return NextResponse.json(
|
||||
@ -50,9 +86,18 @@ export async function GET() {
|
||||
}
|
||||
}
|
||||
|
||||
// PUT /api/settings - 更新用户设置
|
||||
// PUT /api/settings - 更新当前用户的设置
|
||||
export async function PUT(request: Request) {
|
||||
try {
|
||||
// 1. 获取当前登录用户
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
return NextResponse.json(
|
||||
{ error: '请先登录后再修改设置' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const {
|
||||
cchUrl,
|
||||
@ -68,7 +113,7 @@ export async function PUT(request: Request) {
|
||||
saveChatHistory,
|
||||
} = body;
|
||||
|
||||
// 构建更新对象
|
||||
// 2. 构建更新对象
|
||||
const updateData: Record<string, unknown> = {
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
@ -77,14 +122,15 @@ export async function PUT(request: Request) {
|
||||
updateData.cchUrl = cchUrl;
|
||||
}
|
||||
|
||||
// 如果提供了 API Key,更新它
|
||||
// 如果提供了 API Key,加密后存储
|
||||
if (cchApiKey !== undefined) {
|
||||
if (cchApiKey === '') {
|
||||
// 清除 API Key
|
||||
updateData.cchApiKey = null;
|
||||
updateData.cchApiKeyConfigured = false;
|
||||
} else {
|
||||
updateData.cchApiKey = cchApiKey;
|
||||
// 加密存储 API Key
|
||||
updateData.cchApiKey = encryptApiKey(cchApiKey);
|
||||
updateData.cchApiKeyConfigured = true;
|
||||
}
|
||||
}
|
||||
@ -126,15 +172,23 @@ export async function PUT(request: Request) {
|
||||
updateData.saveChatHistory = saveChatHistory;
|
||||
}
|
||||
|
||||
// 检查是否存在设置记录
|
||||
// 3. 检查是否存在该用户的设置记录
|
||||
const existing = await db.query.userSettings.findFirst({
|
||||
where: eq(userSettings.id, 1),
|
||||
where: eq(userSettings.userId, user.userId),
|
||||
});
|
||||
|
||||
if (!existing) {
|
||||
// 创建新的设置记录
|
||||
await db.insert(userSettings).values({
|
||||
id: 1,
|
||||
userId: user.userId,
|
||||
cchUrl: DEFAULT_SETTINGS.cchUrl,
|
||||
defaultModel: DEFAULT_SETTINGS.defaultModel,
|
||||
defaultTools: DEFAULT_SETTINGS.defaultTools,
|
||||
theme: DEFAULT_SETTINGS.theme,
|
||||
language: DEFAULT_SETTINGS.language,
|
||||
fontSize: DEFAULT_SETTINGS.fontSize,
|
||||
enableThinking: DEFAULT_SETTINGS.enableThinking,
|
||||
saveChatHistory: DEFAULT_SETTINGS.saveChatHistory,
|
||||
...updateData,
|
||||
});
|
||||
} else {
|
||||
@ -142,27 +196,15 @@ export async function PUT(request: Request) {
|
||||
await db
|
||||
.update(userSettings)
|
||||
.set(updateData)
|
||||
.where(eq(userSettings.id, 1));
|
||||
.where(eq(userSettings.userId, user.userId));
|
||||
}
|
||||
|
||||
// 返回更新后的设置(不包含 API Key)
|
||||
// 4. 返回更新后的设置(不包含 API Key)
|
||||
const updatedSettings = await db.query.userSettings.findFirst({
|
||||
where: eq(userSettings.id, 1),
|
||||
where: eq(userSettings.userId, user.userId),
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
cchUrl: updatedSettings?.cchUrl,
|
||||
cchApiKeyConfigured: updatedSettings?.cchApiKeyConfigured,
|
||||
defaultModel: updatedSettings?.defaultModel,
|
||||
defaultTools: updatedSettings?.defaultTools,
|
||||
systemPrompt: updatedSettings?.systemPrompt || '',
|
||||
temperature: updatedSettings?.temperature || '0.7',
|
||||
theme: updatedSettings?.theme,
|
||||
language: updatedSettings?.language,
|
||||
fontSize: updatedSettings?.fontSize || 15,
|
||||
enableThinking: updatedSettings?.enableThinking,
|
||||
saveChatHistory: updatedSettings?.saveChatHistory,
|
||||
});
|
||||
return NextResponse.json(formatSettingsResponse(updatedSettings ?? null));
|
||||
} catch (error) {
|
||||
console.error('Failed to update settings:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user