57 lines
2.6 KiB
TypeScript
57 lines
2.6 KiB
TypeScript
// src/app/api/monitor/settings/route.ts
|
|
import { NextRequest, NextResponse } from 'next/server'
|
|
import { initDatabase } from '@/lib/db-schema'
|
|
import { getCurrentUser } from '@/lib/auth'
|
|
import { hasPermission } from '@/lib/permissions'
|
|
import { getMaskedConfig, updateMonitorConfig } from '@/lib/monitor/settings-manager'
|
|
import { writeAuditLog, getClientIP } from '@/lib/audit'
|
|
|
|
const VALIDATORS: Record<string, (v: unknown) => boolean> = {
|
|
'monitor.enabled': (v) => typeof v === 'boolean',
|
|
'monitor.interval_seconds': (v) => typeof v === 'number' && v >= 10 && v <= 3600,
|
|
'monitor.push_delay_ms': (v) => typeof v === 'number' && v >= 0 && v <= 10000,
|
|
'monitor.silent_start_hour': (v) => typeof v === 'number' && v >= 0 && v <= 23,
|
|
'monitor.silent_end_hour': (v) => typeof v === 'number' && v >= 0 && v <= 23,
|
|
'mail.address': (v) => typeof v === 'string' && v.includes('@'),
|
|
'mail.imap_port': (v) => typeof v === 'number' && v > 0 && v <= 65535,
|
|
'mail.smtp_port': (v) => typeof v === 'number' && v > 0 && v <= 65535,
|
|
'wechat.webhook_url': (v) => typeof v === 'string' && (v === '' || v.startsWith('https://qyapi.weixin.qq.com/')),
|
|
}
|
|
|
|
export async function GET(request: NextRequest) {
|
|
initDatabase()
|
|
const user = await getCurrentUser()
|
|
if (!user || !hasPermission(user, 'monitor:read')) return NextResponse.json({ error: '权限不足' }, { status: 403 })
|
|
return NextResponse.json(getMaskedConfig())
|
|
}
|
|
|
|
export async function PUT(request: NextRequest) {
|
|
initDatabase()
|
|
const user = await getCurrentUser()
|
|
if (!user || !hasPermission(user, 'monitor:write')) return NextResponse.json({ error: '权限不足' }, { status: 403 })
|
|
const body = await request.json()
|
|
// 保留未修改的密码
|
|
if (body.mail?.password === '••••••••' || body.mail?.password === undefined) {
|
|
delete body.mail?.password
|
|
}
|
|
// 先展平嵌套对象
|
|
const flat: Record<string, unknown> = {}
|
|
for (const [section, values] of Object.entries(body)) {
|
|
if (typeof values === 'object' && values !== null) {
|
|
for (const [key, value] of Object.entries(values as Record<string, unknown>)) {
|
|
flat[`${section}.${key}`] = value
|
|
}
|
|
} else {
|
|
flat[section] = values
|
|
}
|
|
}
|
|
// 展平后验证
|
|
for (const [key, value] of Object.entries(flat)) {
|
|
const validator = VALIDATORS[key]
|
|
if (validator && !validator(value)) return NextResponse.json({ error: `参数 ${key} 验证失败` }, { status: 400 })
|
|
}
|
|
updateMonitorConfig(flat)
|
|
writeAuditLog({ userId: user.id, action: 'update', entityType: 'monitor_config', details: { keys: Object.keys(flat) }, ipAddress: getClientIP(request) })
|
|
return NextResponse.json({ success: true })
|
|
}
|