diff --git a/README.md b/README.md
index 016f75c..56be6b0 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
LOGO designed by 熊大 .
-
+
:trollface: Nezha Monitoring: Self-hostable, lightweight, servers and websites monitoring and O&M tool.
diff --git a/cmd/dashboard/controller/member_api.go b/cmd/dashboard/controller/member_api.go index 23b8f0b..4d82d52 100644 --- a/cmd/dashboard/controller/member_api.go +++ b/cmd/dashboard/controller/member_api.go @@ -41,6 +41,7 @@ func (ma *memberAPI) serve() { mr.GET("/cron/:id/manual", ma.manualTrigger) mr.POST("/force-update", ma.forceUpdate) mr.POST("/batch-update-server-group", ma.batchUpdateServerGroup) + mr.POST("/batch-delete-server", ma.batchDeleteServer) mr.POST("/notification", ma.addOrEditNotification) mr.POST("/alert-rule", ma.addOrEditAlertRule) mr.POST("/setting", ma.updateSetting) @@ -187,37 +188,9 @@ func (ma *memberAPI) delete(c *gin.Context) { if err == nil { // 删除服务器 singleton.ServerLock.Lock() - tag := singleton.ServerList[id].Tag - delete(singleton.SecretToID, singleton.ServerList[id].Secret) - delete(singleton.ServerList, id) - index := -1 - for i := 0; i < len(singleton.ServerTagToIDList[tag]); i++ { - if singleton.ServerTagToIDList[tag][i] == id { - index = i - break - } - } - if index > -1 { - // 删除旧 Tag-ID 绑定关系 - singleton.ServerTagToIDList[tag] = append(singleton.ServerTagToIDList[tag][:index], singleton.ServerTagToIDList[tag][index+1:]...) - if len(singleton.ServerTagToIDList[tag]) == 0 { - delete(singleton.ServerTagToIDList, tag) - } - } + onServerDelete(id) singleton.ServerLock.Unlock() singleton.ReSortServer() - // 删除循环流量状态中的此服务器相关的记录 - singleton.AlertsLock.Lock() - for i := 0; i < len(singleton.Alerts); i++ { - if singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID] != nil { - delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].ServerName, id) - delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].Transfer, id) - delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].NextUpdate, id) - } - } - singleton.AlertsLock.Unlock() - // 删除服务器相关循环流量记录 - singleton.DB.Unscoped().Delete(&model.Transfer{}, "server_id = ?", id) } case "notification": err = singleton.DB.Unscoped().Delete(&model.Notification{}, "id = ?", id).Error @@ -446,10 +419,12 @@ func (ma *memberAPI) addOrEditMonitor(c *gin.Context) { if err == nil { err = utils.Json.Unmarshal([]byte(mf.RecoverTriggerTasksRaw), &m.RecoverTriggerTasks) } - if m.ID == 0 { - err = singleton.DB.Create(&m).Error - } else { - err = singleton.DB.Save(&m).Error + if err == nil { + if m.ID == 0 { + err = singleton.DB.Create(&m).Error + } else { + err = singleton.DB.Save(&m).Error + } } } if err == nil { @@ -933,3 +908,63 @@ func (ma *memberAPI) updateSetting(c *gin.Context) { Code: http.StatusOK, }) } + +func (ma *memberAPI) batchDeleteServer(c *gin.Context) { + var servers []uint64 + if err := c.ShouldBindJSON(&servers); err != nil { + c.JSON(http.StatusOK, model.Response{ + Code: http.StatusBadRequest, + Message: err.Error(), + }) + return + } + if err := singleton.DB.Unscoped().Delete(&model.Server{}, "id in (?)", servers).Error; err != nil { + c.JSON(http.StatusOK, model.Response{ + Code: http.StatusBadRequest, + Message: err.Error(), + }) + return + } + singleton.ServerLock.Lock() + for i := 0; i < len(servers); i++ { + id := servers[i] + onServerDelete(id) + } + singleton.ServerLock.Unlock() + singleton.ReSortServer() + c.JSON(http.StatusOK, model.Response{ + Code: http.StatusOK, + }) +} + +func onServerDelete(id uint64) { + tag := singleton.ServerList[id].Tag + delete(singleton.SecretToID, singleton.ServerList[id].Secret) + delete(singleton.ServerList, id) + index := -1 + for i := 0; i < len(singleton.ServerTagToIDList[tag]); i++ { + if singleton.ServerTagToIDList[tag][i] == id { + index = i + break + } + } + if index > -1 { + + singleton.ServerTagToIDList[tag] = append(singleton.ServerTagToIDList[tag][:index], singleton.ServerTagToIDList[tag][index+1:]...) + if len(singleton.ServerTagToIDList[tag]) == 0 { + delete(singleton.ServerTagToIDList, tag) + } + } + + singleton.AlertsLock.Lock() + for i := 0; i < len(singleton.Alerts); i++ { + if singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID] != nil { + delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].ServerName, id) + delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].Transfer, id) + delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].NextUpdate, id) + } + } + singleton.AlertsLock.Unlock() + + singleton.DB.Unscoped().Delete(&model.Transfer{}, "server_id = ?", id) +} diff --git a/resource/l10n/en-US.toml b/resource/l10n/en-US.toml index 0189c80..b0f9c04 100644 --- a/resource/l10n/en-US.toml +++ b/resource/l10n/en-US.toml @@ -202,6 +202,9 @@ other = "Add Server" [BatchEditServerGroup] other = "Batch Modify Groups" +[BatchDeleteServer] +other = "Batch Delete Server" + [InputServerGroupName] other = "Enter the name of the group" @@ -307,7 +310,7 @@ other = "Click To Copy" [DeleteServer] other = "Delete Server" -[ConfirmToDeleteThisServer] +[ConfirmToDeleteServer] other = "Confirm Delete?" [NoServerSelected] diff --git a/resource/l10n/es-ES.toml b/resource/l10n/es-ES.toml index ced85e4..8aee21e 100644 --- a/resource/l10n/es-ES.toml +++ b/resource/l10n/es-ES.toml @@ -202,6 +202,9 @@ other = "Añadir un servidor" [BatchEditServerGroup] other = "Modificación de grupos por lotes" +[BatchDeleteServer] +other = "Batch Delete Server" + [InputServerGroupName] other = "Introduzca un nombre de grupo" @@ -307,8 +310,8 @@ other = "Haga clic para copiar" [DeleteServer] other = "Eliminar el servidor" -[ConfirmToDeleteThisServer] -other = "¿Confirma que quiere eliminar este servidor?" +[ConfirmToDeleteServer] +other = "¿Confirma que quiere eliminar servidor?" [NoServerSelected] other = "No hay servidores seleccionados actualmente" diff --git a/resource/l10n/zh-CN.toml b/resource/l10n/zh-CN.toml index 710c149..998e507 100644 --- a/resource/l10n/zh-CN.toml +++ b/resource/l10n/zh-CN.toml @@ -202,6 +202,9 @@ other = "添加服务器" [BatchEditServerGroup] other = "批量修改分组" +[BatchDeleteServer] +other = "批量删除服务器" + [InputServerGroupName] other = "输入分组名称" @@ -307,8 +310,8 @@ other = "点击复制" [DeleteServer] other = "删除主机" -[ConfirmToDeleteThisServer] -other = "确认删除此主机?" +[ConfirmToDeleteServer] +other = "确认删除主机?" [NoServerSelected] other = "当前没有选中的服务器" diff --git a/resource/l10n/zh-TW.toml b/resource/l10n/zh-TW.toml index f27511d..5714c11 100644 --- a/resource/l10n/zh-TW.toml +++ b/resource/l10n/zh-TW.toml @@ -202,6 +202,9 @@ other = "添加服務器" [BatchEditServerGroup] other = "批量修改分組" +[BatchDeleteServer] +other = "批量删除服务器" + [InputServerGroupName] other = "輸入分組名稱" @@ -307,8 +310,8 @@ other = "點擊複製" [DeleteServer] other = "刪除主機" -[ConfirmToDeleteThisServer] -other = "確認刪除此主機?" +[ConfirmToDeleteServer] +other = "確認刪除主機?" [NoServerSelected] other = "當前沒有選中的服務器" diff --git a/resource/static/main.js b/resource/static/main.js index edc5bf5..df5dd15 100644 --- a/resource/static/main.js +++ b/resource/static/main.js @@ -44,6 +44,30 @@ function showConfirm(title, content, callFn, extData) { .modal("show"); } +function postJson(url, data) { + return $.ajax({ + url: url, + type: "POST", + contentType: "application/json", + data: JSON.stringify(data), + }).done((resp) => { + if (resp.code == 200) { + if (resp.message) { + alert(resp.message); + } else { + alert("删除成功"); + } + window.location.reload(); + } else { + alert("删除失败 " + resp.code + ":" + resp.message); + confirmBtn.toggleClass("loading"); + } + }) + .fail((err) => { + alert("网络错误:" + err.responseText); + }); +} + function showFormModal(modelSelector, formID, URL, getData) { $(modelSelector) .modal({ @@ -344,11 +368,11 @@ function addOrEditMonitor(monitor) { const node = modal.find("i.dropdown.icon.specificServer"); for (let i = 0; i < serverList.length; i++) { node.after( - 'ID:' + - serverList[i] + - '' + 'ID:' + + serverList[i] + + '' ); } @@ -360,31 +384,31 @@ function addOrEditMonitor(monitor) { const node2 = modal.find("i.dropdown.icon.recoverTask"); for (let i = 0; i < failTriggerTasksList.length; i++) { node1.after( - 'ID:' + - failTriggerTasksList[i] + - '' + 'ID:' + + failTriggerTasksList[i] + + '' ); } for (let i = 0; i < recoverTriggerTasksList.length; i++) { node2.after( - 'ID:' + - recoverTriggerTasksList[i] + - '' + 'ID:' + + recoverTriggerTasksList[i] + + '' ); } } -modal + modal .find("input[name=FailTriggerTasksRaw]") .val(monitor ? "[]," + failTriggerTasks.substr(1, failTriggerTasks.length - 2) : "[]"); -modal + modal .find("input[name=RecoverTriggerTasksRaw]") .val(monitor ? "[]," + recoverTriggerTasks.substr(1, recoverTriggerTasks.length - 2) : "[]"); -modal + modal .find("input[name=SkipServersRaw]") .val(monitor ? "[]," + servers.substr(1, servers.length - 2) : "[]"); showFormModal(".monitor.modal", "#monitorForm", "/api/monitor"); diff --git a/resource/template/common/footer.html b/resource/template/common/footer.html index 3058f1d..cd733ef 100644 --- a/resource/template/common/footer.html +++ b/resource/template/common/footer.html @@ -10,7 +10,7 @@ - + {{end}} diff --git a/resource/template/theme-angel-kanade/footer.html b/resource/template/theme-angel-kanade/footer.html index 664c84e..13e0e0a 100644 --- a/resource/template/theme-angel-kanade/footer.html +++ b/resource/template/theme-angel-kanade/footer.html @@ -12,7 +12,7 @@ - +