Compare commits

..
Author SHA1 Message Date
guoyuqi f03116691c fix: alert config log text 2026-10-14 18:59:53 +08:00
guoyuqi 363e950aad fix: alert config log text 2026-10-14 18:51:05 +08:00
8 changed files with 95 additions and 75 deletions
+8 -5
View File
@@ -293,7 +293,7 @@ func (b *BaseApi) PageAlertConfig(c *gin.Context) {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /alert/config/update [post] // @Router /alert/config/update [post]
// @x-panel-log {"bodyKeys":["id","displayName"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新告警配置 [id][displayName]","formatEN":"update alert config [id][displayName]"} // @x-panel-log {"bodyKeys":["displayName"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新告警配置 [displayName]","formatEN":"update alert config [displayName]"}
func (b *BaseApi) UpdateAlertConfig(c *gin.Context) { func (b *BaseApi) UpdateAlertConfig(c *gin.Context) {
var req dto.AlertConfigUpdate var req dto.AlertConfigUpdate
if err := helper.CheckBindAndValidate(&req, c); err != nil { if err := helper.CheckBindAndValidate(&req, c); err != nil {
@@ -321,13 +321,15 @@ func (b *BaseApi) UpdateAlertConfig(c *gin.Context) {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /alert/config/status [post] // @Router /alert/config/status [post]
// @x-panel-log {"bodyKeys":["id","status"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新告警配置状态 [id][status]","formatEN":"update alert config status [id][status]"} // @x-panel-log {"bodyKeys":["status"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新告警配置状态 [name][status]","formatEN":"update alert config status [name][status]"}
func (b *BaseApi) UpdateAlertConfigStatus(c *gin.Context) { func (b *BaseApi) UpdateAlertConfigStatus(c *gin.Context) {
var req dto.AlertConfigStatusUpdate var req dto.AlertConfigStatusUpdate
if err := helper.CheckBindAndValidate(&req, c); err != nil { if err := helper.CheckBindAndValidate(&req, c); err != nil {
return return
} }
if err := alertService.UpdateAlertConfigStatus(req, loadAuditUser(c)); err != nil { name, err := alertService.UpdateAlertConfigStatus(req, loadAuditUser(c))
helper.SetOperationLogValues(c, map[string]string{"name": name})
if err != nil {
helper.InternalServer(c, err) helper.InternalServer(c, err)
return return
} }
@@ -353,13 +355,14 @@ func loadAuditUser(c *gin.Context) string {
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /alert/config/del [post] // @Router /alert/config/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"删除告警配置 [id]","formatEN":"delete alert config [id]"} // @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"删除告警配置 [name]","formatEN":"delete alert config [name]"}
func (b *BaseApi) DeleteAlertConfig(c *gin.Context) { func (b *BaseApi) DeleteAlertConfig(c *gin.Context) {
var req dto.DeleteRequest var req dto.DeleteRequest
if err := helper.CheckBindAndValidate(&req, c); err != nil { if err := helper.CheckBindAndValidate(&req, c); err != nil {
return return
} }
err := alertService.DeleteAlertConfig(req.ID) name, err := alertService.DeleteAlertConfig(req.ID)
helper.SetOperationLogValues(c, map[string]string{"name": name})
if err != nil { if err != nil {
helper.InternalServer(c, err) helper.InternalServer(c, err)
return return
+21
View File
@@ -3,6 +3,7 @@ package helper
import ( import (
"compress/gzip" "compress/gzip"
"context" "context"
"encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
@@ -184,3 +185,23 @@ func GetParamInt32(paramName string, c *gin.Context) (int32, error) {
intNum, _ := strconv.Atoi(idParam) intNum, _ := strconv.Atoi(idParam)
return int32(intNum), nil return int32(intNum), nil
} }
// SetOperationLogValues supplies server-resolved values to Core's operation log.
// Call before writing the response. Only pass public audit fields, never credentials.
func SetOperationLogValues(c *gin.Context, values map[string]string) {
const header = "X-Op-Resolved"
resolved := make(map[string]string)
if data, err := base64.RawURLEncoding.DecodeString(c.Writer.Header().Get(header)); err == nil {
_ = json.Unmarshal(data, &resolved)
}
if resolved == nil {
resolved = make(map[string]string)
}
for key, value := range values {
resolved[key] = value
}
data, err := json.Marshal(resolved)
if err == nil {
c.Header(header, base64.RawURLEncoding.EncodeToString(data))
}
}
+26 -14
View File
@@ -74,8 +74,8 @@ type IAlertService interface {
GetAlertConfig(req dto.AlertConfigQuery) ([]model.AlertConfig, error) GetAlertConfig(req dto.AlertConfigQuery) ([]model.AlertConfig, error)
PageAlertConfig(req dto.AlertConfigPageReq) (int64, []model.AlertConfig, error) PageAlertConfig(req dto.AlertConfigPageReq) (int64, []model.AlertConfig, error)
UpdateAlertConfig(req dto.AlertConfigUpdate, operator string) error UpdateAlertConfig(req dto.AlertConfigUpdate, operator string) error
UpdateAlertConfigStatus(req dto.AlertConfigStatusUpdate, operator string) error UpdateAlertConfigStatus(req dto.AlertConfigStatusUpdate, operator string) (string, error)
DeleteAlertConfig(id uint) error DeleteAlertConfig(id uint) (string, error)
TestAlertConfig(req dto.AlertConfigTest) (bool, error) TestAlertConfig(req dto.AlertConfigTest) (bool, error)
TestCustomAlertConfig(req dto.AlertConfigTest, lang string) (dto.AlertConfigTestResult, error) TestCustomAlertConfig(req dto.AlertConfigTest, lang string) (dto.AlertConfigTestResult, error)
} }
@@ -623,25 +623,26 @@ func (a AlertService) updateCustomAlertConfig(req dto.AlertConfigUpdate, operato
}) })
} }
func (a AlertService) UpdateAlertConfigStatus(req dto.AlertConfigStatusUpdate, operator string) error { func (a AlertService) UpdateAlertConfigStatus(req dto.AlertConfigStatusUpdate, operator string) (string, error) {
if err := validateAlertConfigStatus(req.Status); err != nil { if err := validateAlertConfigStatus(req.Status); err != nil {
return err return "", err
} }
config, err := alertRepo.GetConfigById(req.ID) config, err := alertRepo.GetConfigById(req.ID)
if err != nil { if err != nil {
return err return "", err
} }
name := alertConfigLogName(config.Config, config.Title)
if req.Status == constant.AlertEnable { if req.Status == constant.AlertEnable {
if err := a.validateCommunityAlertConfigType(config.Type); err != nil { if err := a.validateCommunityAlertConfigType(config.Type); err != nil {
return err return name, err
} }
if config.Type == constant.Custom { if config.Type == constant.Custom {
if _, err := alertwebhook.Resolve(config); err != nil { if _, err := alertwebhook.Resolve(config); err != nil {
return err return name, err
} }
} }
} }
return alertRepo.UpdateAlertConfig(map[string]interface{}{ return name, alertRepo.UpdateAlertConfig(map[string]interface{}{
"status": req.Status, "status": req.Status,
"update_user": operator, "update_user": operator,
}, repo.WithByID(req.ID)) }, repo.WithByID(req.ID))
@@ -813,19 +814,20 @@ func alertConfigSMSPhone(configData string) string {
return strings.TrimSpace(cfg.Phone) return strings.TrimSpace(cfg.Phone)
} }
func (a AlertService) DeleteAlertConfig(id uint) error { func (a AlertService) DeleteAlertConfig(id uint) (string, error) {
_, err := alertRepo.GetConfigById(id) config, err := alertRepo.GetConfigById(id)
if err != nil { if err != nil {
return err return "", err
} }
name := alertConfigLogName(config.Config, config.Title)
usedAlerts, err := alertRepo.List(alertRepo.WithByAlertMethodContainsConfigID(id)) usedAlerts, err := alertRepo.List(alertRepo.WithByAlertMethodContainsConfigID(id))
if err != nil { if err != nil {
return err return name, err
} }
if len(usedAlerts) > 0 { if len(usedAlerts) > 0 {
return buserr.New("ErrAlertConfigInUse") return name, buserr.New("ErrAlertConfigInUse")
} }
return alertRepo.DeleteAlertConfig(repo.WithByID(id)) return name, alertRepo.DeleteAlertConfig(repo.WithByID(id))
} }
func (a AlertService) TestAlertConfig(req dto.AlertConfigTest) (bool, error) { func (a AlertService) TestAlertConfig(req dto.AlertConfigTest) (bool, error) {
@@ -1043,3 +1045,13 @@ func (a AlertService) validateCronJobAlertChannels(alertType, advanced, method s
_, err = a.validateAlertMethodReferences(method) _, err = a.validateAlertMethodReferences(method)
return err return err
} }
func alertConfigLogName(config, title string) string {
var value struct {
DisplayName string `json:"displayName"`
}
if json.Unmarshal([]byte(config), &value) == nil && strings.TrimSpace(value.DisplayName) != "" {
return strings.TrimSpace(value.DisplayName)
}
return title
}
+10 -14
View File
@@ -108,33 +108,29 @@
"formatEN": "create alert [title]" "formatEN": "create alert [title]"
}, },
"/alert/config/del": { "/alert/config/del": {
"bodyKeys": [ "bodyKeys": [],
"id"
],
"paramKeys": [], "paramKeys": [],
"beforeFunctions": [], "formatZH": "删除告警配置 [name]",
"formatZH": "删除告警配置 [id]", "formatEN": "delete alert config [name]",
"formatEN": "delete alert config [id]" "beforeFunctions": []
}, },
"/alert/config/status": { "/alert/config/status": {
"bodyKeys": [ "bodyKeys": [
"id",
"status" "status"
], ],
"paramKeys": [], "paramKeys": [],
"beforeFunctions": [], "formatZH": "更新告警配置状态 [name][status]",
"formatZH": "更新告警配置状态 [id][status]", "formatEN": "update alert config status [name][status]",
"formatEN": "update alert config status [id][status]" "beforeFunctions": []
}, },
"/alert/config/update": { "/alert/config/update": {
"bodyKeys": [ "bodyKeys": [
"id",
"displayName" "displayName"
], ],
"paramKeys": [], "paramKeys": [],
"beforeFunctions": [], "formatZH": "更新告警配置 [displayName]",
"formatZH": "更新告警配置 [id][displayName]", "formatEN": "update alert config [displayName]",
"formatEN": "update alert config [id][displayName]" "beforeFunctions": []
}, },
"/alert/del": { "/alert/del": {
"bodyKeys": [ "bodyKeys": [
+9 -12
View File
@@ -3906,13 +3906,11 @@ const docTemplate = `{
"Alert" "Alert"
], ],
"x-panel-log": { "x-panel-log": {
"BeforeFunctions": [], "bodyKeys": [],
"bodyKeys": [ "paramKeys": [],
"id" "formatZH": "删除告警配置 [name]",
], "formatEN": "delete alert config [name]",
"formatEN": "delete alert config [id]", "BeforeFunctions": []
"formatZH": "删除告警配置 [id]",
"paramKeys": []
} }
} }
}, },
@@ -4041,14 +4039,13 @@ const docTemplate = `{
"Alert" "Alert"
], ],
"x-panel-log": { "x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [ "bodyKeys": [
"id",
"displayName" "displayName"
], ],
"formatEN": "update alert config [id][displayName]", "paramKeys": [],
"formatZH": "更新告警配置 [id][displayName]", "formatZH": "更新告警配置 [displayName]",
"paramKeys": [] "formatEN": "update alert config [displayName]",
"BeforeFunctions": []
} }
} }
}, },
+9 -12
View File
@@ -3902,13 +3902,11 @@
"Alert" "Alert"
], ],
"x-panel-log": { "x-panel-log": {
"BeforeFunctions": [], "bodyKeys": [],
"bodyKeys": [ "paramKeys": [],
"id" "formatZH": "删除告警配置 [name]",
], "formatEN": "delete alert config [name]",
"formatEN": "delete alert config [id]", "BeforeFunctions": []
"formatZH": "删除告警配置 [id]",
"paramKeys": []
} }
} }
}, },
@@ -4037,14 +4035,13 @@
"Alert" "Alert"
], ],
"x-panel-log": { "x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [ "bodyKeys": [
"id",
"displayName" "displayName"
], ],
"formatEN": "update alert config [id][displayName]", "paramKeys": [],
"formatZH": "更新告警配置 [id][displayName]", "formatZH": "更新告警配置 [displayName]",
"paramKeys": [] "formatEN": "update alert config [displayName]",
"BeforeFunctions": []
} }
} }
}, },
+10 -14
View File
@@ -108,33 +108,29 @@
"formatEN": "create alert [title]" "formatEN": "create alert [title]"
}, },
"/alert/config/del": { "/alert/config/del": {
"bodyKeys": [ "bodyKeys": [],
"id"
],
"paramKeys": [], "paramKeys": [],
"beforeFunctions": [], "formatZH": "删除告警配置 [name]",
"formatZH": "删除告警配置 [id]", "formatEN": "delete alert config [name]",
"formatEN": "delete alert config [id]" "beforeFunctions": []
}, },
"/alert/config/status": { "/alert/config/status": {
"bodyKeys": [ "bodyKeys": [
"id",
"status" "status"
], ],
"paramKeys": [], "paramKeys": [],
"beforeFunctions": [], "formatZH": "更新告警配置状态 [name][status]",
"formatZH": "更新告警配置状态 [id][status]", "formatEN": "update alert config status [name][status]",
"formatEN": "update alert config status [id][status]" "beforeFunctions": []
}, },
"/alert/config/update": { "/alert/config/update": {
"bodyKeys": [ "bodyKeys": [
"id",
"displayName" "displayName"
], ],
"paramKeys": [], "paramKeys": [],
"beforeFunctions": [], "formatZH": "更新告警配置 [displayName]",
"formatZH": "更新告警配置 [id][displayName]", "formatEN": "update alert config [displayName]",
"formatEN": "update alert config [id][displayName]" "beforeFunctions": []
}, },
"/alert/del": { "/alert/del": {
"bodyKeys": [ "bodyKeys": [
+2 -4
View File
@@ -133,11 +133,9 @@ func OperationLog() gin.HandlerFunc {
record.AuthMethod = "session" record.AuthMethod = "session"
} }
// Handlers may supply audit values even without database resolution metadata.
mergeResolvedData(writer.resolvedHeader, formatMap)
if len(operationDic.BeforeFunctions) != 0 { if len(operationDic.BeforeFunctions) != 0 {
if needAgentResolve {
mergeResolvedData(writer.resolvedHeader, formatMap)
}
if allowCoreFallback && !hasAllResolvedData(formatMap, operationDic.BeforeFunctions) { if allowCoreFallback && !hasAllResolvedData(formatMap, operationDic.BeforeFunctions) {
dbItem, err := newDB(record.Path) dbItem, err := newDB(record.Path)
if err == nil { if err == nil {