170 lines
6.1 KiB
TypeScript
170 lines
6.1 KiB
TypeScript
import { sql } from "drizzle-orm";
|
|
import { messages } from "~~/drizzle/schema";
|
|
import { db } from "~~/server/lib/db";
|
|
import { topicEvents } from "~~/server/utils/events";
|
|
|
|
async function deeplyDeleteMessage(messageId: string, topicId: string, userId: string) {
|
|
const children = await db.query.messages.findMany({
|
|
where: {
|
|
parentMessageId: messageId,
|
|
userId,
|
|
}
|
|
} as any);
|
|
|
|
for (const child of children) {
|
|
await deeplyDeleteMessage(child.id, topicId, userId);
|
|
}
|
|
|
|
await db.delete(messages).where(sql`${messages.id} = ${messageId} AND ${messages.userId} = ${userId}`);
|
|
|
|
topicEvents.emit(topicId, {
|
|
type: 'MESSAGE_DELETED',
|
|
payload: { id: messageId },
|
|
});
|
|
}
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
await protectRoute(event);
|
|
|
|
const userId = event.context.user!.id;
|
|
const messageId = getRouterParam(event, 'messageId')!;
|
|
|
|
const message = await db.query.messages.findFirst({
|
|
where: {
|
|
id: messageId,
|
|
userId,
|
|
}
|
|
} as any);
|
|
|
|
if (!message) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: 'Invalid message',
|
|
});
|
|
}
|
|
|
|
const topicId = message.topicId;
|
|
|
|
const allTopicMessages = await db.query.messages.findMany({
|
|
where: {
|
|
topicId,
|
|
userId,
|
|
},
|
|
orderBy: {
|
|
createdAt: 'asc',
|
|
},
|
|
});
|
|
|
|
const messagesMap = new Map(allTopicMessages.map(m => [m.id, { ...m, children: [] as typeof m[] }]));
|
|
|
|
for (const msg of messagesMap.values()) {
|
|
if (msg.parentMessageId && messagesMap.has(msg.parentMessageId)) {
|
|
messagesMap.get(msg.parentMessageId)!.children.push(msg);
|
|
}
|
|
}
|
|
|
|
const targetMessage = messagesMap.get(messageId);
|
|
if (!targetMessage) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: 'Invalid message',
|
|
});
|
|
}
|
|
|
|
if (targetMessage.role === 'user') {
|
|
await deeplyDeleteMessage(targetMessage.id, topicId, userId);
|
|
return { ok: true };
|
|
}
|
|
|
|
if (targetMessage.parentMessageId && messagesMap.has(targetMessage.parentMessageId)) {
|
|
const parent = messagesMap.get(targetMessage.parentMessageId)!;
|
|
await deeplyDeleteMessage(targetMessage.id, topicId, userId);
|
|
|
|
const remainingChildren = parent.children.filter((child) => {
|
|
return child.id !== targetMessage.id;
|
|
});
|
|
|
|
if (parent.deleted === true && remainingChildren.length === 0) {
|
|
await deeplyDeleteMessage(parent.id, topicId, userId);
|
|
} else if (parent.activeChildId === targetMessage.id) {
|
|
const nextActiveChildId = remainingChildren.length > 0
|
|
? (parent.deleted ? remainingChildren[0]!.id : remainingChildren[remainingChildren.length - 1]!.id)
|
|
: null;
|
|
await db.update(messages).set({ activeChildId: nextActiveChildId }).where(sql`${messages.id} = ${parent.id} AND ${messages.userId} = ${userId}`);
|
|
topicEvents.emit(topicId, {
|
|
type: 'MESSAGE_UPDATED',
|
|
payload: { ...parent, activeChildId: nextActiveChildId },
|
|
});
|
|
}
|
|
return { ok: true };
|
|
}
|
|
|
|
if (targetMessage.deleted === true) {
|
|
const childMessage = targetMessage.activeChildId
|
|
? targetMessage.children.find((c) => { return c.id === targetMessage.activeChildId; })
|
|
: targetMessage.children[0];
|
|
|
|
if (childMessage) {
|
|
await deeplyDeleteMessage(childMessage.id, topicId, userId);
|
|
const remainingChildren = targetMessage.children.filter((child) => {
|
|
return child.id !== childMessage.id;
|
|
});
|
|
if (remainingChildren.length === 0) {
|
|
await deeplyDeleteMessage(targetMessage.id, topicId, userId);
|
|
} else if (targetMessage.activeChildId === childMessage.id) {
|
|
const nextActiveChildId = remainingChildren[0]!.id;
|
|
await db.update(messages).set({ activeChildId: nextActiveChildId }).where(sql`${messages.id} = ${targetMessage.id} AND ${messages.userId} = ${userId}`);
|
|
topicEvents.emit(topicId, {
|
|
type: 'MESSAGE_UPDATED',
|
|
payload: { ...targetMessage, activeChildId: nextActiveChildId },
|
|
});
|
|
}
|
|
} else {
|
|
await deeplyDeleteMessage(targetMessage.id, topicId, userId);
|
|
}
|
|
return { ok: true };
|
|
}
|
|
|
|
if (
|
|
targetMessage.activeChildId
|
|
&& targetMessage.children.length > 0
|
|
) {
|
|
const childMessage = targetMessage.children.find((c) => {
|
|
return c.id === targetMessage.activeChildId;
|
|
});
|
|
if (childMessage) {
|
|
await deeplyDeleteMessage(childMessage.id, topicId, userId);
|
|
const remainingChildren = targetMessage.children.filter((child) => {
|
|
return child.id !== childMessage.id;
|
|
});
|
|
const nextActiveChildId = remainingChildren.length > 0
|
|
? remainingChildren[remainingChildren.length - 1]!.id
|
|
: null;
|
|
await db.update(messages).set({ activeChildId: nextActiveChildId }).where(sql`${messages.id} = ${targetMessage.id} AND ${messages.userId} = ${userId}`);
|
|
topicEvents.emit(topicId, {
|
|
type: 'MESSAGE_UPDATED',
|
|
payload: { ...targetMessage, activeChildId: nextActiveChildId },
|
|
});
|
|
return { ok: true };
|
|
}
|
|
}
|
|
|
|
if (targetMessage.children.length === 0) {
|
|
await deeplyDeleteMessage(targetMessage.id, topicId, userId);
|
|
return { ok: true };
|
|
}
|
|
|
|
const nextActiveChildId = targetMessage.children[0]?.id ?? null;
|
|
await db.update(messages).set({
|
|
deleted: true,
|
|
activeChildId: nextActiveChildId,
|
|
}).where(sql`${messages.id} = ${targetMessage.id} AND ${messages.userId} = ${userId}`);
|
|
|
|
topicEvents.emit(topicId, {
|
|
type: 'MESSAGE_UPDATED',
|
|
payload: { ...targetMessage, deleted: true, activeChildId: nextActiveChildId },
|
|
});
|
|
|
|
return { ok: true };
|
|
});
|