diff --git a/agent/app/dto/alert.go b/agent/app/dto/alert.go index e9695b4ca041..2facd238f987 100644 --- a/agent/app/dto/alert.go +++ b/agent/app/dto/alert.go @@ -335,3 +335,8 @@ type AgentInfo struct { NodeName string `json:"nodeName"` NodeAddr string `json:"nodeAddr"` } + +type AlertWebhookConfig struct { + DisplayName string `json:"displayName"` + Url string `json:"url"` +} diff --git a/agent/app/service/alert_helper.go b/agent/app/service/alert_helper.go index 9dcd08dc2bfe..40df5273f6e1 100644 --- a/agent/app/service/alert_helper.go +++ b/agent/app/service/alert_helper.go @@ -2,6 +2,7 @@ package service import ( "encoding/json" + "fmt" "github.com/1Panel-dev/1Panel/agent/app/dto" "github.com/1Panel-dev/1Panel/agent/app/model" "github.com/1Panel-dev/1Panel/agent/app/repo" @@ -586,8 +587,6 @@ func sendAlerts(alert dto.AlertDTO, alertType, quota, quotaType string, params [ continue } alertUtil.CreateNewAlertTask(quota, alertType, quotaType, constant.SMS) - global.LOG.Infof("%s alert sms push successful", alertType) - case constant.Email: todayCount, isValid := canSendAlertToday(alertType, quotaType, alert.SendCount, constant.Email) if !isValid { @@ -610,7 +609,25 @@ func sendAlerts(alert dto.AlertDTO, alertType, quota, quotaType string, params [ continue } alertUtil.CreateNewAlertTask(quota, alertType, quotaType, constant.Email) - global.LOG.Infof("%s alert email push successful", alertType) + case constant.WeCom, constant.DingTalk, constant.FeiShu: + todayCount, isValid := canSendAlertToday(alertType, quotaType, alert.SendCount, m) + if !isValid { + continue + } + var create = dto.AlertLogCreate{ + Type: alertUtil.GetCronJobType(alert.Type), + AlertId: alert.ID, + Count: todayCount + 1, + } + transport := xpack.LoadRequestTransport() + agentInfo, _ := xpack.GetAgentInfo() + err := xpack.CreateWebhookAlertLog(alertType, alert, create, quotaType, params, m, transport, agentInfo) + if err != nil { + global.LOG.Infof("%s alert webhook %s push faild, err: %v", alertType, m, err) + continue + } + alertUtil.CreateNewAlertTask(quota, alertUtil.GetCronJobType(alert.Type), quotaType, m) + default: } } } @@ -829,30 +846,36 @@ func processAllDisks(alert dto.AlertDTO) error { global.LOG.Errorf("error getting disk list, err: %v", err) return err } + var errMsgs []string for _, item := range diskList { - if success, err := checkAndCreateDiskAlert(alert, item.Path); err == nil && success { - global.LOG.Infof("disk alert pushed successfully for %s", item.Path) + err := checkAndCreateDiskAlert(alert, item.Path) + if err != nil { + errMsg := fmt.Sprintf("disk path %s process failed: %v", item.Path, err) + errMsgs = append(errMsgs, errMsg) + global.LOG.Errorf(errMsg) + continue } } + if len(errMsgs) > 0 { + return fmt.Errorf("batch process disks failed, error count: %d, details: %s", len(errMsgs), strings.Join(errMsgs, "; ")) + } return nil } func processSingleDisk(alert dto.AlertDTO) error { - success, err := checkAndCreateDiskAlert(alert, alert.Project) + err := checkAndCreateDiskAlert(alert, alert.Project) if err != nil { + global.LOG.Errorf(err.Error()) return err } - if success { - global.LOG.Infof("disk alert pushed successfully for %s", alert.Project) - } return nil } -func checkAndCreateDiskAlert(alert dto.AlertDTO, path string) (bool, error) { +func checkAndCreateDiskAlert(alert dto.AlertDTO, path string) error { usageStat, err := psutil.DISK.GetUsage(path, false) if err != nil { global.LOG.Errorf("error getting disk usage for %s, err: %v", path, err) - return false, err + return err } usedTotal, usedStr := calculateUsedTotal(alert.Cycle, usageStat) @@ -861,13 +884,12 @@ func checkAndCreateDiskAlert(alert dto.AlertDTO, path string) (bool, error) { commonTotal *= 1024 * 1024 * 1024 } if usedTotal < commonTotal { - return false, nil + return nil } - global.LOG.Infof("disk「 %s 」usage: %s", path, usedStr) params := createAlertDiskParams(path, usedStr) sender := NewAlertSender(alert, alert.Project) sender.ResourceSend(path, params) - return true, nil + return nil } func calculateUsedTotal(cycle uint, usageStat *disk.UsageStat) (float64, string) { diff --git a/agent/app/service/alert_sender.go b/agent/app/service/alert_sender.go index 228d4b405072..cd39fdeb44a1 100644 --- a/agent/app/service/alert_sender.go +++ b/agent/app/service/alert_sender.go @@ -30,6 +30,8 @@ func (s *AlertSender) Send(quota string, params []dto.Param) { s.sendSMS(quota, params) case constant.Email: s.sendEmail(quota, params) + case constant.WeCom, constant.DingTalk, constant.FeiShu: + s.sendWebhook(quota, params, method) } } } @@ -43,6 +45,8 @@ func (s *AlertSender) ResourceSend(quota string, params []dto.Param) { s.sendResourceSMS(quota, params) case constant.Email: s.sendResourceEmail(quota, params) + case constant.WeCom, constant.DingTalk, constant.FeiShu: + s.sendResourceWebhook(quota, params, method) } } } @@ -64,9 +68,12 @@ func (s *AlertSender) sendSMS(quota string, params []dto.Param) { Type: s.alert.Type, } - _ = xpack.CreateSMSAlertLog(s.alert.Type, s.alert, create, quota, params, constant.SMS) + err := xpack.CreateSMSAlertLog(s.alert.Type, s.alert, create, quota, params, constant.SMS) + if err != nil { + global.LOG.Errorf("%s alert sms push failed: %v", s.alert.Type, err) + return + } alertUtil.CreateNewAlertTask(quota, s.alert.Type, s.quotaType, constant.SMS) - global.LOG.Infof("%s alert sms push successful", s.alert.Type) } func (s *AlertSender) sendEmail(quota string, params []dto.Param) { @@ -86,9 +93,34 @@ func (s *AlertSender) sendEmail(quota string, params []dto.Param) { transport := xpack.LoadRequestTransport() agentInfo, _ := xpack.GetAgentInfo() - _ = alertUtil.CreateEmailAlertLog(create, s.alert, params, transport, agentInfo) + err := alertUtil.CreateEmailAlertLog(create, s.alert, params, transport, agentInfo) + if err != nil { + global.LOG.Errorf("%s alert email push failed: %v", s.alert.Type, err) + return + } alertUtil.CreateNewAlertTask(quota, s.alert.Type, s.quotaType, constant.Email) - global.LOG.Infof("%s alert email push successful", s.alert.Type) +} + +func (s *AlertSender) sendWebhook(quota string, params []dto.Param, method string) { + totalCount, isValid := s.canSendAlert(method) + if !isValid { + return + } + + create := dto.AlertLogCreate{ + Status: constant.AlertSuccess, + Count: totalCount + 1, + AlertId: s.alert.ID, + Type: s.alert.Type, + } + transport := xpack.LoadRequestTransport() + agentInfo, _ := xpack.GetAgentInfo() + err := xpack.CreateWebhookAlertLog(s.alert.Type, s.alert, create, quota, params, method, transport, agentInfo) + if err != nil { + global.LOG.Errorf("%s alert %s webhook push failed: %v", s.alert.Type, method, err) + return + } + alertUtil.CreateNewAlertTask(quota, s.alert.Type, s.quotaType, method) } func (s *AlertSender) sendResourceSMS(quota string, params []dto.Param) { @@ -113,7 +145,6 @@ func (s *AlertSender) sendResourceSMS(quota string, params []dto.Param) { return } alertUtil.CreateNewAlertTask(quota, s.alert.Type, s.quotaType, constant.SMS) - global.LOG.Infof("%s alert sms push successful", s.alert.Type) } func (s *AlertSender) sendResourceEmail(quota string, params []dto.Param) { @@ -138,7 +169,27 @@ func (s *AlertSender) sendResourceEmail(quota string, params []dto.Param) { return } alertUtil.CreateNewAlertTask(quota, s.alert.Type, s.quotaType, constant.Email) - global.LOG.Infof("%s alert email push successful", s.alert.Type) +} + +func (s *AlertSender) sendResourceWebhook(quota string, params []dto.Param, method string) { + todayCount, isValid := s.canResourceSendAlert(method) + if !isValid { + return + } + + create := dto.AlertLogCreate{ + Status: constant.AlertSuccess, + Count: todayCount + 1, + AlertId: s.alert.ID, + Type: s.alert.Type, + } + transport := xpack.LoadRequestTransport() + agentInfo, _ := xpack.GetAgentInfo() + if err := xpack.CreateWebhookAlertLog(s.alert.Type, s.alert, create, quota, params, method, transport, agentInfo); err != nil { + global.LOG.Errorf("failed to send webhook alert: %v", err) + return + } + alertUtil.CreateNewAlertTask(quota, s.alert.Type, s.quotaType, method) } func (s *AlertSender) canSendAlert(method string) (uint, bool) { diff --git a/agent/constant/alert.go b/agent/constant/alert.go index 3fc50c030a51..67915121d88f 100644 --- a/agent/constant/alert.go +++ b/agent/constant/alert.go @@ -24,4 +24,5 @@ const ( WeCom = "weCom" DingTalk = "dingTalk" FeiShu = "feiShu" + Custom = "custom" ) diff --git a/agent/utils/alert/alert.go b/agent/utils/alert/alert.go index 08e2ccd7091e..ac605f5abe2d 100644 --- a/agent/utils/alert/alert.go +++ b/agent/utils/alert/alert.go @@ -49,19 +49,24 @@ func CreateEmailAlertLog(create dto.AlertLogCreate, alert dto.AlertDTO, params [ return err } create.Method = constant.Email + emailConfig, err := alertRepo.GetConfig(alertRepo.WithByType(constant.EmailConfig)) + if err != nil { + return err + } + var emailInfo dto.AlertEmailConfig + err = json.Unmarshal([]byte(emailConfig.Config), &emailInfo) + if err != nil { + return err + } + if emailInfo.Host == "" { + create.Message = "email config is required" + create.Status = constant.AlertError + return SaveAlertLog(create, &alertLog) + } if !global.IsMaster && cfg.IsOffline == constant.StatusEnable { create.Status = constant.AlertPushing return SaveAlertLog(create, &alertLog) } else { - emailConfig, err := alertRepo.GetConfig(alertRepo.WithByType(constant.EmailConfig)) - if err != nil { - return err - } - var emailInfo dto.AlertEmailConfig - err = json.Unmarshal([]byte(emailConfig.Config), &emailInfo) - if err != nil { - return err - } username := emailInfo.UserName if username == "" { username = emailInfo.Sender @@ -76,7 +81,7 @@ func CreateEmailAlertLog(create dto.AlertLogCreate, alert dto.AlertDTO, params [ Encryption: emailInfo.Encryption, Recipient: emailInfo.Recipient, } - content := GetEmailContent(alert.Type, params, agentInfo) + content := GetSendContent(alert.Type, params, agentInfo) if content == "" { content = i18n.GetMsgWithMap("CommonAlert", map[string]interface{}{"msg": alert.Title}) } @@ -122,6 +127,7 @@ func CreateNewAlertTask(quota, alertType, quotaType, method string) { if err != nil { global.LOG.Errorf("error creating alert tasks, err: %v", err) } + global.LOG.Infof("%s alert %s push completed", alertType, method) } func ProcessAlertDetail(alert dto.AlertDTO, project string, params []dto.Param, method string) string { @@ -300,7 +306,7 @@ func isWithinTimeRange(savedTimeString string) bool { return now.After(skipTime) && now.Before(endSkipTime) } -func GetEmailContent(alertType string, params []dto.Param, agentInfo *dto.AgentInfo) string { +func GetSendContent(alertType string, params []dto.Param, agentInfo *dto.AgentInfo) string { switch GetCronJobType(alertType) { case "ssl": return i18n.GetMsgWithMap("SSLAlert", map[string]interface{}{"num": getValueByIndex(params, "1"), "day": getValueByIndex(params, "2"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)}) diff --git a/agent/utils/alert_push/alert_push.go b/agent/utils/alert_push/alert_push.go index 8ea04a9dce50..ac32310027f6 100644 --- a/agent/utils/alert_push/alert_push.go +++ b/agent/utils/alert_push/alert_push.go @@ -42,9 +42,12 @@ func PushAlert(pushAlert dto.PushAlert) error { AlertId: alert.ID, Count: todayCount + 1, } - _ = xpack.CreateTaskScanSMSAlertLog(alert, alert.Type, create, pushAlert, constant.SMS) + err = xpack.CreateTaskScanSMSAlertLog(alert, alert.Type, create, pushAlert, constant.SMS) + if err != nil { + global.LOG.Errorf("%s alert sms push failed: %v", alert.Type, err) + continue + } alertUtil.CreateNewAlertTask(strconv.Itoa(int(pushAlert.EntryID)), alertUtil.GetCronJobType(alert.Type), strconv.Itoa(int(pushAlert.EntryID)), constant.SMS) - global.LOG.Infof("%s %s alert push successful", alert.Type, constant.SMS) case constant.Email: todayCount, _, err := alertRepo.LoadTaskCount(alertUtil.GetCronJobType(alert.Type), strconv.Itoa(int(pushAlert.EntryID)), constant.Email) if err != nil || alert.SendCount <= todayCount { @@ -59,10 +62,28 @@ func PushAlert(pushAlert dto.PushAlert) error { agentInfo, _ := xpack.GetAgentInfo() err = alertUtil.CreateTaskScanEmailAlertLog(alert, create, pushAlert, constant.Email, transport, agentInfo) if err != nil { - return err + global.LOG.Errorf("%s alert email push failed: %v", alert.Type, err) + continue } alertUtil.CreateNewAlertTask(strconv.Itoa(int(pushAlert.EntryID)), alertUtil.GetCronJobType(alert.Type), strconv.Itoa(int(pushAlert.EntryID)), constant.Email) - global.LOG.Infof("%s %s alert push successful", alert.Type, constant.Email) + case constant.WeCom, constant.DingTalk, constant.FeiShu: + todayCount, _, err := alertRepo.LoadTaskCount(alertUtil.GetCronJobType(alert.Type), strconv.Itoa(int(pushAlert.EntryID)), m) + if err != nil || alert.SendCount <= todayCount { + continue + } + var create = dto.AlertLogCreate{ + Type: alertUtil.GetCronJobType(alert.Type), + AlertId: alert.ID, + Count: todayCount + 1, + } + transport := xpack.LoadRequestTransport() + agentInfo, _ := xpack.GetAgentInfo() + err = xpack.CreateTaskScanWebhookAlertLog(alert, alert.Type, create, pushAlert, m, transport, agentInfo) + if err != nil { + global.LOG.Errorf("%s alert %s webhook push failed: %v", alert.Type, m, err) + continue + } + alertUtil.CreateNewAlertTask(strconv.Itoa(int(pushAlert.EntryID)), alertUtil.GetCronJobType(alert.Type), strconv.Itoa(int(pushAlert.EntryID)), m) default: } } diff --git a/agent/utils/xpack/xpack.go b/agent/utils/xpack/xpack.go index 42e5c15efab9..dfaff10dc12f 100644 --- a/agent/utils/xpack/xpack.go +++ b/agent/utils/xpack/xpack.go @@ -61,6 +61,14 @@ func CreateSMSAlertLog(alertType string, info dto.AlertDTO, create dto.AlertLogC return nil } +func CreateTaskScanWebhookAlertLog(alert dto.AlertDTO, alertType string, create dto.AlertLogCreate, pushAlert dto.PushAlert, method string, transport *http.Transport, agentInfo *dto.AgentInfo) error { + return nil +} + +func CreateWebhookAlertLog(alertType string, info dto.AlertDTO, create dto.AlertLogCreate, project string, params []dto.Param, method string, transport *http.Transport, agentInfo *dto.AgentInfo) error { + return nil +} + func GetLicenseErrorAlert() (uint, error) { return 0, nil } diff --git a/core/constant/alert.go b/core/constant/alert.go index 1ca1d9ec40cd..bf7709cbcebe 100644 --- a/core/constant/alert.go +++ b/core/constant/alert.go @@ -7,4 +7,5 @@ const ( WeCom = "weCom" DingTalk = "dingTalk" FeiShu = "feiShu" + Custom = "custom" ) diff --git a/frontend/src/api/interface/alert.ts b/frontend/src/api/interface/alert.ts index ad168f2baf8c..66aaba141919 100644 --- a/frontend/src/api/interface/alert.ts +++ b/frontend/src/api/interface/alert.ts @@ -159,9 +159,57 @@ export namespace Alert { recipient: string; } + export interface CommonAlertConfig { + id?: number; + type: string; + title: string; + status: string; + config: CommonConfig; + } + export interface CommonConfig { isOffline?: string; alertDailyNum?: number; alertSendTimeRange?: string; } + + export interface EmailConfig { + id?: number; + type: string; + title: string; + status: string; + config: { + status?: string; + sender?: string; + userName?: string; + password?: string; + displayName?: string; + host?: string; + port?: number; + encryption?: string; + recipient?: string; + }; + } + + export interface SmsConfig { + id?: number; + type: string; + title: string; + status: string; + config: { + phone?: string; + alertDailyNum?: number; + }; + } + + export interface WebhookConfig { + id?: number; + type: string; + title: string; + status: string; + config: { + displayName?: string; + url?: string; + }; + } } diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index a8f950900b92..316ef0ab7fb5 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -3935,7 +3935,7 @@ const message = { alertCount: 'Alert Count', clamHelper: 'Trigger alert when scanning infected files', cronJobHelper: 'Trigger alert when task execution fails', - licenseHelper: 'Professional version supports SMS alert', + licenseHelper: 'Professional version supports more alert', alertCountHelper: 'Maximum daily alarm frequency', alert: 'SMS Alert', logs: 'Alert Logs', @@ -4137,6 +4137,13 @@ const message = { panelLoginRule: 'Panel login alert, sent {0} times per day', sshLoginRule: 'SSH login alert, sent {0} times per day', userNameHelper: 'Username is empty, the sender address will be used by default', + alertConfigHelper: 'Configure alert notification channels to receive panel message push', + weComConfigHelper: 'WeCom alert notification configuration', + wechatConfigHelper: 'WeChat Official Account alert notification configuration', + dingTalkConfigHelper: 'DingTalk alert notification configuration', + feiShuConfigHelper: 'Feishu alert notification configuration', + webhookName: 'Bot name or remark', + webhookUrl: 'Webhook URL', }, theme: { lingXiaGold: 'Ling Xia Gold', diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts index afaa8c83ed23..b4f66332f6fe 100644 --- a/frontend/src/lang/modules/es-es.ts +++ b/frontend/src/lang/modules/es-es.ts @@ -3902,7 +3902,7 @@ const message = { alertCount: 'Número de alertas', clamHelper: 'Generar alerta al detectar archivos infectados en escaneo', cronJobHelper: 'Generar alerta cuando falle la ejecución de una tarea programada', - licenseHelper: 'La versión Pro soporta alertas SMS', + licenseHelper: 'La versión Pro soporta alertas', alertCountHelper: 'Frecuencia máxima diaria de alertas', alert: 'Alerta SMS', logs: 'Logs de alertas', @@ -4095,6 +4095,13 @@ const message = { panelLoginRule: 'Alerta de login en panel, {0} envíos/día', sshLoginRule: 'Alerta de login SSH, {0} envíos/día', userNameHelper: 'El nombre de usuario está vacío, se usará la dirección del remitente por defecto', + alertConfigHelper: 'Configurar canales de notificación de alerta para recibir mensajes push del panel', + weComConfigHelper: 'Configuración de notificación de alerta WeCom', + wechatConfigHelper: 'Configuración de notificación de alerta de Cuenta Oficial WeChat', + dingTalkConfigHelper: 'Configuración de notificación de alerta DingTalk', + feiShuConfigHelper: 'Configuración de notificación de alerta Feishu', + webhookName: 'Nombre del bot o nota', + webhookUrl: 'URL de Webhook', }, theme: { lingXiaGold: 'Ling Xia Gold', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index 5fd38c1add29..b69833318b3d 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -3825,7 +3825,7 @@ const message = { alertCount: 'アラート数', clamHelper: '感染したファイルをスキャンするときにアラートをトリガーします', cronJobHelper: 'タスクの実行が失敗したときにアラートをトリガーします', - licenseHelper: 'プロのバージョンはSMSアラートをサポートします', + licenseHelper: 'プロのバージョンはアラートをサポートします', alertCountHelper: '最大毎日のアラーム周波数', alert: 'SMSアラート', logs: 'アラートログ', @@ -4023,6 +4023,13 @@ const message = { panelLoginRule: 'パネルログインアラートは、1日あたり{0}回送信', sshLoginRule: 'SSHログインアラートは、1日あたり{0}回送信', userNameHelper: 'ユーザー名が空の場合、送信者のアドレスがデフォルトで使用されます', + alertConfigHelper: 'パネルメッセージプッシュを受信するためのアラート通知チャネルを設定', + weComConfigHelper: 'WeComアラート通知設定', + wechatConfigHelper: 'WeChat公式アカウントアラート通知設定', + dingTalkConfigHelper: 'DingTalkアラート通知設定', + feiShuConfigHelper: 'Feishuアラート通知設定', + webhookName: 'ボット名または', + webhookUrl: 'Webhook URL', }, theme: { lingXiaGold: '凌霞金', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 3dfda945583c..0c4bae3b462c 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -3753,7 +3753,7 @@ const message = { alertCount: '알림 횟수', clamHelper: '감염된 파일을 스캔할 때 알림 트리거', cronJobHelper: '작업 실행 실패 시 알림 트리거', - licenseHelper: '전문 버전에서는 SMS 알림을 지원합니다.', + licenseHelper: '전문 버전에서는 알림을 지원합니다.', alertCountHelper: '최대 일일 알림 빈도', alert: 'SMS 알림', logs: '알림 로그', @@ -3946,6 +3946,13 @@ const message = { panelLoginRule: '패널 로그인 알림은 하루 {0}회 전송', sshLoginRule: 'SSH 로그인 알림은 하루 {0}회 전송', userNameHelper: '사용자 이름이 비어 있으면 기본적으로 발신자 주소가 사용됩니다', + alertConfigHelper: '패널 메시지 푸시를 수신하기 위한 알림 채널 구성', + weComConfigHelper: 'WeCom 알림 구성', + wechatConfigHelper: 'WeChat 공식 계정 알림 구성', + dingTalkConfigHelper: 'DingTalk 알림 구성', + feiShuConfigHelper: 'Feishu 알림 구성', + webhookName: '봇 이름 또는 비고', + webhookUrl: 'Webhook URL', }, theme: { lingXiaGold: '링샤 골드', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index e2866a0287ff..1100d2d8fdd5 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -3895,7 +3895,7 @@ const message = { alertCount: 'Bilangan Amaran', clamHelper: 'Hantar amaran apabila terdapat fail yang dijangkiti semasa imbasan', cronJobHelper: 'Hantar amaran apabila pelaksanaan tugas gagal', - licenseHelper: 'Versi profesional menyokong amaran SMS', + licenseHelper: 'Versi profesional menyokong amaran', alertCountHelper: 'Kekerapan maksimum amaran harian', alert: 'Amaran SMS', logs: 'Log Amaran', @@ -4101,6 +4101,13 @@ const message = { panelLoginRule: 'Amaran log masuk panel, dihantar {0} kali sehari', sshLoginRule: 'Amaran log masuk SSH, dihantar {0} kali sehari', userNameHelper: 'Nama pengguna kosong, alamat penghantar akan digunakan secara lalai', + alertConfigHelper: 'Konfigurasikan saluran pemberitahuan amaran untuk menerima tolakan mesej panel', + weComConfigHelper: 'Konfigurasi pemberitahuan amaran WeCom', + wechatConfigHelper: 'Konfigurasi pemberitahuan amaran Akaun Rasmi WeChat', + dingTalkConfigHelper: 'Konfigurasi pemberitahuan amaran DingTalk', + feiShuConfigHelper: 'Konfigurasi pemberitahuan amaran Feishu', + webhookName: 'Nama bot atau catatan', + webhookUrl: 'URL Webhook', }, theme: { lingXiaGold: 'Ling Xia Emas', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index df57980dfe60..ae6b36c8cb67 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -3916,7 +3916,7 @@ const message = { alertCount: 'Contagem de Alertas', clamHelper: 'Dispara alerta via ao detectar arquivos infectados durante a varredura', cronJobHelper: 'Dispara alerta via ao falhar na execução de tarefas', - licenseHelper: 'A versão profissional suporta alertas via SMS', + licenseHelper: 'A versão profissional suporta alertas via', alertCountHelper: 'Frequência máxima diária de alertas', alert: 'Alerta por SMS', logs: 'Registros de Alerta', @@ -4121,6 +4121,13 @@ const message = { panelLoginRule: 'Alerta de login no painel, enviado {0} vezes por dia', sshLoginRule: 'Alerta de login SSH, enviado {0} vezes por dia', userNameHelper: 'O nome de usuário está vazio, o endereço do remetente será usado por padrão', + alertConfigHelper: 'Configurar canais de notificação de alerta para receber push de mensagens do painel', + weComConfigHelper: 'Configuração de notificação de alerta WeCom', + wechatConfigHelper: 'Configuração de notificação de alerta da Conta Oficial WeChat', + dingTalkConfigHelper: 'Configuração de notificação de alerta DingTalk', + feiShuConfigHelper: 'Configuração de notificação de alerta Feishu', + webhookName: 'Nome do bot ou observação', + webhookUrl: 'URL do Webhook', }, theme: { lingXiaGold: 'Ling Xia Gold', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index 6056996a0d40..11c33b3242d3 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -3903,7 +3903,7 @@ const message = { alertCount: 'Количество оповещений', clamHelper: 'Отправлять оповещение при обнаружении зараженных файлов', cronJobHelper: 'Отправлять оповещение при сбое выполнения задачи', - licenseHelper: 'Профессиональная версия поддерживает SMS-оповещения', + licenseHelper: 'Профессиональная версия поддерживает оповещения', alertCountHelper: 'Максимальная дневная частота оповещений', alert: 'SMS Уведомление', logs: 'Журнал Уведомлений', @@ -4112,6 +4112,13 @@ const message = { panelLoginRule: 'Оповещение о входе в панель, отправляется {0} раз в день', sshLoginRule: 'Оповещение о входе по SSH, отправляется {0} раз в день', userNameHelper: 'Имя пользователя не указано, по умолчанию будет использоваться адрес отправителя', + alertConfigHelper: 'Настройка каналов уведомлений для получения push-уведомлений от панели', + weComConfigHelper: 'Конфигурация уведомлений WeCom', + wechatConfigHelper: 'Конфигурация уведомлений официального аккаунта WeChat', + dingTalkConfigHelper: 'Конфигурация уведомлений DingTalk', + feiShuConfigHelper: 'Конфигурация уведомлений Feishu', + webhookName: 'Имя бота или примечание', + webhookUrl: 'URL Webhook', }, theme: { lingXiaGold: 'Лин Ся Золотой', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index 8d3ac7247cf4..44f59bd23cb0 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -3975,7 +3975,7 @@ const message = { alertCount: 'Uyarı Sayısı', clamHelper: 'Enfekte dosyalar tarandığında uyarısını tetikle', cronJobHelper: 'Görev yürütme başarısız olduğunda uyarısını tetikle', - licenseHelper: 'Profesyonel sürüm SMS uyarısını destekler', + licenseHelper: 'Profesyonel sürüm more uyarısını destekler', alertCountHelper: 'Günlük maksimum uyarı sıklığı', alert: 'SMS Uyarısı', logs: 'Uyarı Günlükleri', @@ -4182,6 +4182,13 @@ const message = { panelLoginRule: 'Panel girişi uyarısı, günde {0} kez gönderilir', sshLoginRule: 'SSH girişi uyarısı, günde {0} kez gönderilir', userNameHelper: 'Kullanıcı adı boşsa, varsayılan olarak gönderici adresi kullanılacaktır', + alertConfigHelper: 'Panel mesaj gönderimini almak için uyarı bildirim kanallarını yapılandırın', + weComConfigHelper: 'WeCom uyarı bildirim yapılandırması', + wechatConfigHelper: 'WeChat Resmi Hesap uyarı bildirim yapılandırması', + dingTalkConfigHelper: 'DingTalk uyarı bildirim yapılandırması', + feiShuConfigHelper: 'Feishu uyarı bildirim yapılandırması', + webhookName: 'Bot adı veya not', + webhookUrl: 'Webhook URL', }, theme: { lingXiaGold: 'Ling Xia Altın', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index 3fb222d1eda0..203f1e08a78a 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -3627,7 +3627,7 @@ const message = { alertCount: '告警次數', clamHelper: '掃描到感染檔案時觸發告警', cronJobHelper: '定時任務執行失敗時將觸發告警', - licenseHelper: '專業版支援簡訊告警功能', + licenseHelper: '專業版支援更多告警功能', alertCountHelper: '每日最大告警次數', alert: '簡訊告警', logs: '告警日誌', @@ -3821,6 +3821,13 @@ const message = { panelLoginRule: '面板登入告警,每天發送 {0} 次', sshLoginRule: 'SSH 登入告警,每天發送 {0} 次', userNameHelper: '使用者名稱為空時,將預設使用寄件者地址', + alertConfigHelper: '配置告警通知通道,用於接收面板訊息推送', + weComConfigHelper: '企業微信告警通知配置', + wechatConfigHelper: '微信公眾號告警通知配置', + dingTalkConfigHelper: '釘釘告警通知配置', + feiShuConfigHelper: '飛書告警通知配置', + webhookName: '機器人名稱', + webhookUrl: 'Webhook 位址', }, theme: { lingXiaGold: '凌霞金', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index dea62f6a3b17..e4671cb4f0a8 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -3620,7 +3620,7 @@ const message = { alertCount: '告警次数', clamHelper: '扫描到感染文件时触发告警通知', cronJobHelper: '定时任务执行失败时将触发告警通知', - licenseHelper: '专业版支持短信告警功能', + licenseHelper: '专业版支持更多告警功能', alertCountHelper: '每日最大告警次数', alert: '短信告警', logs: '告警日志', @@ -3810,6 +3810,13 @@ const message = { panelLoginRule: '面板登录告警,每天发送 {0} 次', sshLoginRule: 'SSH 登录告警告警,每天发送 {0} 次', userNameHelper: '用户名为空会默认使用发件箱地址', + alertConfigHelper: '配置告警通知通道,用于接收面板消息推送', + weComConfigHelper: '企业微信告警通知配置', + wechatConfigHelper: '微信公众号告警通知配置', + dingTalkConfigHelper: '钉钉告警通知配置', + feiShuConfigHelper: '飞书告警通知配置', + webhookName: '机器人名称', + webhookUrl: 'Webhook 地址', }, theme: { lingXiaGold: '凌霞金', diff --git a/frontend/src/views/cronjob/cronjob/operate/index.vue b/frontend/src/views/cronjob/cronjob/operate/index.vue index 11b734952593..4338ceba3701 100644 --- a/frontend/src/views/cronjob/cronjob/operate/index.vue +++ b/frontend/src/views/cronjob/cronjob/operate/index.vue @@ -722,6 +722,24 @@ :disabled="!form.hasAlert || !isProductPro" :label="$t('xpack.alert.sms')" /> + + + diff --git a/frontend/src/views/setting/alert/dash/task/index.vue b/frontend/src/views/setting/alert/dash/task/index.vue index e77c02636c67..fecb35333d12 100644 --- a/frontend/src/views/setting/alert/dash/task/index.vue +++ b/frontend/src/views/setting/alert/dash/task/index.vue @@ -328,6 +328,24 @@ :disabled="!globalStore.isProductPro" :label="$t('xpack.alert.sms')" /> + + + diff --git a/frontend/src/views/setting/alert/log/index.vue b/frontend/src/views/setting/alert/log/index.vue index 66d06b62ce2d..2699906e34c2 100644 --- a/frontend/src/views/setting/alert/log/index.vue +++ b/frontend/src/views/setting/alert/log/index.vue @@ -214,7 +214,24 @@ const formatMessage = (row: Alert.AlertInfo) => { }; const formatMethod = (row: Alert.AlertLog) => { - return row.method === 'mail' ? t('xpack.alert.mail') : t('xpack.alert.sms'); + switch (row.method) { + case 'mail': + return t('xpack.alert.mail'); + case 'sms': + return t('xpack.alert.sms'); + case 'dingTalk': + return t('xpack.alert.dingTalk'); + case 'weCom': + return t('xpack.alert.weCom'); + case 'feiShu': + return t('xpack.alert.feiShu'); + case 'wechat': + return t('xpack.alert.wechat'); + case 'webhook': + return t('xpack.alert.webhook'); + default: + return t('xpack.alert.unknown'); + } }; const formatCount = (row: Alert.AlertInfo) => { diff --git a/frontend/src/views/setting/alert/setting/index.vue b/frontend/src/views/setting/alert/setting/index.vue index e223e3822212..f2e5dad8c1c4 100644 --- a/frontend/src/views/setting/alert/setting/index.vue +++ b/frontend/src/views/setting/alert/setting/index.vue @@ -40,7 +40,22 @@ @@ -148,6 +313,7 @@ + @@ -162,6 +328,7 @@ import i18n from '@/lang'; import { storeToRefs } from 'pinia'; import { MsgSuccess } from '@/utils/message'; import EmailDrawer from '@/views/setting/alert/setting/email/index.vue'; +import WebhookDrawer from '@/views/setting/alert/setting/webhook/index.vue'; import { Alert } from '@/api/interface/alert'; import { getLicenseSmsInfo } from '@/api/modules/setting'; @@ -172,29 +339,13 @@ const loading = ref(false); const alertFormRef = ref(); const phoneRef = ref(); const emailRef = ref(); +const webHookRef = ref(); const sendTimeRangeRef = ref(); const sendTimeRangeValue = ref(); const sendTimeRange = ref(); const isInitialized = ref(false); -export interface EmailConfig { - id?: number; - type: string; - title: string; - status: string; - config: { - status?: string; - sender?: string; - userName?: string; - password?: string; - displayName?: string; - host?: string; - port?: number; - encryption?: string; - recipient?: string; - }; -} -const defaultEmailConfig: EmailConfig = { +const defaultEmailConfig: Alert.EmailConfig = { id: undefined, type: 'email', title: 'xpack.alert.emailConfig', @@ -211,19 +362,9 @@ const defaultEmailConfig: EmailConfig = { recipient: '', }, }; -const emailConfig = ref({ ...defaultEmailConfig }); +const emailConfig = ref({ ...defaultEmailConfig }); -export interface CommonConfig { - id?: number; - type: string; - title: string; - status: string; - config: { - isOffline?: string; - alertSendTimeRange?: string; - }; -} -const defaultCommonConfig: CommonConfig = { +const defaultCommonConfig: Alert.CommonConfig = { id: undefined, type: 'common', title: 'xpack.alert.commonConfig', @@ -241,19 +382,9 @@ const defaultCommonConfig: CommonConfig = { }, }; -const commonConfig = ref({ ...defaultCommonConfig }); +const commonConfig = ref({ ...defaultCommonConfig }); -export interface SmsConfig { - id?: number; - type: string; - title: string; - status: string; - config: { - phone?: string; - alertDailyNum?: number; - }; -} -const defaultSmsConfig: SmsConfig = { +const defaultSmsConfig: Alert.SmsConfig = { id: undefined, type: 'sms', title: 'xpack.alert.smsConfig', @@ -263,7 +394,43 @@ const defaultSmsConfig: SmsConfig = { alertDailyNum: 50, }, }; -const smsConfig = ref({ ...defaultSmsConfig }); +const smsConfig = ref({ ...defaultSmsConfig }); + +const defaultWeComConfig: Alert.WebhookConfig = { + id: undefined, + type: 'weCom', + title: 'xpack.alert.weCom', + status: 'Enable', + config: { + displayName: '', + url: '', + }, +}; +const weComConfig = ref({ ...defaultWeComConfig }); + +const defaultDingTalkConfig: Alert.WebhookConfig = { + id: undefined, + type: 'dingTalk', + title: 'xpack.alert.dingTalk', + status: 'Enable', + config: { + displayName: '', + url: '', + }, +}; +const dingTalkConfig = ref({ ...defaultDingTalkConfig }); + +const defaultFeiShuConfig: Alert.WebhookConfig = { + id: undefined, + type: 'feiShu', + title: 'xpack.alert.feiShu', + status: 'Enable', + config: { + displayName: '', + url: '', + }, +}; +const feiShuConfig = ref({ ...defaultFeiShuConfig }); const config = ref({ id: 0, @@ -329,6 +496,15 @@ const search = async () => { i18n.global.t('xpack.alert.resourceAlert') + ': ' + resourceTimeRange; + + const weComFound = res.data.find((s: any) => s.type === 'weCom'); + assignConfig(weComFound, weComConfig, defaultWeComConfig); + + const dingTalkFound = res.data.find((s: any) => s.type === 'dingTalk'); + assignConfig(dingTalkFound, dingTalkConfig, defaultDingTalkConfig); + + const feiShuFound = res.data.find((s: any) => s.type === 'feiShu'); + assignConfig(feiShuFound, feiShuConfig, defaultFeiShuConfig); isInitialized.value = true; } finally { loading.value = false; @@ -416,6 +592,33 @@ const goBuy = async () => { window.open('https://www.lxware.cn/uc/cloud/licenses/' + uri, '_blank', 'noopener,noreferrer'); }; +const onChangeWeCom = (id: number) => { + webHookRef.value.acceptParams({ + id: id, + config: weComConfig.value.config, + type: 'weCom', + title: weComConfig.value.title, + }); +}; + +const onChangeDingTalk = (id: number) => { + webHookRef.value.acceptParams({ + id: id, + config: dingTalkConfig.value.config, + type: 'dingTalk', + title: dingTalkConfig.value.title, + }); +}; + +const onChangeFeiShu = (id: number) => { + webHookRef.value.acceptParams({ + id: id, + config: feiShuConfig.value.config, + type: 'feiShu', + title: feiShuConfig.value.title, + }); +}; + onMounted(async () => { await search(); if (globalStore.isProductPro && !globalStore.isIntl) { @@ -427,7 +630,7 @@ onMounted(async () => { .label { color: var(--el-text-color-placeholder); } -.email-form { +.config-form { .el-form-item { margin-bottom: 0 !important; } diff --git a/frontend/src/views/setting/alert/setting/webhook/index.vue b/frontend/src/views/setting/alert/setting/webhook/index.vue new file mode 100644 index 000000000000..ff4106a8a007 --- /dev/null +++ b/frontend/src/views/setting/alert/setting/webhook/index.vue @@ -0,0 +1,113 @@ + + diff --git a/frontend/src/views/toolbox/clam/operate/index.vue b/frontend/src/views/toolbox/clam/operate/index.vue index 8ab32b5a5f9e..f2eb86fa84a6 100644 --- a/frontend/src/views/toolbox/clam/operate/index.vue +++ b/frontend/src/views/toolbox/clam/operate/index.vue @@ -160,6 +160,24 @@ :disabled="!dialogData.rowData!.hasAlert || !isProductPro" :label="$t('xpack.alert.sms')" /> + + +