refactor!: 重新实现最近对话和收藏对话的逻辑 (破坏性变更)
This commit is contained in:
@@ -318,11 +318,11 @@ export default class UserApi extends BaseApi {
|
||||
const user = User.findById(token.author) as User
|
||||
const recentChats = user.getRecentChats()
|
||||
const recentChatsList: any[] = []
|
||||
for (const [chatId, content] of recentChats) {
|
||||
const chat = Chat.findById(chatId)
|
||||
for (const {chat_id, content} of recentChats) {
|
||||
const chat = Chat.findById(chat_id)
|
||||
recentChatsList.push({
|
||||
content,
|
||||
id: chatId,
|
||||
id: chat_id,
|
||||
title: chat?.getTitle(user) || "未知",
|
||||
avatar_file_hash: chat?.getAvatarFileHash(user) ? chat?.getAvatarFileHash(user) : undefined
|
||||
})
|
||||
|
||||
10
server/data/RecentChatBean.ts
Normal file
10
server/data/RecentChatBean.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export default class RecentChatBean {
|
||||
declare count: number
|
||||
/** 最近对话所关联的用户 */
|
||||
declare user_id: string
|
||||
declare chat_id: string
|
||||
declare content: string
|
||||
declare updated_time: number
|
||||
|
||||
[key: string]: unknown
|
||||
}
|
||||
@@ -11,11 +11,10 @@ import UserBean from './UserBean.ts'
|
||||
import FileManager from './FileManager.ts'
|
||||
import { SQLInputValue } from "node:sqlite"
|
||||
import ChatPrivate from "./ChatPrivate.ts"
|
||||
import Chat from "./Chat.ts"
|
||||
import ChatBean from "./ChatBean.ts"
|
||||
import MapJson from "../MapJson.ts"
|
||||
import DataWrongError from '../api/DataWrongError.ts'
|
||||
import UserChatLinker from "./UserChatLinker.ts";
|
||||
import UserChatLinker from "./UserChatLinker.ts"
|
||||
import UserFavouriteChatLinker from "./UserFavouriteChatLinker.ts"
|
||||
import UserRecentChatLinker from "./UserRecentChatLinker.ts"
|
||||
|
||||
type UserBeanKey = keyof UserBean
|
||||
|
||||
@@ -38,8 +37,6 @@ export default class User {
|
||||
/* 用户名 */ username TEXT,
|
||||
/* 昵称 */ nickname TEXT NOT NULL,
|
||||
/* 头像, 可选 */ avatar_file_hash TEXT,
|
||||
/* 对话列表 */ favourite_chats TEXT NOT NULL,
|
||||
/* 最近对话 */ recent_chats TEXT NOT NULL,
|
||||
/* 设置 */ settings TEXT NOT NULL
|
||||
);
|
||||
`)
|
||||
@@ -69,18 +66,14 @@ export default class User {
|
||||
username,
|
||||
nickname,
|
||||
avatar_file_hash,
|
||||
favourite_chats,
|
||||
recent_chats,
|
||||
settings
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);`).run(
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?);`).run(
|
||||
crypto.randomUUID(),
|
||||
password,
|
||||
Date.now(),
|
||||
userName,
|
||||
nickName,
|
||||
null,
|
||||
'[]',
|
||||
JSON.stringify(new Map(), MapJson.replacer),
|
||||
"{}"
|
||||
).lastInsertRowid
|
||||
)[0]
|
||||
@@ -136,37 +129,25 @@ export default class User {
|
||||
this.setAttr("username", userName)
|
||||
}
|
||||
updateRecentChat(chatId: string, content: string) {
|
||||
const map = JSON.parse(this.bean.recent_chats, MapJson.reviver) as Map<string, string>
|
||||
map.delete(chatId)
|
||||
map.set(chatId, content)
|
||||
this.setAttr("recent_chats", JSON.stringify(map, MapJson.replacer))
|
||||
UserRecentChatLinker.updateOrAddRecentChat(this.bean.id, chatId, content)
|
||||
}
|
||||
getRecentChats(): Map<string, string> {
|
||||
try {
|
||||
return JSON.parse(this.bean.recent_chats, MapJson.reviver)
|
||||
} catch (e) {
|
||||
console.log(chalk.yellow(`警告: 最近对话列表解析失敗: ${(e as Error).message}`))
|
||||
return new Map()
|
||||
getRecentChats() {
|
||||
return UserRecentChatLinker.getUserRecentChatBeans(this.bean.id)
|
||||
}
|
||||
|
||||
getFavouriteChats() {
|
||||
return UserFavouriteChatLinker.getUserFavouriteChats(this.bean.id)
|
||||
}
|
||||
addFavouriteChats(chatIds: string[]) {
|
||||
chatIds.forEach((v) => UserFavouriteChatLinker.linkUserAndChat(this.bean.id, v))
|
||||
}
|
||||
removeFavouriteChats(chatIds: string[]) {
|
||||
chatIds.forEach((v) => UserFavouriteChatLinker.unlinkUserAndChat(this.bean.id, v))
|
||||
}
|
||||
addFavouriteChat(chatId: string) {
|
||||
const ls = this.getFavouriteChats()
|
||||
if (ls.indexOf(chatId) != -1 || ChatPrivate.getChatIdByUsersId(this.bean.id, this.bean.id) == chatId) return
|
||||
ls.push(chatId)
|
||||
this.setAttr("favourite_chats", JSON.stringify(ls))
|
||||
}
|
||||
removeFavouriteChats(contacts: string[]) {
|
||||
const ls = this.getFavouriteChats().filter((v) => !contacts.includes(v))
|
||||
this.setAttr("favourite_chats", JSON.stringify(ls))
|
||||
}
|
||||
getFavouriteChats() {
|
||||
try {
|
||||
return [...(JSON.parse(this.bean.favourite_chats) as string[]), ChatPrivate.findOrCreateForPrivate(this, this).bean.id]
|
||||
} catch (e) {
|
||||
console.log(chalk.yellow(`警告: 收藏对话解析失败: ${(e as Error).message}`))
|
||||
return []
|
||||
}
|
||||
this.addFavouriteChats([chatId])
|
||||
}
|
||||
|
||||
getAllChatsList() {
|
||||
return UserChatLinker.getUserChats(this.bean.id)
|
||||
}
|
||||
|
||||
57
server/data/UserFavouriteChatLinker.ts
Normal file
57
server/data/UserFavouriteChatLinker.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { DatabaseSync } from "node:sqlite"
|
||||
import path from 'node:path'
|
||||
|
||||
import config from "../config.ts"
|
||||
import { SQLInputValue } from "node:sqlite"
|
||||
|
||||
export default class UserFavouriteChatLinker {
|
||||
static database: DatabaseSync = this.init()
|
||||
|
||||
private static init(): DatabaseSync {
|
||||
const db: DatabaseSync = new DatabaseSync(path.join(config.data_path, 'UserFavouriteChatLinker.db'))
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS UserFavouriteChatLinker (
|
||||
/* 序号 */ count INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
/* 用戶 ID */ user_id TEXT NOT NULL,
|
||||
/* Chat ID */ chat_id TEXT NOT NULL
|
||||
);
|
||||
`)
|
||||
db.exec(`CREATE INDEX IF NOT EXISTS idx_user_id ON UserFavouriteChatLinker(user_id);`)
|
||||
return db
|
||||
}
|
||||
|
||||
/**
|
||||
* 若用户和对话未关联, 则进行关联
|
||||
*/
|
||||
static linkUserAndChat(userId: string, chatId: string) {
|
||||
if (!this.checkUserIsLinkedToChat(userId, chatId))
|
||||
this.database.prepare(`INSERT INTO UserFavouriteChatLinker (
|
||||
user_id,
|
||||
chat_id
|
||||
) VALUES (?, ?);`).run(
|
||||
userId,
|
||||
chatId
|
||||
)
|
||||
}
|
||||
/**
|
||||
* 解除用户和对话的关联
|
||||
*/
|
||||
static unlinkUserAndChat(userId: string, chatId: string) {
|
||||
this.database.prepare(`DELETE FROM UserFavouriteChatLinker 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 getUserFavouriteChats(userId: string) {
|
||||
return this.findAllByCondition('user_id = ?', userId).map((v) => v.chat_id) as string[]
|
||||
}
|
||||
protected static findAllByCondition(condition: string, ...args: SQLInputValue[]) {
|
||||
return this.database.prepare(`SELECT * FROM UserFavouriteChatLinker WHERE ${condition}`).all(...args)
|
||||
}
|
||||
}
|
||||
71
server/data/UserRecentChatLinker.ts
Normal file
71
server/data/UserRecentChatLinker.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { DatabaseSync } from "node:sqlite"
|
||||
import path from 'node:path'
|
||||
|
||||
import RecentChatBean from './RecentChatBean.ts'
|
||||
import config from "../config.ts"
|
||||
import { SQLInputValue } from "node:sqlite"
|
||||
|
||||
export default class UserRecentChatLinker {
|
||||
static database: DatabaseSync = this.init()
|
||||
|
||||
private static init(): DatabaseSync {
|
||||
const db: DatabaseSync = new DatabaseSync(path.join(config.data_path, 'UserRecentChatLinker.db'))
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS UserRecentChatLinker (
|
||||
/* 序号 */ count INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
/* 用戶 ID */ user_id TEXT NOT NULL,
|
||||
/* Chat ID */ chat_id TEXT NOT NULL,
|
||||
/* Last Message Content */ content TEXT NOT NULL,
|
||||
/* Last Update Time */ updated_time INT8 NOT NULL
|
||||
);
|
||||
`)
|
||||
db.exec(`CREATE INDEX IF NOT EXISTS idx_user_id ON UserRecentChatLinker(user_id);`)
|
||||
return db
|
||||
}
|
||||
|
||||
/**
|
||||
* 若用户和对话未关联, 则进行关联
|
||||
*/
|
||||
static updateOrAddRecentChat(userId: string, chatId: string, content: string) {
|
||||
if (!this.checkUserIsLinkedToChat(userId, chatId))
|
||||
this.database.prepare(`INSERT INTO UserRecentChatLinker (
|
||||
user_id,
|
||||
chat_id,
|
||||
content,
|
||||
updated_time
|
||||
) VALUES (?, ?, ?, ?);`).run(
|
||||
userId,
|
||||
chatId,
|
||||
content,
|
||||
Date.now()
|
||||
)
|
||||
else
|
||||
this.database.prepare('UPDATE UserRecentChatLinker SET content = ?, updated_time = ? WHERE count = ?').run(
|
||||
content,
|
||||
Date.now(),
|
||||
/* 既然已经 bind 了, 那么就不需要判断了? */
|
||||
this.findAllByCondition('user_id = ? AND chat_id = ?', userId, chatId)[0].count
|
||||
)
|
||||
}
|
||||
/**
|
||||
* 解除用户和对话的关联
|
||||
*/
|
||||
static removeRecentChat(userId: string, chatId: string) {
|
||||
this.database.prepare(`DELETE FROM UserRecentChatLinker 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 getUserRecentChatBeans(userId: string) {
|
||||
return this.findAllByCondition('user_id = ? ORDER BY updated_time DESC', userId) as unknown as RecentChatBean[]
|
||||
}
|
||||
protected static findAllByCondition(condition: string, ...args: SQLInputValue[]) {
|
||||
return this.database.prepare(`SELECT * FROM UserRecentChatLinker WHERE ${condition}`).all(...args)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user