feat(API): 对话接口添加用户数据隔离
- 获取对话列表时按用户过滤 - 创建对话时关联当前用户 - 删除对话时验证所有权 - 所有对话操作需要登录认证
This commit is contained in:
parent
bfbeef726d
commit
a7e846d733
@ -1,7 +1,8 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { db } from '@/drizzle/db';
|
||||
import { conversations, messages } from '@/drizzle/schema';
|
||||
import { eq, asc } from 'drizzle-orm';
|
||||
import { eq, asc, and } from 'drizzle-orm';
|
||||
import { getCurrentUser } from '@/lib/auth';
|
||||
|
||||
interface RouteParams {
|
||||
params: Promise<{ id: string }>;
|
||||
@ -10,10 +11,22 @@ interface RouteParams {
|
||||
// GET /api/conversations/[id] - 获取单个对话及其消息
|
||||
export async function GET(request: Request, { params }: RouteParams) {
|
||||
try {
|
||||
// 获取当前用户
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
return NextResponse.json(
|
||||
{ error: '未登录' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
|
||||
const conversation = await db.query.conversations.findFirst({
|
||||
where: eq(conversations.conversationId, id),
|
||||
where: and(
|
||||
eq(conversations.conversationId, id),
|
||||
eq(conversations.userId, user.userId)
|
||||
),
|
||||
});
|
||||
|
||||
if (!conversation) {
|
||||
@ -44,10 +57,34 @@ export async function GET(request: Request, { params }: RouteParams) {
|
||||
// PUT /api/conversations/[id] - 更新对话
|
||||
export async function PUT(request: Request, { params }: RouteParams) {
|
||||
try {
|
||||
// 获取当前用户
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
return NextResponse.json(
|
||||
{ error: '未登录' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
const body = await request.json();
|
||||
const { title, isPinned, isArchived } = body;
|
||||
|
||||
// 验证对话属于当前用户
|
||||
const existingConversation = await db.query.conversations.findFirst({
|
||||
where: and(
|
||||
eq(conversations.conversationId, id),
|
||||
eq(conversations.userId, user.userId)
|
||||
),
|
||||
});
|
||||
|
||||
if (!existingConversation) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Conversation not found' },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
const updateData: Record<string, unknown> = {
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
@ -70,13 +107,6 @@ export async function PUT(request: Request, { params }: RouteParams) {
|
||||
.where(eq(conversations.conversationId, id))
|
||||
.returning();
|
||||
|
||||
if (!updated) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Conversation not found' },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json(updated);
|
||||
} catch (error) {
|
||||
console.error('Failed to update conversation:', error);
|
||||
@ -90,24 +120,40 @@ export async function PUT(request: Request, { params }: RouteParams) {
|
||||
// DELETE /api/conversations/[id] - 删除对话
|
||||
export async function DELETE(request: Request, { params }: RouteParams) {
|
||||
try {
|
||||
// 获取当前用户
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
return NextResponse.json(
|
||||
{ error: '未登录' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
|
||||
// 先删除相关消息
|
||||
await db.delete(messages).where(eq(messages.conversationId, id));
|
||||
// 验证对话属于当前用户
|
||||
const existingConversation = await db.query.conversations.findFirst({
|
||||
where: and(
|
||||
eq(conversations.conversationId, id),
|
||||
eq(conversations.userId, user.userId)
|
||||
),
|
||||
});
|
||||
|
||||
// 再删除对话
|
||||
const [deleted] = await db
|
||||
.delete(conversations)
|
||||
.where(eq(conversations.conversationId, id))
|
||||
.returning();
|
||||
|
||||
if (!deleted) {
|
||||
if (!existingConversation) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Conversation not found' },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
// 先删除相关消息
|
||||
await db.delete(messages).where(eq(messages.conversationId, id));
|
||||
|
||||
// 再删除对话
|
||||
await db
|
||||
.delete(conversations)
|
||||
.where(eq(conversations.conversationId, id));
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error('Failed to delete conversation:', error);
|
||||
|
||||
@ -1,24 +1,48 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { db } from '@/drizzle/db';
|
||||
import { conversations, messages } from '@/drizzle/schema';
|
||||
import { sql } from 'drizzle-orm';
|
||||
import { sql, eq, inArray } from 'drizzle-orm';
|
||||
import { getCurrentUser } from '@/lib/auth';
|
||||
|
||||
// GET /api/conversations/all - 获取统计信息
|
||||
// GET /api/conversations/all - 获取当前用户的统计信息
|
||||
export async function GET() {
|
||||
try {
|
||||
// 获取对话数量
|
||||
// 获取当前用户
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
return NextResponse.json(
|
||||
{ error: '未登录' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
// 获取当前用户的对话数量
|
||||
const conversationCount = await db
|
||||
.select({ count: sql<number>`count(*)` })
|
||||
.from(conversations);
|
||||
.from(conversations)
|
||||
.where(eq(conversations.userId, user.userId));
|
||||
|
||||
// 获取消息数量
|
||||
const messageCount = await db
|
||||
.select({ count: sql<number>`count(*)` })
|
||||
.from(messages);
|
||||
// 获取当前用户的对话 ID 列表
|
||||
const userConversations = await db
|
||||
.select({ conversationId: conversations.conversationId })
|
||||
.from(conversations)
|
||||
.where(eq(conversations.userId, user.userId));
|
||||
|
||||
const conversationIds = userConversations.map(c => c.conversationId);
|
||||
|
||||
// 获取当前用户的消息数量
|
||||
let messageCountValue = 0;
|
||||
if (conversationIds.length > 0) {
|
||||
const messageCount = await db
|
||||
.select({ count: sql<number>`count(*)` })
|
||||
.from(messages)
|
||||
.where(inArray(messages.conversationId, conversationIds));
|
||||
messageCountValue = Number(messageCount[0]?.count || 0);
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
conversationCount: Number(conversationCount[0]?.count || 0),
|
||||
messageCount: Number(messageCount[0]?.count || 0),
|
||||
messageCount: messageCountValue,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to get stats:', error);
|
||||
@ -29,18 +53,37 @@ export async function GET() {
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE /api/conversations/all - 清除所有对话和消息
|
||||
// DELETE /api/conversations/all - 清除当前用户的所有对话和消息
|
||||
export async function DELETE() {
|
||||
try {
|
||||
// 先删除所有消息
|
||||
await db.delete(messages);
|
||||
// 获取当前用户
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
return NextResponse.json(
|
||||
{ error: '未登录' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
// 再删除所有对话
|
||||
await db.delete(conversations);
|
||||
// 获取当前用户的所有对话 ID
|
||||
const userConversations = await db
|
||||
.select({ conversationId: conversations.conversationId })
|
||||
.from(conversations)
|
||||
.where(eq(conversations.userId, user.userId));
|
||||
|
||||
const conversationIds = userConversations.map(c => c.conversationId);
|
||||
|
||||
if (conversationIds.length > 0) {
|
||||
// 删除当前用户对话相关的所有消息
|
||||
await db.delete(messages).where(inArray(messages.conversationId, conversationIds));
|
||||
|
||||
// 删除当前用户的所有对话
|
||||
await db.delete(conversations).where(eq(conversations.userId, user.userId));
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'All conversations and messages have been deleted',
|
||||
message: 'All your conversations and messages have been deleted',
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to delete all conversations:', error);
|
||||
|
||||
@ -1,14 +1,27 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { db } from '@/drizzle/db';
|
||||
import { conversations, messages } from '@/drizzle/schema';
|
||||
import { desc, eq } from 'drizzle-orm';
|
||||
import { desc, eq, and } from 'drizzle-orm';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { getCurrentUser } from '@/lib/auth';
|
||||
|
||||
// GET /api/conversations - 获取对话列表
|
||||
// GET /api/conversations - 获取当前用户的对话列表
|
||||
export async function GET() {
|
||||
try {
|
||||
// 获取当前用户
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
return NextResponse.json(
|
||||
{ error: '未登录' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const conversationList = await db.query.conversations.findMany({
|
||||
where: eq(conversations.isArchived, false),
|
||||
where: and(
|
||||
eq(conversations.isArchived, false),
|
||||
eq(conversations.userId, user.userId)
|
||||
),
|
||||
orderBy: [desc(conversations.lastMessageAt)],
|
||||
});
|
||||
|
||||
@ -25,6 +38,15 @@ export async function GET() {
|
||||
// POST /api/conversations - 创建新对话
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
// 获取当前用户
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
return NextResponse.json(
|
||||
{ error: '未登录' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { title, model, tools, enableThinking } = body;
|
||||
|
||||
@ -38,6 +60,7 @@ export async function POST(request: Request) {
|
||||
model: model || 'claude-sonnet-4-20250514',
|
||||
tools: tools || [],
|
||||
enableThinking: enableThinking || false,
|
||||
userId: user.userId, // 关联当前用户
|
||||
})
|
||||
.returning();
|
||||
|
||||
@ -54,6 +77,15 @@ export async function POST(request: Request) {
|
||||
// DELETE /api/conversations - 批量删除对话
|
||||
export async function DELETE(request: Request) {
|
||||
try {
|
||||
// 获取当前用户
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
return NextResponse.json(
|
||||
{ error: '未登录' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { conversationIds } = body;
|
||||
|
||||
@ -64,10 +96,22 @@ export async function DELETE(request: Request) {
|
||||
);
|
||||
}
|
||||
|
||||
// 删除相关消息
|
||||
// 删除相关消息和对话(只删除属于当前用户的)
|
||||
for (const id of conversationIds) {
|
||||
await db.delete(messages).where(eq(messages.conversationId, id));
|
||||
await db.delete(conversations).where(eq(conversations.conversationId, id));
|
||||
// 先验证对话属于当前用户
|
||||
const [conv] = await db
|
||||
.select()
|
||||
.from(conversations)
|
||||
.where(and(
|
||||
eq(conversations.conversationId, id),
|
||||
eq(conversations.userId, user.userId)
|
||||
))
|
||||
.limit(1);
|
||||
|
||||
if (conv) {
|
||||
await db.delete(messages).where(eq(messages.conversationId, id));
|
||||
await db.delete(conversations).where(eq(conversations.conversationId, id));
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
|
||||
Loading…
Reference in New Issue
Block a user