issue-ai/src/app/api/monitor/settings/route.ts

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 })
}