关闭 allowJs;集中 JsonObject 定义并替换分散 any 别名;parseTaskContext 返回 TaskContext;任务详情 API 标注 AdminTaskDetailView;测试减少 as any。
154 lines
4.5 KiB
TypeScript
154 lines
4.5 KiB
TypeScript
import path from 'node:path'
|
|
import type { JsonObject } from '../../types/json.js'
|
|
|
|
import { APP_CONFIG_KEYS } from '../../config/app-config-keys.js'
|
|
import { PROJECT_ROOT } from '../../config/runtime.js'
|
|
import {
|
|
readAppConfigEntry,
|
|
saveAppConfigEntry,
|
|
} from '../config/app-config-store.js'
|
|
|
|
const NOTIFICATION_CONFIG_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'notification-config.json')
|
|
const DEFAULT_BARK_SERVER_URL = 'https://api.day.app'
|
|
|
|
type NotificationRecipient = {
|
|
id: string
|
|
name: string
|
|
deviceKey?: string
|
|
apiKey?: string
|
|
enabled: boolean
|
|
}
|
|
|
|
export function getNotificationConfigFilePath() {
|
|
return NOTIFICATION_CONFIG_FILE_PATH
|
|
}
|
|
|
|
export function getNotificationConfig() {
|
|
return readAppConfigEntry({
|
|
configKey: APP_CONFIG_KEYS.notification,
|
|
legacyFilePath: NOTIFICATION_CONFIG_FILE_PATH,
|
|
fallback: createDefaultNotificationConfig,
|
|
normalize: normalizeNotificationConfig,
|
|
})
|
|
}
|
|
|
|
export function saveNotificationConfig(rawValue: unknown) {
|
|
return saveAppConfigEntry({
|
|
configKey: APP_CONFIG_KEYS.notification,
|
|
legacyFilePath: NOTIFICATION_CONFIG_FILE_PATH,
|
|
value: rawValue,
|
|
normalize: normalizeNotificationConfig,
|
|
})
|
|
}
|
|
|
|
export function listEnabledBarkRecipients(config: JsonObject = getNotificationConfig()) {
|
|
if (config.enabled === false || config.channels?.bark?.enabled === false) {
|
|
return []
|
|
}
|
|
|
|
return (Array.isArray(config.channels?.bark?.recipients) ? config.channels.bark.recipients : [])
|
|
.filter((item: JsonObject) => item.enabled !== false && String(item.deviceKey || '').trim())
|
|
}
|
|
|
|
export function listEnabledWpushRecipients(config: JsonObject = getNotificationConfig()) {
|
|
if (config.enabled === false || config.channels?.wpush?.enabled === false) {
|
|
return []
|
|
}
|
|
|
|
return (Array.isArray(config.channels?.wpush?.recipients) ? config.channels.wpush.recipients : [])
|
|
.filter((item: JsonObject) => item.enabled !== false && String(item.apiKey || item.apikey || '').trim())
|
|
}
|
|
|
|
export function normalizeNotificationConfig(rawValue: unknown) {
|
|
const source = isPlainObject(rawValue) ? rawValue : {}
|
|
const bark = isPlainObject(source.channels?.bark) ? source.channels.bark : {}
|
|
const wpush = isPlainObject(source.channels?.wpush) ? source.channels.wpush : {}
|
|
|
|
return {
|
|
enabled: typeof source.enabled === 'boolean' ? source.enabled : true,
|
|
channels: {
|
|
bark: {
|
|
enabled: typeof bark.enabled === 'boolean' ? bark.enabled : true,
|
|
serverUrl: normalizeBarkServerUrl(bark.serverUrl),
|
|
recipients: (Array.isArray(bark.recipients) ? bark.recipients : [])
|
|
.map((item: unknown) => normalizeBarkRecipient(item))
|
|
.filter(Boolean),
|
|
},
|
|
wpush: {
|
|
enabled: typeof wpush.enabled === 'boolean' ? wpush.enabled : true,
|
|
recipients: (Array.isArray(wpush.recipients) ? wpush.recipients : [])
|
|
.map((item: unknown) => normalizeWpushRecipient(item))
|
|
.filter(Boolean),
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
function normalizeBarkRecipient(rawValue: unknown): NotificationRecipient | null {
|
|
if (!isPlainObject(rawValue)) {
|
|
return null
|
|
}
|
|
|
|
const name = String(rawValue.name || '').trim()
|
|
const deviceKey = String(rawValue.deviceKey || '').trim()
|
|
const id = String(rawValue.id || deviceKey || name || '').trim()
|
|
|
|
if (!name && !deviceKey) {
|
|
return null
|
|
}
|
|
|
|
return {
|
|
id,
|
|
name,
|
|
deviceKey,
|
|
enabled: typeof rawValue.enabled === 'boolean' ? rawValue.enabled : true,
|
|
}
|
|
}
|
|
|
|
function normalizeBarkServerUrl(value: unknown) {
|
|
const normalized = String(value || DEFAULT_BARK_SERVER_URL).trim() || DEFAULT_BARK_SERVER_URL
|
|
return normalized.replace(/\/+$/, '')
|
|
}
|
|
|
|
function normalizeWpushRecipient(rawValue: unknown): NotificationRecipient | null {
|
|
if (!isPlainObject(rawValue)) {
|
|
return null
|
|
}
|
|
|
|
const name = String(rawValue.name || '').trim()
|
|
const apiKey = String(rawValue.apiKey || rawValue.apikey || '').trim()
|
|
const id = String(rawValue.id || apiKey || name || '').trim()
|
|
|
|
if (!name && !apiKey) {
|
|
return null
|
|
}
|
|
|
|
return {
|
|
id,
|
|
name,
|
|
apiKey,
|
|
enabled: typeof rawValue.enabled === 'boolean' ? rawValue.enabled : true,
|
|
}
|
|
}
|
|
|
|
export function createDefaultNotificationConfig() {
|
|
return {
|
|
enabled: true,
|
|
channels: {
|
|
bark: {
|
|
enabled: true,
|
|
serverUrl: DEFAULT_BARK_SERVER_URL,
|
|
recipients: [] as NotificationRecipient[],
|
|
},
|
|
wpush: {
|
|
enabled: true,
|
|
recipients: [] as NotificationRecipient[],
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
function isPlainObject(value: unknown): value is JsonObject {
|
|
return Object.prototype.toString.call(value) === '[object Object]'
|
|
}
|