import SiteConfigModel from "../model/site-config" import { logger } from "@/logger.js" /** * 站点配置服务类 * 提供站点配置相关的业务逻辑 */ class SiteConfigService { /** * 获取配置值 * @param {string} key - 配置键 * @param {*} defaultValue - 默认值 * @returns {Promise<*>} 配置值 */ static async get(key, defaultValue = null) { try { const value = await SiteConfigModel.get(key) return value !== null ? value : defaultValue } catch (error) { logger.error(`获取配置失败 (${key}):`, error) throw error } } /** * 设置配置值 * @param {string} key - 配置键 * @param {*} value - 配置值 * @returns {Promise} 配置对象 */ static async set(key, value) { try { // 验证配置键 this.validateConfigKey(key) // 序列化值 const serializedValue = this.serializeValue(value) const config = await SiteConfigModel.set(key, serializedValue) logger.info(`配置设置成功: ${key}`) return this.formatConfigResponse(config) } catch (error) { logger.error(`设置配置失败 (${key}):`, error) throw error } } /** * 批量获取配置 * @param {Array} keys - 配置键数组 * @returns {Promise} 配置对象 */ static async getMany(keys) { try { if (!Array.isArray(keys) || keys.length === 0) { return {} } const configs = await SiteConfigModel.getMany(keys) // 反序列化值 const result = {} for (const [key, value] of Object.entries(configs)) { result[key] = this.deserializeValue(value) } return result } catch (error) { logger.error(`批量获取配置失败:`, error) throw error } } /** * 获取所有配置 * @returns {Promise} 所有配置 */ static async getAll() { try { const configs = await SiteConfigModel.getAll() // 反序列化值 const result = {} for (const [key, value] of Object.entries(configs)) { result[key] = this.deserializeValue(value) } return result } catch (error) { logger.error(`获取所有配置失败:`, error) throw error } } /** * 批量设置配置 * @param {Object} configs - 配置对象 * @returns {Promise} 设置结果 */ static async setMany(configs) { try { if (!configs || typeof configs !== 'object') { throw new Error("配置对象不能为空") } const results = [] for (const [key, value] of Object.entries(configs)) { try { this.validateConfigKey(key) const serializedValue = this.serializeValue(value) const config = await SiteConfigModel.set(key, serializedValue) results.push(this.formatConfigResponse(config)) } catch (error) { logger.error(`设置配置失败 (${key}):`, error) results.push({ key, error: error.message }) } } logger.info(`批量设置配置完成: ${Object.keys(configs).length} 个配置`) return results } catch (error) { logger.error(`批量设置配置失败:`, error) throw error } } /** * 删除配置 * @param {string} key - 配置键 * @returns {Promise} 删除结果 */ static async delete(key) { try { const result = await SiteConfigModel.deleteByKey(key) logger.info(`配置删除成功: ${key}`) return result > 0 } catch (error) { logger.error(`删除配置失败 (${key}):`, error) throw error } } /** * 检查配置是否存在 * @param {string} key - 配置键 * @returns {Promise} 是否存在 */ static async has(key) { try { return await SiteConfigModel.hasKey(key) } catch (error) { logger.error(`检查配置是否存在失败 (${key}):`, error) throw error } } /** * 获取配置统计 * @returns {Promise} 统计信息 */ static async getStats() { try { return await SiteConfigModel.getConfigStats() } catch (error) { logger.error(`获取配置统计失败:`, error) throw error } } /** * 获取站点基本信息配置 * @returns {Promise} 站点基本信息 */ static async getSiteInfo() { try { const keys = [ 'site_name', 'site_description', 'site_keywords', 'site_author', 'site_url', 'site_logo', 'site_favicon', 'site_theme', 'site_language', 'site_timezone' ] const configs = await this.getMany(keys) return { name: configs.site_name || '我的网站', description: configs.site_description || '', keywords: configs.site_keywords || '', author: configs.site_author || '', url: configs.site_url || '', logo: configs.site_logo || '', favicon: configs.site_favicon || '', theme: configs.site_theme || 'default', language: configs.site_language || 'zh-CN', timezone: configs.site_timezone || 'Asia/Shanghai' } } catch (error) { logger.error(`获取站点基本信息失败:`, error) throw error } } /** * 设置站点基本信息配置 * @param {Object} siteInfo - 站点信息 * @returns {Promise} 设置结果 */ static async setSiteInfo(siteInfo) { try { const configs = {} if (siteInfo.name) configs.site_name = siteInfo.name if (siteInfo.description) configs.site_description = siteInfo.description if (siteInfo.keywords) configs.site_keywords = siteInfo.keywords if (siteInfo.author) configs.site_author = siteInfo.author if (siteInfo.url) configs.site_url = siteInfo.url if (siteInfo.logo) configs.site_logo = siteInfo.logo if (siteInfo.favicon) configs.site_favicon = siteInfo.favicon if (siteInfo.theme) configs.site_theme = siteInfo.theme if (siteInfo.language) configs.site_language = siteInfo.language if (siteInfo.timezone) configs.site_timezone = siteInfo.timezone return await this.setMany(configs) } catch (error) { logger.error(`设置站点基本信息失败:`, error) throw error } } /** * 获取邮件配置 * @returns {Promise} 邮件配置 */ static async getEmailConfig() { try { const keys = [ 'email_host', 'email_port', 'email_secure', 'email_user', 'email_password', 'email_from', 'email_name' ] const configs = await this.getMany(keys) return { host: configs.email_host || '', port: parseInt(configs.email_port) || 587, secure: configs.email_secure === 'true', user: configs.email_user || '', password: configs.email_password || '', from: configs.email_from || '', name: configs.email_name || '' } } catch (error) { logger.error(`获取邮件配置失败:`, error) throw error } } /** * 设置邮件配置 * @param {Object} emailConfig - 邮件配置 * @returns {Promise} 设置结果 */ static async setEmailConfig(emailConfig) { try { const configs = {} if (emailConfig.host) configs.email_host = emailConfig.host if (emailConfig.port) configs.email_port = emailConfig.port.toString() if (emailConfig.secure !== undefined) configs.email_secure = emailConfig.secure.toString() if (emailConfig.user) configs.email_user = emailConfig.user if (emailConfig.password) configs.email_password = emailConfig.password if (emailConfig.from) configs.email_from = emailConfig.from if (emailConfig.name) configs.email_name = emailConfig.name return await this.setMany(configs) } catch (error) { logger.error(`设置邮件配置失败:`, error) throw error } } /** * 获取系统配置 * @returns {Promise} 系统配置 */ static async getSystemConfig() { try { const keys = [ 'maintenance_mode', 'registration_enabled', 'email_verification_required', 'max_upload_size', 'allowed_file_types', 'session_timeout', 'password_min_length', 'login_attempts_limit' ] const configs = await this.getMany(keys) return { maintenanceMode: configs.maintenance_mode === 'true', registrationEnabled: configs.registration_enabled !== 'false', emailVerificationRequired: configs.email_verification_required === 'true', maxUploadSize: parseInt(configs.max_upload_size) || 10485760, // 10MB allowedFileTypes: configs.allowed_file_types ? configs.allowed_file_types.split(',') : ['jpg', 'jpeg', 'png', 'gif', 'pdf'], sessionTimeout: parseInt(configs.session_timeout) || 3600, // 1小时 passwordMinLength: parseInt(configs.password_min_length) || 6, loginAttemptsLimit: parseInt(configs.login_attempts_limit) || 5 } } catch (error) { logger.error(`获取系统配置失败:`, error) throw error } } /** * 设置系统配置 * @param {Object} systemConfig - 系统配置 * @returns {Promise} 设置结果 */ static async setSystemConfig(systemConfig) { try { const configs = {} if (systemConfig.maintenanceMode !== undefined) configs.maintenance_mode = systemConfig.maintenanceMode.toString() if (systemConfig.registrationEnabled !== undefined) configs.registration_enabled = systemConfig.registrationEnabled.toString() if (systemConfig.emailVerificationRequired !== undefined) configs.email_verification_required = systemConfig.emailVerificationRequired.toString() if (systemConfig.maxUploadSize) configs.max_upload_size = systemConfig.maxUploadSize.toString() if (systemConfig.allowedFileTypes) configs.allowed_file_types = Array.isArray(systemConfig.allowedFileTypes) ? systemConfig.allowedFileTypes.join(',') : systemConfig.allowedFileTypes if (systemConfig.sessionTimeout) configs.session_timeout = systemConfig.sessionTimeout.toString() if (systemConfig.passwordMinLength) configs.password_min_length = systemConfig.passwordMinLength.toString() if (systemConfig.loginAttemptsLimit) configs.login_attempts_limit = systemConfig.loginAttemptsLimit.toString() return await this.setMany(configs) } catch (error) { logger.error(`设置系统配置失败:`, error) throw error } } /** * 重置配置为默认值 * @param {Array} keys - 要重置的配置键数组(可选,默认重置所有) * @returns {Promise} 重置结果 */ static async resetToDefaults(keys = null) { try { const defaultConfigs = { site_name: '我的网站', site_description: '欢迎来到我的网站', site_keywords: '网站,博客,个人网站', site_author: '网站管理员', site_url: 'http://localhost:3000', site_theme: 'default', site_language: 'zh-CN', site_timezone: 'Asia/Shanghai', maintenance_mode: 'false', registration_enabled: 'true', email_verification_required: 'false', max_upload_size: '10485760', allowed_file_types: 'jpg,jpeg,png,gif,pdf', session_timeout: '3600', password_min_length: '6', login_attempts_limit: '5' } const configsToReset = keys ? Object.fromEntries(keys.filter(key => defaultConfigs[key]).map(key => [key, defaultConfigs[key]])) : defaultConfigs return await this.setMany(configsToReset) } catch (error) { logger.error(`重置配置为默认值失败:`, error) throw error } } /** * 验证配置键 * @param {string} key - 配置键 */ static validateConfigKey(key) { if (!key || typeof key !== 'string') { throw new Error("配置键不能为空") } if (key.length > 100) { throw new Error("配置键长度不能超过100个字符") } if (!/^[a-zA-Z0-9_]+$/.test(key)) { throw new Error("配置键只能包含字母、数字和下划线") } } /** * 序列化值 * @param {*} value - 要序列化的值 * @returns {string} 序列化后的字符串 */ static serializeValue(value) { if (value === null || value === undefined) { return '' } if (typeof value === 'string') { return value } if (typeof value === 'number' || typeof value === 'boolean') { return value.toString() } return JSON.stringify(value) } /** * 反序列化值 * @param {string} value - 要反序列化的字符串 * @returns {*} 反序列化后的值 */ static deserializeValue(value) { if (value === null || value === undefined || value === '') { return null } // 尝试解析为JSON try { return JSON.parse(value) } catch (e) { // 如果不是有效的JSON,返回原字符串 return value } } /** * 格式化配置响应数据 * @param {Object} config - 配置数据 * @returns {Object} 格式化后的配置数据 */ static formatConfigResponse(config) { return { ...config, // 确保数字字段为数字类型 id: parseInt(config.id), // 反序列化值 value: this.deserializeValue(config.value), // 格式化日期字段 created_at: config.created_at, updated_at: config.updated_at } } /** * 导出配置 * @returns {Promise} 导出的配置 */ static async exportConfig() { try { const configs = await this.getAll() return { exported_at: new Date().toISOString(), configs } } catch (error) { logger.error(`导出配置失败:`, error) throw error } } /** * 导入配置 * @param {Object} configData - 配置数据 * @returns {Promise} 导入结果 */ static async importConfig(configData) { try { if (!configData || !configData.configs) { throw new Error("无效的配置数据") } const results = await this.setMany(configData.configs) logger.info(`配置导入完成: ${Object.keys(configData.configs).length} 个配置`) return { success: results.filter(r => !r.error).length, failed: results.filter(r => r.error).length, results } } catch (error) { logger.error(`导入配置失败:`, error) throw error } } } export default SiteConfigService export { SiteConfigService }