From 5d5b04ba05252db06fc6b26b6946bb4faac79749 Mon Sep 17 00:00:00 2001 From: CrescentLeaf Date: Tue, 23 Sep 2025 09:20:30 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=A7=8B=20=E5=B0=8D?= =?UTF-8?q?=E8=A9=B1=20=E6=88=90=E5=93=A1=E7=9A=84=E5=84=B2=E5=AD=98?= =?UTF-8?q?=E9=82=8F=E8=BC=AF=20*=20=E4=BD=BF=E7=94=A8=E9=97=9C=E8=81=AF?= =?UTF-8?q?=E8=B3=87=E6=96=99=E5=BA=AB,=20=E9=8F=88=E6=8E=A5=20user=5Fid?= =?UTF-8?q?=20=E5=92=8C=20chat=5Fid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/data/Chat.ts | 21 +++++---------- server/data/ChatPrivate.ts | 2 +- server/data/UserChatLinker.ts | 50 +++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 15 deletions(-) create mode 100644 server/data/UserChatLinker.ts diff --git a/server/data/Chat.ts b/server/data/Chat.ts index 4033ed2..e4d13ce 100644 --- a/server/data/Chat.ts +++ b/server/data/Chat.ts @@ -8,6 +8,7 @@ import { SQLInputValue } from "node:sqlite" import chalk from "chalk" import User from "./User.ts" import ChatType from "./ChatType.ts" +import UserChatLinker from "./UserChatLinker.ts" /** * Chat.ts - Wrapper and manager @@ -55,14 +56,12 @@ export default class Chat { id, title, avatar, - members_list, settings - ) VALUES (?, ?, ?, ?, ?, ?);`).run( + ) VALUES (?, ?, ?, ?, ?);`).run( type, chatId, null, null, - "[]", "{}" ).lastInsertRowid )[0] @@ -80,19 +79,13 @@ export default class Chat { } getMembersList() { - return JSON.parse(this.bean.members_list) as string[] + return UserChatLinker.getChatMembers(this.bean.id) } - addMember(userId: string) { - const ls = this.getMembersList() - ls.push(userId) - this.setMembers(ls) + addMembers(userIds: string[]) { + userIds.forEach((v) => UserChatLinker.linkUserAndChat(v, this.bean.id)) } - setMembers(members: string[]) { - this.setAttr("members_list", JSON.stringify(members)) - } - removeMembers(members: string[]) { - const ls = this.getMembersList().filter((v) => !members.includes(v)) - this.setAttr("members_list", JSON.stringify(ls)) + removeMembers(userIds: string[]) { + userIds.forEach((v) => UserChatLinker.unlinkUserAndChat(v, this.bean.id)) } getAnotherUserForPrivate(userMySelf: User) { const user_a_id = this.getMembersList()[0] diff --git a/server/data/ChatPrivate.ts b/server/data/ChatPrivate.ts index 28889e5..09d1777 100644 --- a/server/data/ChatPrivate.ts +++ b/server/data/ChatPrivate.ts @@ -13,7 +13,7 @@ export default class ChatPrivate extends Chat { static createForPrivate(userA: User, userB: User) { const chat = this.create(this.getChatIdByUsersId(userA.bean.id, userB.bean.id), 'private') - chat.setMembers([ + chat.addMembers([ userA.bean.id, userB.bean.id ]) diff --git a/server/data/UserChatLinker.ts b/server/data/UserChatLinker.ts new file mode 100644 index 0000000..0204a23 --- /dev/null +++ b/server/data/UserChatLinker.ts @@ -0,0 +1,50 @@ +import { DatabaseSync } from "node:sqlite" +import path from 'node:path' + +import config from "../config.ts" +import { SQLInputValue } from "node:sqlite"; +export default class UserChatLinker { + static database: DatabaseSync = this.init() + + private static init(): DatabaseSync { + const db: DatabaseSync = new DatabaseSync(path.join(config.data_path, 'UserChatLinker.db')) + db.exec(` + CREATE TABLE IF NOT EXISTS UserChatLinker ( + /* 序号 */ count INTEGER PRIMARY KEY AUTOINCREMENT, + /* 用戶 ID */ user_id TEXT NOT NULL, + /* Chat ID */ chat_id TEXT NOT NULL + ); + `) + return db + } + + /** + * 對用戶和對話建立關聯 + * 自動檢測是否已關聯, 保證不會重複 + */ + static linkUserAndChat(userId: string, chatId: string) { + if (!this.checkUserIsLinkedToChat(userId, chatId)) + this.database.prepare(`INSERT INTO UserChatLinker ( + user_id, + chat_id + ) VALUES (?, ?);`).run( + userId, + chatId + ) + } + static unlinkUserAndChat(userId: string, chatId: string) { + this.database.prepare(`DELETE FROM UserChatLinker WHERE user_id = ? AND chat_id = ?`).run(userId, chatId) + } + static checkUserIsLinkedToChat(userId: string, chatId: string) { + return this.findAllByCondition('user_id = ? AND chat_id = ?', userId, chatId).length != 0 + } + static getUserChats(userId: string) { + return this.findAllByCondition('user_id = ?', userId).map((v) => v.chat_id) as string[] + } + static getChatMembers(chatId: string) { + return this.findAllByCondition('chat_id = ?', chatId).map((v) => v.user_id) as string[] + } + protected static findAllByCondition(condition: string, ...args: SQLInputValue[]) { + return this.database.prepare(`SELECT * FROM UserChatLinker WHERE ${condition}`).all(...args) + } +}