This commit is contained in:
Baobhan Sith
2025-04-19 21:10:04 +08:00
parent 283fa02a18
commit d6cb9f1846
7 changed files with 276 additions and 117 deletions
@@ -12,7 +12,7 @@ export const settingsRepository = {
return new Promise((resolve, reject) => {
db.all('SELECT key, value FROM settings', (err: any, rows: Setting[]) => { // 添加 err 类型
if (err) {
console.error('获取所有设置时出错:', err); // 更新日志为中文
console.error('[Repository] 获取所有设置时出错:', err); // 更新日志为中文
reject(new Error('获取设置失败')); // 更新错误消息为中文
} else {
resolve(rows);
@@ -23,11 +23,13 @@ export const settingsRepository = {
async getSetting(key: string): Promise<string | null> {
return new Promise((resolve, reject) => {
console.log(`[Repository] Attempting to get setting with key: ${key}`); // +++ 添加日志 +++
db.get('SELECT value FROM settings WHERE key = ?', [key], (err: any, row: { value: string } | undefined) => { // 添加 err 类型
if (err) {
console.error(`获取设置项 ${key} 时出错:`, err); // 更新日志为中文
console.error(`[Repository] 获取设置项 ${key} 时出错:`, err); // 更新日志为中文
reject(new Error(`获取设置项 ${key} 失败`)); // 更新错误消息为中文
} else {
console.log(`[Repository] Found value for key ${key}:`, row ? row.value : null); // +++ 添加日志 +++
resolve(row ? row.value : null);
}
});
@@ -37,18 +39,26 @@ export const settingsRepository = {
async setSetting(key: string, value: string): Promise<void> {
return new Promise((resolve, reject) => {
const now = Math.floor(Date.now() / 1000); // 获取当前 Unix 时间戳
db.run(
`INSERT INTO settings (key, value, created_at, updated_at)
VALUES (?, ?, ?, ?)
ON CONFLICT(key) DO UPDATE SET
const sql = `INSERT INTO settings (key, value, created_at, updated_at)
VALUES (?, ?, ?, ?)
ON CONFLICT(key) DO UPDATE SET
value = excluded.value,
updated_at = excluded.updated_at`,
[key, value, now, now],
function (err: any) { // 添加 err 类型
updated_at = excluded.updated_at`;
const params = [key, value, now, now];
console.log(`[Repository] Attempting to set setting. Key: ${key}, Value: ${value}`); // +++ 添加日志 +++
console.log(`[Repository] Executing SQL: ${sql} with params: ${JSON.stringify(params)}`); // +++ 添加日志 +++
db.run(
sql,
params,
function (this: any, err: any) { // 使用 this 需要 function 声明, 添加 err 类型
if (err) {
console.error(`设置设置项 ${key} 时出错:`, err); // 更新日志为中文
console.error(`[Repository] 设置设置项 ${key} 时出错:`, err); // 更新日志为中文
reject(new Error(`设置设置项 ${key} 失败`)); // 更新错误消息为中文
} else {
// this.changes 提供了受影响的行数 (对于 INSERT/UPDATE)
console.log(`[Repository] Successfully set setting for key: ${key}. Rows affected: ${this.changes}`); // +++ 添加日志 +++
resolve();
}
}
@@ -58,11 +68,13 @@ export const settingsRepository = {
async deleteSetting(key: string): Promise<void> {
return new Promise((resolve, reject) => {
db.run('DELETE FROM settings WHERE key = ?', [key], function (err: any) { // 添加 err 类型
console.log(`[Repository] Attempting to delete setting with key: ${key}`); // +++ 添加日志 +++
db.run('DELETE FROM settings WHERE key = ?', [key], function (this: any, err: any) { // 添加 err 类型
if (err) {
console.error(`删除设置项 ${key} 时出错:`, err); // 更新日志为中文
console.error(`[Repository] 删除设置项 ${key} 时出错:`, err); // 更新日志为中文
reject(new Error(`删除设置项 ${key} 失败`)); // 更新错误消息为中文
} else {
console.log(`[Repository] Successfully deleted setting for key: ${key}. Rows affected: ${this.changes}`); // +++ 添加日志 +++
resolve();
}
});
@@ -70,9 +82,11 @@ export const settingsRepository = {
},
async setMultipleSettings(settings: Record<string, string>): Promise<void> {
console.log('[Repository] setMultipleSettings called with:', JSON.stringify(settings)); // +++ 添加日志 +++
const promises = Object.entries(settings).map(([key, value]) =>
this.setSetting(key, value)
this.setSetting(key, value) // this 指向 settingsRepository 对象
);
await Promise.all(promises);
console.log('[Repository] setMultipleSettings finished.'); // +++ 添加日志 +++
},
};
@@ -1,6 +1,12 @@
import { settingsRepository, Setting } from '../repositories/settings.repository';
// +++ 定义默认的焦点切换顺序 +++
const DEFAULT_FOCUS_SEQUENCE = ["quickCommandsSearch", "commandHistorySearch", "fileManagerSearch", "commandInput", "terminalSearch"];
const FOCUS_SEQUENCE_KEY = 'focusSwitcherSequence'; // +++ 定义设置键常量 +++
export const settingsService = {
// ... (getAllSettings, getSetting, setSetting, setMultipleSettings, deleteSetting, getIpWhitelistSettings, updateIpWhitelistSettings, getFocusSwitcherSequence 保持不变) ...
/**
* 获取所有设置项
* @returns 返回包含所有设置项的数组
@@ -76,4 +82,57 @@ export const settingsService = {
settingsRepository.setSetting('ipWhitelist', whitelist),
]);
},
// +++ 新增:获取焦点切换顺序 +++
/**
* 获取焦点切换顺序
* @returns 返回存储的焦点切换顺序数组,如果未设置或无效则返回默认顺序
*/
async getFocusSwitcherSequence(): Promise<string[]> {
console.log(`[Service] Attempting to get setting for key: ${FOCUS_SEQUENCE_KEY}`); // +++ 添加日志 +++
try {
const sequenceJson = await settingsRepository.getSetting(FOCUS_SEQUENCE_KEY);
console.log(`[Service] Raw value from repository for ${FOCUS_SEQUENCE_KEY}:`, sequenceJson); // +++ 添加日志 +++
if (sequenceJson) {
const sequence = JSON.parse(sequenceJson);
// 基本验证:确保它是一个数组并且包含字符串
if (Array.isArray(sequence) && sequence.every(item => typeof item === 'string')) {
console.log('[Service] Fetched and validated focus switcher sequence:', JSON.stringify(sequence)); // +++ 更新日志 +++
return sequence;
} else {
console.warn('[Service] Invalid focus switcher sequence format found in settings. Returning default.');
}
} else {
console.log('[Service] No focus switcher sequence found in settings. Returning default.');
}
} catch (error) {
console.error(`[Service] Error parsing focus switcher sequence from settings (key: ${FOCUS_SEQUENCE_KEY}):`, error); // +++ 更新日志 +++
}
// 如果发生错误或未找到/无效,返回默认值
console.log('[Service] Returning default focus sequence:', JSON.stringify(DEFAULT_FOCUS_SEQUENCE)); // +++ 添加日志 +++
return [...DEFAULT_FOCUS_SEQUENCE]; // 返回默认值的副本
},
// +++ 新增:设置焦点切换顺序 +++
/**
* 设置焦点切换顺序
* @param sequence 要保存的焦点切换顺序数组
*/
async setFocusSwitcherSequence(sequence: string[]): Promise<void> {
console.log('[Service] setFocusSwitcherSequence called with:', JSON.stringify(sequence)); // +++ 添加日志 +++
// 基本验证
if (!Array.isArray(sequence) || !sequence.every(item => typeof item === 'string')) {
console.error('[Service] Attempted to save invalid focus switcher sequence format:', sequence);
throw new Error('Invalid sequence format provided.'); // 抛出错误阻止保存无效数据
}
try {
const sequenceJson = JSON.stringify(sequence);
console.log(`[Service] Attempting to save setting. Key: ${FOCUS_SEQUENCE_KEY}, Value: ${sequenceJson}`); // +++ 添加日志 +++
await settingsRepository.setSetting(FOCUS_SEQUENCE_KEY, sequenceJson);
console.log(`[Service] Successfully saved setting for key: ${FOCUS_SEQUENCE_KEY}`); // +++ 添加日志 +++
} catch (error) {
console.error(`[Service] Error calling settingsRepository.setSetting for key ${FOCUS_SEQUENCE_KEY}:`, error); // +++ 更新日志 +++
throw new Error('Failed to save focus switcher sequence.'); // 重新抛出错误
}
},
};
@@ -6,6 +6,8 @@ import { ipBlacklistService } from '../services/ip-blacklist.service'; // 引入
const auditLogService = new AuditLogService(); // 实例化 AuditLogService
export const settingsController = {
// ... (getAllSettings, updateSettings, getFocusSwitcherSequence 保持不变) ...
/**
* 获取所有设置项
*/
@@ -31,11 +33,11 @@ export const settingsController = {
return;
}
// --- 过滤掉外观设置相关的键 ---
// --- 过滤掉外观设置和焦点切换顺序相关的键 ---
const allowedSettingsKeys = [
'language', 'ipWhitelist', 'maxLoginAttempts', 'loginBanDuration',
'showPopupFileEditor', 'shareFileEditorTabs', 'ipWhitelistEnabled' // 添加 ipWhitelistEnabled
// 在这里添加其他允许的通用设置键
'showPopupFileEditor', 'shareFileEditorTabs', 'ipWhitelistEnabled'
// 不在此处处理 'focusSwitcherSequence'
];
const filteredSettings: Record<string, string> = {};
for (const key in settingsToUpdate) {
@@ -51,29 +53,75 @@ export const settingsController = {
}
// 记录审计日志
// 区分 IP 白名单更新和其他设置更新
// 注意:现在审计日志可能需要更精细的逻辑,因为它只记录了实际更新的通用设置
const updatedKeys = Object.keys(filteredSettings); // 使用过滤后的键
if (updatedKeys.length > 0) { // 只有实际更新了才记录
const updatedKeys = Object.keys(filteredSettings);
if (updatedKeys.length > 0) {
if (updatedKeys.includes('ipWhitelist') || updatedKeys.includes('ipWhitelistEnabled')) {
auditLogService.logAction('IP_WHITELIST_UPDATED', { updatedKeys });
} else {
auditLogService.logAction('SETTINGS_UPDATED', { updatedKeys });
}
}
res.status(200).json({ message: '设置已成功更新' }); // 即使没有更新通用设置也返回成功
res.status(200).json({ message: '设置已成功更新' });
} catch (error: any) {
console.error('更新设置时出错:', error);
res.status(500).json({ message: '更新设置失败', error: error.message });
}
},
// 注意:通常不直接通过 API 提供单个设置项的获取、设置或删除,
// 而是通过批量获取/更新来管理。如果需要单独操作,可以添加相应方法。
// 例如:
// async getSetting(req: Request, res: Response): Promise<void> { ... }
// async setSetting(req: Request, res: Response): Promise<void> { ... }
// async deleteSetting(req: Request, res: Response): Promise<void> { ... }
// +++ 新增:获取焦点切换顺序 +++
/**
* 获取焦点切换顺序
*/
async getFocusSwitcherSequence(req: Request, res: Response): Promise<void> {
try {
console.log('[Controller] Received request to get focus switcher sequence.'); // +++ 添加日志 +++
const sequence = await settingsService.getFocusSwitcherSequence();
console.log('[Controller] Sending focus switcher sequence to client:', JSON.stringify(sequence)); // +++ 添加日志 +++
res.json(sequence);
} catch (error: any) {
console.error('[Controller] 获取焦点切换顺序时出错:', error); // +++ 更新日志前缀 +++
res.status(500).json({ message: '获取焦点切换顺序失败', error: error.message });
}
},
// +++ 新增:设置焦点切换顺序 +++
/**
* 设置焦点切换顺序
*/
async setFocusSwitcherSequence(req: Request, res: Response): Promise<void> {
console.log('[Controller] Received request to set focus switcher sequence.'); // +++ 添加日志 +++
try {
const { sequence } = req.body;
console.log('[Controller] Request body sequence:', JSON.stringify(sequence)); // +++ 添加日志 +++
// 输入验证
if (!Array.isArray(sequence) || !sequence.every(item => typeof item === 'string')) {
console.warn('[Controller] Invalid sequence format received:', sequence); // +++ 添加日志 +++
res.status(400).json({ message: '无效的请求体,"sequence" 必须是一个字符串数组' });
return;
}
console.log('[Controller] Calling settingsService.setFocusSwitcherSequence...'); // +++ 添加日志 +++
await settingsService.setFocusSwitcherSequence(sequence);
console.log('[Controller] settingsService.setFocusSwitcherSequence completed successfully.'); // +++ 添加日志 +++
// 记录审计日志 (可选)
console.log('[Controller] Logging audit action: FOCUS_SWITCHER_SEQUENCE_UPDATED'); // +++ 添加日志 +++
auditLogService.logAction('FOCUS_SWITCHER_SEQUENCE_UPDATED', { sequence });
console.log('[Controller] Sending success response.'); // +++ 添加日志 +++
res.status(200).json({ message: '焦点切换顺序已成功更新' });
} catch (error: any) {
console.error('[Controller] 设置焦点切换顺序时出错:', error); // +++ 更新日志前缀 +++
// 区分是服务层抛出的验证错误还是其他错误
if (error.message === 'Invalid sequence format provided.') {
res.status(400).json({ message: '设置焦点切换顺序失败: 无效的格式', error: error.message });
} else {
res.status(500).json({ message: '设置焦点切换顺序失败', error: error.message });
}
}
},
/**
* 获取 IP 黑名单列表 (分页)
@@ -11,6 +11,13 @@ router.use(isAuthenticated);
router.get('/', settingsController.getAllSettings); // GET /api/v1/settings
router.put('/', settingsController.updateSettings); // PUT /api/v1/settings
// +++ 新增:焦点切换顺序路由 +++
// GET /api/v1/settings/focus-switcher-sequence - 获取焦点切换顺序
router.get('/focus-switcher-sequence', settingsController.getFocusSwitcherSequence);
// PUT /api/v1/settings/focus-switcher-sequence - 更新焦点切换顺序
router.put('/focus-switcher-sequence', settingsController.setFocusSwitcherSequence);
// --- IP 黑名单管理路由 ---
// GET /api/v1/settings/ip-blacklist - 获取 IP 黑名单列表 (需要认证)
router.get('/ip-blacklist', settingsController.getIpBlacklist);
@@ -31,6 +31,7 @@ export type AuditLogActionType =
// Settings
| 'SETTINGS_UPDATED' // General settings update
| 'IP_WHITELIST_UPDATED' // Specific setting update
| 'FOCUS_SWITCHER_SEQUENCE_UPDATED' // +++ 新增:焦点切换顺序更新 +++
// Notifications
| 'NOTIFICATION_SETTING_CREATED'