From 200f5fd0aaa399a1317861bcd1190f092f339e45 Mon Sep 17 00:00:00 2001 From: CrescentLeaf Date: Sat, 17 Jan 2026 00:59:11 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E5=90=8E=E7=AB=AF=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/data/Chat.ts | 24 +++++++++++++++++++++++- server/data/ChatGroup.ts | 16 ++++++++++++++++ server/data/ChatPrivate.ts | 21 +++++++++++++++++++++ server/data/FileManager.ts | 9 +++++++++ server/data/MessagesManager.ts | 4 ++++ server/data/User.ts | 11 +++++++++++ server/data/UserChatLinker.ts | 15 +++++++++++++-- 7 files changed, 97 insertions(+), 3 deletions(-) diff --git a/server/data/Chat.ts b/server/data/Chat.ts index 7fa7ace..a8486bf 100644 --- a/server/data/Chat.ts +++ b/server/data/Chat.ts @@ -59,8 +59,13 @@ export default class Chat { return new Chat(beans[0]) } + /** + * 对话创建基本方法 + * @param chatName 对话别名, 供查询 + * @param type 对话类型 + */ static create(chatName: string | undefined, type: ChatType) { - if (this.findAllChatBeansByCondition('id = ?', chatName || null).length > 0) + if (this.findAllChatBeansByCondition('name = ?', chatName || null).length > 0) throw new DataWrongError(`对话名称 ${chatName} 已被使用`) const chat = new Chat( Chat.findAllChatBeansByCondition( @@ -123,6 +128,11 @@ export default class Chat { * ====================================================== */ + /** + * 添加加入请求 + * @param userId + * @param reason + */ addJoinRequest(userId: string, reason?: string) { if (this.findAllJoinRequestsByCondition('user_id = ?', userId).length == 0) Chat.database.prepare(`INSERT INTO ${this.getJoinRequestsTableName()} ( @@ -149,6 +159,11 @@ export default class Chat { * ====================================================== */ + /** + * 添加对话管理员 + * @param userId + * @param permission + */ addAdmin(userId: string, permission: string[] | string) { if (!this.checkUserIsAdmin(userId)) Chat.database.prepare(`INSERT INTO ${this.getAdminsTableName()} ( @@ -185,6 +200,9 @@ export default class Chat { * ====================================================== */ + /** + * 获取对话成员 + */ getMembersList() { return UserChatLinker.getChatMembers(this.bean.id) } @@ -201,6 +219,10 @@ export default class Chat { * ====================================================== */ + /** + * 从**私聊**中获取对方用户 + * @param userMySelf + */ getAnotherUserForPrivate(userMySelf: User) { const members = this.getMembersList() const user_a_id = members[0] diff --git a/server/data/ChatGroup.ts b/server/data/ChatGroup.ts index 4a02ed9..173672c 100644 --- a/server/data/ChatGroup.ts +++ b/server/data/ChatGroup.ts @@ -11,6 +11,10 @@ class GroupSettings { this.settings = JSON.parse(chat.bean.settings) } + /** + * 覆盖群组设定 + * @param bean 要覆盖的设定, 不需要覆盖的不需要填入 + */ update(bean: GroupSettingsBean) { const updateValue = (key: string) => { if (key in bean) @@ -26,6 +30,9 @@ class GroupSettings { this.apply() } + /** + * 应用更改 + */ apply() { this.chat.setAttr('settings', JSON.stringify(this.settings)) } @@ -36,10 +43,19 @@ export default class ChatGroup extends Chat { return new GroupSettings(this) } + /** + * 确保是群组类型后, 转换成群组对话 + * 唯一的作用可能是修改群组设定 + * @param chat + */ static fromChat(chat: Chat) { return new ChatGroup(chat.bean) } + /** + * 创建新的群组 + * @param group_name 群组名称 + */ static createGroup(group_name?: string) { return this.create(group_name, 'group') } diff --git a/server/data/ChatPrivate.ts b/server/data/ChatPrivate.ts index c7c44de..2b1b5e6 100644 --- a/server/data/ChatPrivate.ts +++ b/server/data/ChatPrivate.ts @@ -3,6 +3,12 @@ import Chat from "./Chat.ts" import User from "./User.ts" export default class ChatPrivate extends Chat { + /** + * 确保是私聊类型后, 转换成私聊对话 + * 实际上没啥用, 因为实例方法都在 Chat + * 未来可能会移除 + * @param chat + */ static fromChat(chat: Chat) { return new ChatPrivate(chat.bean) } @@ -11,6 +17,11 @@ export default class ChatPrivate extends Chat { return 'priv_' + [userIdA, userIdB].sort().join('__').replaceAll('-', '_') } + /** + * 为两个用户创建对话 (无需注意顺序) + * @param userA + * @param userB + */ static createForPrivate(userA: User, userB: User) { const chat = this.create(undefined, 'private') chat.setAttr('id', this.getChatIdByUsersId(userA.bean.id, userB.bean.id)) @@ -19,11 +30,21 @@ export default class ChatPrivate extends Chat { userB.bean.id ]) } + /** + * 寻找两个用户间的对话 (无需注意顺序) + * @param userA + * @param userB + */ static findByUsersForPrivate(userA: User, userB: User) { const chat = this.findById(this.getChatIdByUsersId(userA.bean.id, userB.bean.id)) if (chat) return this.fromChat(chat as Chat) } + /** + * 寻找两个用户间的对话, 若无则创建 (无需注意顺序) + * @param userA + * @param userB + */ static findOrCreateForPrivate(userA: User, userB: User) { let a = this.findByUsersForPrivate(userA, userB) if (a == null) { diff --git a/server/data/FileManager.ts b/server/data/FileManager.ts index ab0f701..cba170e 100644 --- a/server/data/FileManager.ts +++ b/server/data/FileManager.ts @@ -36,6 +36,9 @@ class File { getName() { return this.bean.name } + /** + * 获取文件的相对路径 + */ getFilePath() { const hash = this.bean.hash return path.join( @@ -90,6 +93,12 @@ export default class FileManager { return db } + /** + * 上传文件 (与 HTTP API 对接) + * @param fileName 文件名 + * @param data 文件二进制数据 + * @param chatId 所属的对话 + */ static async uploadFile(fileName: string, data: Buffer, chatId?: string) { const hash = crypto.createHash('sha256').update(data).digest('hex') const file = FileManager.findByHash(hash) diff --git a/server/data/MessagesManager.ts b/server/data/MessagesManager.ts index f916db3..e8566de 100644 --- a/server/data/MessagesManager.ts +++ b/server/data/MessagesManager.ts @@ -16,6 +16,10 @@ export default class MessagesManager { return db } + /** + * 为对话获取实例 + * @param chat 对话 + */ static getInstanceForChat(chat: Chat) { return new MessagesManager(chat) } diff --git a/server/data/User.ts b/server/data/User.ts index 0e0b59f..851e82d 100644 --- a/server/data/User.ts +++ b/server/data/User.ts @@ -49,6 +49,13 @@ export default class User { return db } + /** + * 检查用户名是否存在, 不存在则创建用户, 否则报错 + * @param userName + * @param password + * @param nickName + * @param avatar + */ static create(userName: string | null, password: string, nickName: string, avatar: Buffer | null) { if (userName && User.findAllBeansByCondition('username = ?', userName).length > 0) throw new DataWrongError(`用户名 ${userName} 已存在`) @@ -102,6 +109,10 @@ export default class User { console.error(chalk.red(`警告: 查询 username = ${userName} 时, 查询到多个相同用户名的用户`)) return new User(beans[0]) } + /** + * 通过用户名或 ID 获取某个用户, 用户名优先 + * @param account 用户名或用户 ID + */ static findByAccount(account: string) { return User.findByUserName(account) || User.findById(account) } diff --git a/server/data/UserChatLinker.ts b/server/data/UserChatLinker.ts index da2f98b..8b96bd0 100644 --- a/server/data/UserChatLinker.ts +++ b/server/data/UserChatLinker.ts @@ -21,8 +21,7 @@ export default class UserChatLinker { } /** - * 對用戶和對話建立關聯 - * 自動檢測是否已關聯, 保證不會重複 + * 若用户和对话未关联, 则进行关联 */ static linkUserAndChat(userId: string, chatId: string) { if (!this.checkUserIsLinkedToChat(userId, chatId)) @@ -34,15 +33,27 @@ export default class UserChatLinker { 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[] }