2019-12-08 03:59:58 -05:00
package controller
import (
2021-11-04 00:06:20 -04:00
"bytes"
2020-12-19 23:18:27 -05:00
"errors"
2019-12-08 03:59:58 -05:00
"fmt"
"net/http"
2020-03-22 08:55:27 -04:00
"strconv"
2021-04-23 07:09:04 -04:00
"strings"
2024-08-11 22:06:55 -04:00
"sync"
2019-12-08 03:59:58 -05:00
"time"
"github.com/gin-gonic/gin"
2022-09-16 12:08:27 -04:00
"github.com/jinzhu/copier"
2024-10-17 09:03:03 -04:00
"golang.org/x/net/idna"
2024-02-12 01:16:04 -05:00
"gorm.io/gorm"
2019-12-08 03:59:58 -05:00
2020-11-10 21:07:45 -05:00
"github.com/naiba/nezha/model"
"github.com/naiba/nezha/pkg/mygin"
2021-01-18 20:59:04 -05:00
"github.com/naiba/nezha/pkg/utils"
2021-11-04 00:06:20 -04:00
"github.com/naiba/nezha/proto"
2023-11-28 10:01:37 -05:00
"github.com/naiba/nezha/resource"
2022-01-08 22:54:14 -05:00
"github.com/naiba/nezha/service/singleton"
2019-12-08 03:59:58 -05:00
)
type memberAPI struct {
r gin . IRouter
}
func ( ma * memberAPI ) serve ( ) {
mr := ma . r . Group ( "" )
mr . Use ( mygin . Authorize ( mygin . AuthorizeOption {
2024-02-24 10:21:33 -05:00
MemberOnly : true ,
IsPage : false ,
Msg : "访问此接口需要登录" ,
Btn : "点此登录" ,
Redirect : "/login" ,
2019-12-08 03:59:58 -05:00
} ) )
2021-01-20 09:15:47 -05:00
mr . GET ( "/search-server" , ma . searchServer )
2022-09-13 23:32:15 -04:00
mr . GET ( "/search-tasks" , ma . searchTask )
2024-10-17 09:03:03 -04:00
mr . GET ( "/search-ddns" , ma . searchDDNS )
2019-12-20 10:58:09 -05:00
mr . POST ( "/server" , ma . addOrEditServer )
2021-01-15 11:45:49 -05:00
mr . POST ( "/monitor" , ma . addOrEditMonitor )
2021-01-18 20:59:04 -05:00
mr . POST ( "/cron" , ma . addOrEditCron )
2021-01-23 20:41:35 -05:00
mr . GET ( "/cron/:id/manual" , ma . manualTrigger )
2021-11-04 00:06:20 -04:00
mr . POST ( "/force-update" , ma . forceUpdate )
2022-09-16 12:08:27 -04:00
mr . POST ( "/batch-update-server-group" , ma . batchUpdateServerGroup )
2023-06-13 12:23:47 -04:00
mr . POST ( "/batch-delete-server" , ma . batchDeleteServer )
2020-12-19 09:14:36 -05:00
mr . POST ( "/notification" , ma . addOrEditNotification )
2024-10-17 09:03:03 -04:00
mr . POST ( "/ddns" , ma . addOrEditDDNS )
2024-07-14 07:41:50 -04:00
mr . POST ( "/nat" , ma . addOrEditNAT )
2020-12-19 10:11:16 -05:00
mr . POST ( "/alert-rule" , ma . addOrEditAlertRule )
2020-12-09 06:05:40 -05:00
mr . POST ( "/setting" , ma . updateSetting )
2020-12-19 10:11:16 -05:00
mr . DELETE ( "/:model/:id" , ma . delete )
2021-01-20 09:15:47 -05:00
mr . POST ( "/logout" , ma . logout )
2022-05-17 22:10:35 -04:00
mr . GET ( "/token" , ma . getToken )
mr . POST ( "/token" , ma . issueNewToken )
mr . DELETE ( "/token/:token" , ma . deleteToken )
2022-05-16 23:21:27 -04:00
// API
2022-05-17 22:10:35 -04:00
v1 := ma . r . Group ( "v1" )
{
apiv1 := & apiV1 { v1 }
apiv1 . serve ( )
}
2022-05-16 23:21:27 -04:00
}
2022-05-17 22:10:35 -04:00
type apiResult struct {
Token string ` json:"token" `
2022-05-18 08:52:18 -04:00
Note string ` json:"note" `
2022-05-16 23:21:27 -04:00
}
2022-05-17 22:10:35 -04:00
// getToken 获取 Token
func ( ma * memberAPI ) getToken ( c * gin . Context ) {
u := c . MustGet ( model . CtxKeyAuthorizedUser ) . ( * model . User )
2022-05-17 22:28:24 -04:00
singleton . ApiLock . RLock ( )
2022-05-18 08:52:18 -04:00
defer singleton . ApiLock . RUnlock ( )
2022-05-17 22:10:35 -04:00
tokenList := singleton . UserIDToApiTokenList [ u . ID ]
res := make ( [ ] * apiResult , len ( tokenList ) )
for i , token := range tokenList {
res [ i ] = & apiResult {
Token : token ,
2022-05-18 08:52:18 -04:00
Note : singleton . ApiTokenList [ token ] . Note ,
2022-05-16 23:21:27 -04:00
}
}
2022-05-17 22:10:35 -04:00
c . JSON ( http . StatusOK , gin . H {
"code" : 0 ,
"message" : "success" ,
"result" : res ,
} )
}
2022-05-18 08:52:18 -04:00
type TokenForm struct {
Note string
}
2022-05-17 22:10:35 -04:00
// issueNewToken 生成新的 token
func ( ma * memberAPI ) issueNewToken ( c * gin . Context ) {
u := c . MustGet ( model . CtxKeyAuthorizedUser ) . ( * model . User )
2022-05-18 08:52:18 -04:00
tf := & TokenForm { }
err := c . ShouldBindJSON ( tf )
if err != nil {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "请求错误:%s" , err ) ,
} )
return
}
2022-12-16 10:34:14 -05:00
secureToken , err := utils . GenerateRandomString ( 32 )
if err != nil {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "请求错误:%s" , err ) ,
} )
return
}
2022-05-17 22:10:35 -04:00
token := & model . ApiToken {
UserID : u . ID ,
2022-12-16 10:34:14 -05:00
Token : secureToken ,
2022-05-18 08:52:18 -04:00
Note : tf . Note ,
2022-05-16 23:21:27 -04:00
}
2022-05-17 22:10:35 -04:00
singleton . DB . Create ( token )
2022-05-17 22:28:24 -04:00
singleton . ApiLock . Lock ( )
2022-05-17 22:10:35 -04:00
singleton . ApiTokenList [ token . Token ] = token
singleton . UserIDToApiTokenList [ u . ID ] = append ( singleton . UserIDToApiTokenList [ u . ID ] , token . Token )
2022-05-17 22:28:24 -04:00
singleton . ApiLock . Unlock ( )
2022-05-17 22:10:35 -04:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
Message : "success" ,
Result : map [ string ] string {
"token" : token . Token ,
2022-05-18 08:52:18 -04:00
"note" : token . Note ,
2022-05-17 22:10:35 -04:00
} ,
} )
}
// deleteToken 删除 token
func ( ma * memberAPI ) deleteToken ( c * gin . Context ) {
token := c . Param ( "token" )
if token == "" {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : "token 不能为空" ,
} )
2022-05-16 23:21:27 -04:00
return
}
2022-05-17 22:28:24 -04:00
singleton . ApiLock . Lock ( )
defer singleton . ApiLock . Unlock ( )
2022-05-17 22:10:35 -04:00
if _ , ok := singleton . ApiTokenList [ token ] ; ! ok {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : "token 不存在" ,
} )
2022-05-16 23:21:27 -04:00
return
}
2022-05-17 22:10:35 -04:00
// 在数据库中删除该Token
singleton . DB . Unscoped ( ) . Delete ( & model . ApiToken { } , "token = ?" , token )
2022-05-17 22:28:24 -04:00
2022-05-17 22:10:35 -04:00
// 在UserIDToApiTokenList中删除该Token
for i , t := range singleton . UserIDToApiTokenList [ singleton . ApiTokenList [ token ] . UserID ] {
if t == token {
singleton . UserIDToApiTokenList [ singleton . ApiTokenList [ token ] . UserID ] = append ( singleton . UserIDToApiTokenList [ singleton . ApiTokenList [ token ] . UserID ] [ : i ] , singleton . UserIDToApiTokenList [ singleton . ApiTokenList [ token ] . UserID ] [ i + 1 : ] ... )
break
}
}
if len ( singleton . UserIDToApiTokenList [ singleton . ApiTokenList [ token ] . UserID ] ) == 0 {
delete ( singleton . UserIDToApiTokenList , singleton . ApiTokenList [ token ] . UserID )
}
// 在ApiTokenList中删除该Token
delete ( singleton . ApiTokenList , token )
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
Message : "success" ,
} )
2020-03-22 08:55:27 -04:00
}
func ( ma * memberAPI ) delete ( c * gin . Context ) {
id , _ := strconv . ParseUint ( c . Param ( "id" ) , 10 , 64 )
if id < 1 {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : "错误的 Server ID" ,
} )
return
}
2019-12-08 10:18:29 -05:00
2020-12-19 10:11:16 -05:00
var err error
switch c . Param ( "model" ) {
case "server" :
2024-02-12 01:16:04 -05:00
err := singleton . DB . Transaction ( func ( tx * gorm . DB ) error {
err = singleton . DB . Unscoped ( ) . Delete ( & model . Server { } , "id = ?" , id ) . Error
if err != nil {
return err
}
err = singleton . DB . Unscoped ( ) . Delete ( & model . MonitorHistory { } , "server_id = ?" , id ) . Error
if err != nil {
return err
}
return nil
} )
2020-12-19 10:11:16 -05:00
if err == nil {
2021-11-06 04:00:08 -04:00
// 删除服务器
2022-01-08 22:54:14 -05:00
singleton . ServerLock . Lock ( )
2023-06-13 12:23:47 -04:00
onServerDelete ( id )
2022-01-08 22:54:14 -05:00
singleton . ServerLock . Unlock ( )
singleton . ReSortServer ( )
2020-12-19 10:11:16 -05:00
}
case "notification" :
2022-01-08 22:54:14 -05:00
err = singleton . DB . Unscoped ( ) . Delete ( & model . Notification { } , "id = ?" , id ) . Error
2020-12-19 23:18:27 -05:00
if err == nil {
2022-01-08 22:54:14 -05:00
singleton . OnDeleteNotification ( id )
2020-12-19 23:18:27 -05:00
}
2024-10-17 09:03:03 -04:00
case "ddns" :
err = singleton . DB . Unscoped ( ) . Delete ( & model . DDNSProfile { } , "id = ?" , id ) . Error
if err == nil {
singleton . OnDDNSUpdate ( )
}
2024-07-14 07:41:50 -04:00
case "nat" :
err = singleton . DB . Unscoped ( ) . Delete ( & model . NAT { } , "id = ?" , id ) . Error
if err == nil {
singleton . OnNATUpdate ( )
}
2021-01-15 11:45:49 -05:00
case "monitor" :
2022-01-08 22:54:14 -05:00
err = singleton . DB . Unscoped ( ) . Delete ( & model . Monitor { } , "id = ?" , id ) . Error
2021-01-16 02:05:35 -05:00
if err == nil {
2022-01-08 22:54:14 -05:00
singleton . ServiceSentinelShared . OnMonitorDelete ( id )
err = singleton . DB . Unscoped ( ) . Delete ( & model . MonitorHistory { } , "monitor_id = ?" , id ) . Error
2021-01-16 02:05:35 -05:00
}
2021-01-18 20:59:04 -05:00
case "cron" :
2022-01-08 22:54:14 -05:00
err = singleton . DB . Unscoped ( ) . Delete ( & model . Cron { } , "id = ?" , id ) . Error
2021-01-18 20:59:04 -05:00
if err == nil {
2022-01-08 22:54:14 -05:00
singleton . CronLock . RLock ( )
defer singleton . CronLock . RUnlock ( )
cr := singleton . Crons [ id ]
2021-09-29 23:59:57 -04:00
if cr != nil && cr . CronJobID != 0 {
2022-01-08 22:54:14 -05:00
singleton . Cron . Remove ( cr . CronJobID )
2021-01-18 20:59:04 -05:00
}
2022-01-08 22:54:14 -05:00
delete ( singleton . Crons , id )
2021-01-18 20:59:04 -05:00
}
2020-12-19 10:11:16 -05:00
case "alert-rule" :
2022-01-08 22:54:14 -05:00
err = singleton . DB . Unscoped ( ) . Delete ( & model . AlertRule { } , "id = ?" , id ) . Error
2020-12-19 23:18:27 -05:00
if err == nil {
2022-01-08 22:54:14 -05:00
singleton . OnDeleteAlert ( id )
2020-12-19 23:18:27 -05:00
}
2020-12-19 09:14:36 -05:00
}
2020-12-19 10:11:16 -05:00
if err != nil {
2020-12-19 09:14:36 -05:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "数据库错误:%s" , err ) ,
} )
return
}
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
} )
2021-01-20 09:15:47 -05:00
}
type searchResult struct {
Name string ` json:"name,omitempty" `
Value uint64 ` json:"value,omitempty" `
Text string ` json:"text,omitempty" `
}
func ( ma * memberAPI ) searchServer ( c * gin . Context ) {
var servers [ ] model . Server
likeWord := "%" + c . Query ( "word" ) + "%"
2022-01-08 22:54:14 -05:00
singleton . DB . Select ( "id,name" ) . Where ( "id = ? OR name LIKE ? OR tag LIKE ? OR note LIKE ?" ,
2021-01-20 09:15:47 -05:00
c . Query ( "word" ) , likeWord , likeWord , likeWord ) . Find ( & servers )
var resp [ ] searchResult
for i := 0 ; i < len ( servers ) ; i ++ {
resp = append ( resp , searchResult {
Value : servers [ i ] . ID ,
Name : servers [ i ] . Name ,
Text : servers [ i ] . Name ,
} )
}
c . JSON ( http . StatusOK , map [ string ] interface { } {
"success" : true ,
"results" : resp ,
} )
2020-12-19 09:14:36 -05:00
}
2022-09-13 23:32:15 -04:00
func ( ma * memberAPI ) searchTask ( c * gin . Context ) {
var tasks [ ] model . Cron
likeWord := "%" + c . Query ( "word" ) + "%"
singleton . DB . Select ( "id,name" ) . Where ( "id = ? OR name LIKE ?" ,
c . Query ( "word" ) , likeWord ) . Find ( & tasks )
var resp [ ] searchResult
for i := 0 ; i < len ( tasks ) ; i ++ {
resp = append ( resp , searchResult {
Value : tasks [ i ] . ID ,
Name : tasks [ i ] . Name ,
Text : tasks [ i ] . Name ,
} )
}
c . JSON ( http . StatusOK , map [ string ] interface { } {
"success" : true ,
"results" : resp ,
} )
}
2024-10-17 09:03:03 -04:00
func ( ma * memberAPI ) searchDDNS ( c * gin . Context ) {
var ddns [ ] model . DDNSProfile
likeWord := "%" + c . Query ( "word" ) + "%"
singleton . DB . Select ( "id,name" ) . Where ( "id = ? OR name LIKE ?" ,
c . Query ( "word" ) , likeWord ) . Find ( & ddns )
var resp [ ] searchResult
for i := 0 ; i < len ( ddns ) ; i ++ {
resp = append ( resp , searchResult {
Value : ddns [ i ] . ID ,
Name : ddns [ i ] . Name ,
Text : ddns [ i ] . Name ,
} )
}
c . JSON ( http . StatusOK , map [ string ] interface { } {
"success" : true ,
"results" : resp ,
} )
}
2019-12-08 10:18:29 -05:00
type serverForm struct {
2024-10-17 09:03:03 -04:00
ID uint64
Name string ` binding:"required" `
DisplayIndex int
Secret string
Tag string
Note string
PublicNote string
HideForGuest string
EnableDDNS string
DDNSProfilesRaw string
2019-12-08 10:18:29 -05:00
}
2019-12-20 10:58:09 -05:00
func ( ma * memberAPI ) addOrEditServer ( c * gin . Context ) {
2019-12-08 10:18:29 -05:00
var sf serverForm
2019-12-09 03:02:49 -05:00
var s model . Server
2021-01-08 08:21:06 -05:00
var isEdit bool
2019-12-08 10:18:29 -05:00
err := c . ShouldBindJSON ( & sf )
if err == nil {
s . Name = sf . Name
2020-03-22 08:55:27 -04:00
s . Secret = sf . Secret
2021-01-08 08:04:50 -05:00
s . DisplayIndex = sf . DisplayIndex
2020-03-22 08:55:27 -04:00
s . ID = sf . ID
2021-01-12 01:09:25 -05:00
s . Tag = sf . Tag
2021-01-20 06:24:59 -05:00
s . Note = sf . Note
2024-09-27 12:16:54 -04:00
s . PublicNote = sf . PublicNote
2022-09-30 10:40:56 -04:00
s . HideForGuest = sf . HideForGuest == "on"
2024-02-24 08:10:27 -05:00
s . EnableDDNS = sf . EnableDDNS == "on"
2024-10-17 09:03:03 -04:00
s . DDNSProfilesRaw = sf . DDNSProfilesRaw
err = utils . Json . Unmarshal ( [ ] byte ( sf . DDNSProfilesRaw ) , & s . DDNSProfiles )
if err == nil {
if s . ID == 0 {
s . Secret , err = utils . GenerateRandomString ( 18 )
if err == nil {
err = singleton . DB . Create ( & s ) . Error
}
} else {
isEdit = true
err = singleton . DB . Save ( & s ) . Error
2022-12-16 10:34:14 -05:00
}
2021-01-08 08:04:50 -05:00
}
2019-12-08 10:18:29 -05:00
}
if err != nil {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "请求错误:%s" , err ) ,
} )
return
}
2021-01-08 08:21:06 -05:00
if isEdit {
2022-01-08 22:54:14 -05:00
singleton . ServerLock . Lock ( )
s . CopyFromRunningServer ( singleton . ServerList [ s . ID ] )
2021-07-25 11:50:08 -04:00
// 如果修改了 Secret
2022-01-08 22:54:14 -05:00
if s . Secret != singleton . ServerList [ s . ID ] . Secret {
2021-07-25 11:50:08 -04:00
// 删除旧 Secret-ID 绑定关系
2022-01-08 22:54:14 -05:00
singleton . SecretToID [ s . Secret ] = s . ID
2021-07-25 11:50:08 -04:00
// 设置新的 Secret-ID 绑定关系
2022-01-08 22:54:14 -05:00
delete ( singleton . SecretToID , singleton . ServerList [ s . ID ] . Secret )
2021-07-25 11:50:08 -04:00
}
2022-05-16 23:21:27 -04:00
// 如果修改了Tag
2022-09-20 22:01:41 -04:00
oldTag := singleton . ServerList [ s . ID ] . Tag
newTag := s . Tag
if newTag != oldTag {
2022-05-19 21:03:58 -04:00
index := - 1
2022-09-20 22:01:41 -04:00
for i := 0 ; i < len ( singleton . ServerTagToIDList [ oldTag ] ) ; i ++ {
if singleton . ServerTagToIDList [ oldTag ] [ i ] == s . ID {
2022-05-19 21:05:18 -04:00
index = i
2022-05-16 23:21:27 -04:00
break
}
2022-05-19 21:03:58 -04:00
}
if index > - 1 {
// 删除旧 Tag-ID 绑定关系
2022-09-20 22:01:41 -04:00
singleton . ServerTagToIDList [ oldTag ] = append ( singleton . ServerTagToIDList [ oldTag ] [ : index ] , singleton . ServerTagToIDList [ oldTag ] [ index + 1 : ] ... )
if len ( singleton . ServerTagToIDList [ oldTag ] ) == 0 {
delete ( singleton . ServerTagToIDList , oldTag )
}
2022-05-16 23:21:27 -04:00
}
// 设置新的 Tag-ID 绑定关系
2022-09-20 22:01:41 -04:00
singleton . ServerTagToIDList [ newTag ] = append ( singleton . ServerTagToIDList [ newTag ] , s . ID )
2022-05-16 23:21:27 -04:00
}
2022-01-08 22:54:14 -05:00
singleton . ServerList [ s . ID ] = & s
singleton . ServerLock . Unlock ( )
2021-01-08 08:21:06 -05:00
} else {
s . Host = & model . Host { }
2021-01-15 11:45:49 -05:00
s . State = & model . HostState { }
2024-08-11 22:06:55 -04:00
s . TaskCloseLock = new ( sync . Mutex )
2022-01-08 22:54:14 -05:00
singleton . ServerLock . Lock ( )
singleton . SecretToID [ s . Secret ] = s . ID
singleton . ServerList [ s . ID ] = & s
2022-05-16 23:21:27 -04:00
singleton . ServerTagToIDList [ s . Tag ] = append ( singleton . ServerTagToIDList [ s . Tag ] , s . ID )
2022-01-08 22:54:14 -05:00
singleton . ServerLock . Unlock ( )
2021-01-08 08:21:06 -05:00
}
2022-01-08 22:54:14 -05:00
singleton . ReSortServer ( )
2019-12-08 10:18:29 -05:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
} )
2019-12-08 03:59:58 -05:00
}
2021-01-15 11:45:49 -05:00
type monitorForm struct {
2023-04-15 07:04:38 -04:00
ID uint64
Name string
Target string
Type uint8
Cover uint8
Notify string
NotificationTag string
SkipServersRaw string
Duration uint64
MinLatency float32
MaxLatency float32
LatencyNotify string
EnableTriggerTask string
2024-02-13 10:09:40 -05:00
EnableShowInService string
2023-04-15 07:04:38 -04:00
FailTriggerTasksRaw string
RecoverTriggerTasksRaw string
2021-01-15 11:45:49 -05:00
}
func ( ma * memberAPI ) addOrEditMonitor ( c * gin . Context ) {
var mf monitorForm
var m model . Monitor
err := c . ShouldBindJSON ( & mf )
if err == nil {
m . Name = mf . Name
2021-04-23 07:09:04 -04:00
m . Target = strings . TrimSpace ( mf . Target )
2021-01-15 11:45:49 -05:00
m . Type = mf . Type
m . ID = mf . ID
2021-04-22 09:53:31 -04:00
m . SkipServersRaw = mf . SkipServersRaw
2021-06-21 09:30:42 -04:00
m . Cover = mf . Cover
2021-04-17 11:36:37 -04:00
m . Notify = mf . Notify == "on"
2022-04-14 15:13:53 -04:00
m . NotificationTag = mf . NotificationTag
2021-09-02 11:45:21 -04:00
m . Duration = mf . Duration
2022-09-16 22:30:32 -04:00
m . LatencyNotify = mf . LatencyNotify == "on"
m . MinLatency = mf . MinLatency
m . MaxLatency = mf . MaxLatency
2024-02-13 10:09:40 -05:00
m . EnableShowInService = mf . EnableShowInService == "on"
2023-04-15 07:04:38 -04:00
m . EnableTriggerTask = mf . EnableTriggerTask == "on"
m . RecoverTriggerTasksRaw = mf . RecoverTriggerTasksRaw
m . FailTriggerTasksRaw = mf . FailTriggerTasksRaw
2022-01-14 04:34:49 -05:00
err = m . InitSkipServers ( )
2021-01-15 11:45:49 -05:00
}
if err == nil {
2022-04-15 08:34:25 -04:00
// 保证NotificationTag不为空
2022-04-14 15:13:53 -04:00
if m . NotificationTag == "" {
m . NotificationTag = "default"
}
2024-06-23 04:15:08 -04:00
err = utils . Json . Unmarshal ( [ ] byte ( mf . FailTriggerTasksRaw ) , & m . FailTriggerTasks )
}
if err == nil {
err = utils . Json . Unmarshal ( [ ] byte ( mf . RecoverTriggerTasksRaw ) , & m . RecoverTriggerTasks )
}
if err == nil {
if m . ID == 0 {
err = singleton . DB . Create ( & m ) . Error
} else {
err = singleton . DB . Save ( & m ) . Error
2021-01-15 11:45:49 -05:00
}
2024-06-23 04:15:08 -04:00
}
if err == nil {
if m . Cover == 0 {
err = singleton . DB . Unscoped ( ) . Delete ( & model . MonitorHistory { } , "monitor_id = ? and server_id in (?)" , m . ID , strings . Split ( m . SkipServersRaw [ 1 : len ( m . SkipServersRaw ) - 1 ] , "," ) ) . Error
} else {
err = singleton . DB . Unscoped ( ) . Delete ( & model . MonitorHistory { } , "monitor_id = ? and server_id not in (?)" , m . ID , strings . Split ( m . SkipServersRaw [ 1 : len ( m . SkipServersRaw ) - 1 ] , "," ) ) . Error
2024-02-12 01:16:04 -05:00
}
2021-01-15 11:45:49 -05:00
}
2021-09-02 11:45:21 -04:00
if err == nil {
2022-01-08 22:54:14 -05:00
err = singleton . ServiceSentinelShared . OnMonitorUpdate ( m )
2021-09-02 11:45:21 -04:00
}
2021-01-15 11:45:49 -05:00
if err != nil {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "请求错误:%s" , err ) ,
} )
return
}
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
} )
}
2021-01-18 20:59:04 -05:00
type cronForm struct {
2022-04-14 09:06:42 -04:00
ID uint64
2022-09-12 18:14:47 -04:00
TaskType uint8 // 0:计划任务 1:触发任务
2022-04-14 09:06:42 -04:00
Name string
Scheduler string
Command string
ServersRaw string
Cover uint8
PushSuccessful string
NotificationTag string
2021-01-18 20:59:04 -05:00
}
func ( ma * memberAPI ) addOrEditCron ( c * gin . Context ) {
var cf cronForm
var cr model . Cron
err := c . ShouldBindJSON ( & cf )
if err == nil {
2022-09-12 18:14:47 -04:00
cr . TaskType = cf . TaskType
2021-01-18 20:59:04 -05:00
cr . Name = cf . Name
cr . Scheduler = cf . Scheduler
cr . Command = cf . Command
cr . ServersRaw = cf . ServersRaw
cr . PushSuccessful = cf . PushSuccessful == "on"
2022-04-14 09:06:42 -04:00
cr . NotificationTag = cf . NotificationTag
2021-01-18 20:59:04 -05:00
cr . ID = cf . ID
2021-06-21 09:30:42 -04:00
cr . Cover = cf . Cover
2022-03-18 11:13:22 -04:00
err = utils . Json . Unmarshal ( [ ] byte ( cf . ServersRaw ) , & cr . Servers )
2021-01-18 20:59:04 -05:00
}
2022-09-12 18:14:47 -04:00
// 计划任务类型不得使用触发服务器执行方式
2022-09-14 10:14:47 -04:00
if cr . TaskType == model . CronTypeCronTask && cr . Cover == model . CronCoverAlertTrigger {
2022-09-12 18:14:47 -04:00
err = errors . New ( "计划任务类型不得使用触发服务器执行方式" )
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "请求错误:%s" , err ) ,
} )
return
}
2022-01-08 22:54:14 -05:00
tx := singleton . DB . Begin ( )
2021-01-18 20:59:04 -05:00
if err == nil {
2022-04-15 08:34:25 -04:00
// 保证NotificationTag不为空
if cr . NotificationTag == "" {
cr . NotificationTag = "default"
}
2021-01-18 20:59:04 -05:00
if cf . ID == 0 {
2021-09-29 07:58:02 -04:00
err = tx . Create ( & cr ) . Error
2021-01-18 20:59:04 -05:00
} else {
2021-09-29 07:58:02 -04:00
err = tx . Save ( & cr ) . Error
2021-01-18 20:59:04 -05:00
}
}
2021-07-18 22:44:44 -04:00
if err == nil {
2022-09-12 18:14:47 -04:00
// 对于计划任务类型, 需要更新CronJob
if cf . TaskType == model . CronTypeCronTask {
cr . CronJobID , err = singleton . Cron . AddFunc ( cr . Scheduler , singleton . CronTrigger ( cr ) )
}
2021-01-18 20:59:04 -05:00
}
2021-09-29 07:58:02 -04:00
if err == nil {
err = tx . Commit ( ) . Error
} else {
tx . Rollback ( )
}
2021-07-18 22:37:12 -04:00
if err != nil {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
2021-07-18 22:44:44 -04:00
Message : fmt . Sprintf ( "请求错误:%s" , err ) ,
2021-07-18 22:37:12 -04:00
} )
return
}
2022-01-08 22:54:14 -05:00
singleton . CronLock . Lock ( )
defer singleton . CronLock . Unlock ( )
crOld := singleton . Crons [ cr . ID ]
2021-09-29 23:59:57 -04:00
if crOld != nil && crOld . CronJobID != 0 {
2022-01-08 22:54:14 -05:00
singleton . Cron . Remove ( crOld . CronJobID )
2021-05-27 08:48:12 -04:00
}
2021-01-18 20:59:04 -05:00
2022-01-08 22:54:14 -05:00
delete ( singleton . Crons , cr . ID )
singleton . Crons [ cr . ID ] = & cr
2021-01-23 02:32:04 -05:00
2021-01-18 20:59:04 -05:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
} )
}
2021-01-23 20:41:35 -05:00
func ( ma * memberAPI ) manualTrigger ( c * gin . Context ) {
var cr model . Cron
2022-01-08 22:54:14 -05:00
if err := singleton . DB . First ( & cr , "id = ?" , c . Param ( "id" ) ) . Error ; err != nil {
2021-01-23 20:41:35 -05:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : err . Error ( ) ,
} )
return
}
2022-01-08 22:54:14 -05:00
singleton . ManualTrigger ( cr )
2021-01-23 20:41:35 -05:00
2022-09-16 12:08:27 -04:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
} )
}
type BatchUpdateServerGroupRequest struct {
Servers [ ] uint64
Group string
}
func ( ma * memberAPI ) batchUpdateServerGroup ( c * gin . Context ) {
var req BatchUpdateServerGroupRequest
if err := c . ShouldBindJSON ( & req ) ; err != nil {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : err . Error ( ) ,
} )
return
}
if err := singleton . DB . Model ( & model . Server { } ) . Where ( "id in (?)" , req . Servers ) . Update ( "tag" , req . Group ) . Error ; err != nil {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : err . Error ( ) ,
} )
return
}
singleton . ServerLock . Lock ( )
for i := 0 ; i < len ( req . Servers ) ; i ++ {
serverId := req . Servers [ i ]
var s model . Server
copier . Copy ( & s , singleton . ServerList [ serverId ] )
s . Tag = req . Group
2022-09-20 22:01:41 -04:00
// 如果修改了Ta
oldTag := singleton . ServerList [ serverId ] . Tag
newTag := s . Tag
if newTag != oldTag {
2022-09-16 12:08:27 -04:00
index := - 1
2022-09-20 22:01:41 -04:00
for i := 0 ; i < len ( singleton . ServerTagToIDList [ oldTag ] ) ; i ++ {
if singleton . ServerTagToIDList [ oldTag ] [ i ] == s . ID {
2022-09-16 12:08:27 -04:00
index = i
break
}
}
if index > - 1 {
// 删除旧 Tag-ID 绑定关系
2022-09-20 22:01:41 -04:00
singleton . ServerTagToIDList [ oldTag ] = append ( singleton . ServerTagToIDList [ oldTag ] [ : index ] , singleton . ServerTagToIDList [ oldTag ] [ index + 1 : ] ... )
if len ( singleton . ServerTagToIDList [ oldTag ] ) == 0 {
delete ( singleton . ServerTagToIDList , oldTag )
}
2022-09-16 12:08:27 -04:00
}
// 设置新的 Tag-ID 绑定关系
2022-09-20 22:01:41 -04:00
singleton . ServerTagToIDList [ newTag ] = append ( singleton . ServerTagToIDList [ newTag ] , s . ID )
2022-09-16 12:08:27 -04:00
}
singleton . ServerList [ s . ID ] = & s
}
singleton . ServerLock . Unlock ( )
singleton . ReSortServer ( )
2021-01-23 20:41:35 -05:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
} )
}
2021-11-04 00:06:20 -04:00
func ( ma * memberAPI ) forceUpdate ( c * gin . Context ) {
var forceUpdateServers [ ] uint64
if err := c . ShouldBindJSON ( & forceUpdateServers ) ; err != nil {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : err . Error ( ) ,
} )
return
}
var executeResult bytes . Buffer
for i := 0 ; i < len ( forceUpdateServers ) ; i ++ {
2022-01-08 22:54:14 -05:00
singleton . ServerLock . RLock ( )
server := singleton . ServerList [ forceUpdateServers [ i ] ]
singleton . ServerLock . RUnlock ( )
2021-11-04 00:06:20 -04:00
if server != nil && server . TaskStream != nil {
if err := server . TaskStream . Send ( & proto . Task {
Type : model . TaskTypeUpgrade ,
} ) ; err != nil {
executeResult . WriteString ( fmt . Sprintf ( "%d 下发指令失败 %+v<br/>" , forceUpdateServers [ i ] , err ) )
} else {
executeResult . WriteString ( fmt . Sprintf ( "%d 下发指令成功<br/>" , forceUpdateServers [ i ] ) )
}
} else {
executeResult . WriteString ( fmt . Sprintf ( "%d 离线<br/>" , forceUpdateServers [ i ] ) )
}
}
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
Message : executeResult . String ( ) ,
} )
}
2020-12-19 09:14:36 -05:00
type notificationForm struct {
ID uint64
Name string
2022-04-14 09:06:42 -04:00
Tag string // 分组名
2020-12-19 09:14:36 -05:00
URL string
RequestMethod int
RequestType int
2021-11-05 00:04:39 -04:00
RequestHeader string
2020-12-19 09:14:36 -05:00
RequestBody string
VerifySSL string
2022-04-22 14:07:46 -04:00
SkipCheck string
2020-12-19 09:14:36 -05:00
}
func ( ma * memberAPI ) addOrEditNotification ( c * gin . Context ) {
var nf notificationForm
var n model . Notification
err := c . ShouldBindJSON ( & nf )
if err == nil {
n . Name = nf . Name
2022-04-14 09:06:42 -04:00
n . Tag = nf . Tag
2020-12-19 09:14:36 -05:00
n . RequestMethod = nf . RequestMethod
n . RequestType = nf . RequestType
2021-11-05 00:04:39 -04:00
n . RequestHeader = nf . RequestHeader
2020-12-19 09:14:36 -05:00
n . RequestBody = nf . RequestBody
n . URL = nf . URL
verifySSL := nf . VerifySSL == "on"
n . VerifySSL = & verifySSL
n . ID = nf . ID
2022-04-17 05:38:45 -04:00
ns := model . NotificationServerBundle {
Notification : & n ,
Server : nil ,
2023-09-01 12:06:40 -04:00
Loc : singleton . Loc ,
2022-04-17 05:38:45 -04:00
}
2022-04-22 14:07:46 -04:00
// 勾选了跳过检查
2022-04-23 02:46:33 -04:00
if nf . SkipCheck != "on" {
2022-04-22 14:07:46 -04:00
err = ns . Send ( "这是测试消息" )
}
2020-12-19 23:18:27 -05:00
}
if err == nil {
2022-04-14 09:06:42 -04:00
// 保证Tag不为空
if n . Tag == "" {
n . Tag = "default"
}
2020-12-19 09:14:36 -05:00
if n . ID == 0 {
2022-01-08 22:54:14 -05:00
err = singleton . DB . Create ( & n ) . Error
2020-12-19 09:14:36 -05:00
} else {
2022-01-08 22:54:14 -05:00
err = singleton . DB . Save ( & n ) . Error
2020-12-19 09:14:36 -05:00
}
}
if err != nil {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "请求错误:%s" , err ) ,
} )
return
}
2022-04-14 09:06:42 -04:00
singleton . OnRefreshOrAddNotification ( & n )
2020-12-19 09:14:36 -05:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
} )
}
2024-10-17 09:03:03 -04:00
type ddnsForm struct {
ID uint64
MaxRetries uint64
EnableIPv4 string
EnableIPv6 string
Name string
Provider uint8
DomainsRaw string
AccessID string
AccessSecret string
WebhookURL string
WebhookMethod uint8
2024-10-17 11:35:28 -04:00
WebhookRequestType uint8
2024-10-17 09:03:03 -04:00
WebhookRequestBody string
WebhookHeaders string
}
func ( ma * memberAPI ) addOrEditDDNS ( c * gin . Context ) {
var df ddnsForm
var p model . DDNSProfile
err := c . ShouldBindJSON ( & df )
if err == nil {
if df . MaxRetries < 1 || df . MaxRetries > 10 {
err = errors . New ( "重试次数必须为大于 1 且不超过 10 的整数" )
}
}
if err == nil {
p . Name = df . Name
p . ID = df . ID
enableIPv4 := df . EnableIPv4 == "on"
enableIPv6 := df . EnableIPv6 == "on"
p . EnableIPv4 = & enableIPv4
p . EnableIPv6 = & enableIPv6
p . MaxRetries = df . MaxRetries
p . Provider = df . Provider
p . DomainsRaw = df . DomainsRaw
p . Domains = strings . Split ( p . DomainsRaw , "," )
p . AccessID = df . AccessID
p . AccessSecret = df . AccessSecret
p . WebhookURL = df . WebhookURL
p . WebhookMethod = df . WebhookMethod
2024-10-17 11:35:28 -04:00
p . WebhookRequestType = df . WebhookRequestType
2024-10-17 09:03:03 -04:00
p . WebhookRequestBody = df . WebhookRequestBody
p . WebhookHeaders = df . WebhookHeaders
for n , domain := range p . Domains {
// IDN to ASCII
domainValid , domainErr := idna . Lookup . ToASCII ( domain )
if domainErr != nil {
err = fmt . Errorf ( "域名 %s 解析错误: %v" , domain , domainErr )
break
}
p . Domains [ n ] = domainValid
}
}
if err == nil {
if p . ID == 0 {
err = singleton . DB . Create ( & p ) . Error
} else {
err = singleton . DB . Save ( & p ) . Error
}
}
if err != nil {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "请求错误:%s" , err ) ,
} )
return
}
singleton . OnDDNSUpdate ( )
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
} )
}
2024-07-14 07:41:50 -04:00
type natForm struct {
ID uint64
Name string
ServerID uint64
Host string
Domain string
}
func ( ma * memberAPI ) addOrEditNAT ( c * gin . Context ) {
var nf natForm
var n model . NAT
err := c . ShouldBindJSON ( & nf )
if err == nil {
n . Name = nf . Name
n . ID = nf . ID
n . Domain = nf . Domain
n . Host = nf . Host
n . ServerID = nf . ServerID
}
if err == nil {
if n . ID == 0 {
err = singleton . DB . Create ( & n ) . Error
} else {
err = singleton . DB . Save ( & n ) . Error
}
}
if err != nil {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "请求错误:%s" , err ) ,
} )
return
}
singleton . OnNATUpdate ( )
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
} )
}
2020-12-19 10:11:16 -05:00
type alertRuleForm struct {
2022-09-13 23:14:23 -04:00
ID uint64
Name string
RulesRaw string
FailTriggerTasksRaw string // 失败时触发的任务id
RecoverTriggerTasksRaw string // 恢复时触发的任务id
NotificationTag string
TriggerMode int
Enable string
2020-12-19 10:11:16 -05:00
}
func ( ma * memberAPI ) addOrEditAlertRule ( c * gin . Context ) {
var arf alertRuleForm
var r model . AlertRule
err := c . ShouldBindJSON ( & arf )
if err == nil {
2022-03-18 11:13:22 -04:00
err = utils . Json . Unmarshal ( [ ] byte ( arf . RulesRaw ) , & r . Rules )
2020-12-19 23:18:27 -05:00
}
if err == nil {
if len ( r . Rules ) == 0 {
err = errors . New ( "至少定义一条规则" )
} else {
for i := 0 ; i < len ( r . Rules ) ; i ++ {
2022-02-28 21:19:23 -05:00
if ! r . Rules [ i ] . IsTransferDurationRule ( ) {
if r . Rules [ i ] . Duration < 3 {
err = errors . New ( "错误: Duration 至少为 3" )
break
}
} else {
if r . Rules [ i ] . CycleInterval < 1 {
err = errors . New ( "错误: cycle_interval 至少为 1" )
break
}
if r . Rules [ i ] . CycleStart == nil {
err = errors . New ( "错误: cycle_start 未设置" )
break
}
if r . Rules [ i ] . CycleStart . After ( time . Now ( ) ) {
err = errors . New ( "错误: cycle_start 是个未来值" )
break
}
2020-12-19 23:18:27 -05:00
}
}
2020-12-19 10:11:16 -05:00
}
}
if err == nil {
r . Name = arf . Name
r . RulesRaw = arf . RulesRaw
2022-09-13 23:14:23 -04:00
r . FailTriggerTasksRaw = arf . FailTriggerTasksRaw
r . RecoverTriggerTasksRaw = arf . RecoverTriggerTasksRaw
2022-04-14 15:13:53 -04:00
r . NotificationTag = arf . NotificationTag
2020-12-19 10:11:16 -05:00
enable := arf . Enable == "on"
2022-09-12 16:01:08 -04:00
r . TriggerMode = arf . TriggerMode
2020-12-19 10:11:16 -05:00
r . Enable = & enable
r . ID = arf . ID
2022-09-13 23:14:23 -04:00
}
if err == nil {
err = utils . Json . Unmarshal ( [ ] byte ( arf . FailTriggerTasksRaw ) , & r . FailTriggerTasks )
}
if err == nil {
err = utils . Json . Unmarshal ( [ ] byte ( arf . RecoverTriggerTasksRaw ) , & r . RecoverTriggerTasks )
}
//保证NotificationTag不为空
if err == nil {
2022-04-15 08:34:25 -04:00
if r . NotificationTag == "" {
r . NotificationTag = "default"
}
2020-12-19 10:11:16 -05:00
if r . ID == 0 {
2022-01-08 22:54:14 -05:00
err = singleton . DB . Create ( & r ) . Error
2020-12-19 10:11:16 -05:00
} else {
2022-01-08 22:54:14 -05:00
err = singleton . DB . Save ( & r ) . Error
2020-12-19 10:11:16 -05:00
}
}
if err != nil {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "请求错误:%s" , err ) ,
} )
return
}
2022-01-08 22:54:14 -05:00
singleton . OnRefreshOrAddAlert ( r )
2020-12-19 10:11:16 -05:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
} )
}
2019-12-08 03:59:58 -05:00
type logoutForm struct {
ID uint64
}
func ( ma * memberAPI ) logout ( c * gin . Context ) {
2019-12-20 10:58:09 -05:00
admin := c . MustGet ( model . CtxKeyAuthorizedUser ) . ( * model . User )
2019-12-08 03:59:58 -05:00
var lf logoutForm
if err := c . ShouldBindJSON ( & lf ) ; err != nil {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "请求错误:%s" , err ) ,
} )
return
}
2019-12-20 10:58:09 -05:00
if lf . ID != admin . ID {
2019-12-08 03:59:58 -05:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "请求错误:%s" , "用户ID不匹配" ) ,
} )
return
}
2022-01-08 22:54:14 -05:00
singleton . DB . Model ( admin ) . UpdateColumns ( model . User {
2019-12-20 10:58:09 -05:00
Token : "" ,
TokenExpired : time . Now ( ) ,
} )
2019-12-08 03:59:58 -05:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
} )
2024-07-13 00:51:59 -04:00
if oidcLogoutUrl := singleton . Conf . Oauth2 . OidcLogoutURL ; oidcLogoutUrl != "" {
// 重定向到 OIDC 退出登录地址。不知道为什么,这里的重定向不生效
c . Redirect ( http . StatusOK , oidcLogoutUrl )
}
2019-12-08 03:59:58 -05:00
}
2020-12-09 06:05:40 -05:00
type settingForm struct {
2022-04-14 15:13:53 -04:00
Title string
Admin string
2022-04-29 12:48:39 -04:00
Language string
2022-04-14 15:13:53 -04:00
Theme string
2022-06-02 21:45:11 -04:00
DashboardTheme string
2022-04-14 15:13:53 -04:00
CustomCode string
2024-08-13 12:24:17 -04:00
CustomCodeDashboard string
2024-10-18 10:06:01 -04:00
CustomNameservers string
2022-04-14 15:13:53 -04:00
ViewPassword string
IgnoredIPNotification string
IPChangeNotificationTag string // IP变更提醒的通知组
GRPCHost string
Cover uint8
2022-02-19 01:29:06 -05:00
2024-02-27 08:05:39 -05:00
EnableIPChangeNotification string
EnablePlainIPInNotification string
DisableSwitchTemplateInFrontend string
2020-12-09 06:05:40 -05:00
}
func ( ma * memberAPI ) updateSetting ( c * gin . Context ) {
var sf settingForm
if err := c . ShouldBind ( & sf ) ; err != nil {
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "请求错误:%s" , err ) ,
} )
return
}
2022-06-02 21:45:11 -04:00
2022-06-24 08:43:38 -04:00
if _ , yes := model . Themes [ sf . Theme ] ; ! yes {
2022-06-02 21:45:11 -04:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
2022-06-24 08:43:38 -04:00
Message : fmt . Sprintf ( "前台主题不存在:%s" , sf . Theme ) ,
2022-06-02 21:45:11 -04:00
} )
return
}
2024-10-10 01:38:09 -04:00
if _ , yes := model . DashboardThemes [ sf . DashboardTheme ] ; ! yes {
2022-06-02 21:45:11 -04:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
2022-06-24 08:43:38 -04:00
Message : fmt . Sprintf ( "后台主题不存在:%s" , sf . DashboardTheme ) ,
} )
return
}
2023-11-28 10:01:37 -05:00
if ! utils . IsFileExists ( "resource/template/theme-" + sf . Theme + "/home.html" ) && ! resource . IsTemplateFileExist ( "template/theme-" + sf . Theme + "/home.html" ) {
2022-06-24 08:43:38 -04:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "前台主题文件异常:%s" , sf . Theme ) ,
} )
return
}
2023-11-28 10:01:37 -05:00
if ! utils . IsFileExists ( "resource/template/dashboard-" + sf . DashboardTheme + "/setting.html" ) && ! resource . IsTemplateFileExist ( "template/dashboard-" + sf . DashboardTheme + "/setting.html" ) {
2022-06-24 08:43:38 -04:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "后台主题文件异常:%s" , sf . DashboardTheme ) ,
2022-06-02 21:45:11 -04:00
} )
return
}
2022-04-29 12:48:39 -04:00
singleton . Conf . Language = sf . Language
2022-01-08 22:54:14 -05:00
singleton . Conf . EnableIPChangeNotification = sf . EnableIPChangeNotification == "on"
2022-02-19 01:29:06 -05:00
singleton . Conf . EnablePlainIPInNotification = sf . EnablePlainIPInNotification == "on"
2024-02-27 08:05:39 -05:00
singleton . Conf . DisableSwitchTemplateInFrontend = sf . DisableSwitchTemplateInFrontend == "on"
2022-01-08 22:54:14 -05:00
singleton . Conf . Cover = sf . Cover
singleton . Conf . GRPCHost = sf . GRPCHost
singleton . Conf . IgnoredIPNotification = sf . IgnoredIPNotification
2022-04-14 15:13:53 -04:00
singleton . Conf . IPChangeNotificationTag = sf . IPChangeNotificationTag
2022-01-08 22:54:14 -05:00
singleton . Conf . Site . Brand = sf . Title
singleton . Conf . Site . Theme = sf . Theme
2022-06-02 21:45:11 -04:00
singleton . Conf . Site . DashboardTheme = sf . DashboardTheme
2022-01-08 22:54:14 -05:00
singleton . Conf . Site . CustomCode = sf . CustomCode
2024-08-13 12:24:17 -04:00
singleton . Conf . Site . CustomCodeDashboard = sf . CustomCodeDashboard
2024-10-18 10:06:01 -04:00
singleton . Conf . DNSServers = sf . CustomNameservers
2022-01-08 22:54:14 -05:00
singleton . Conf . Site . ViewPassword = sf . ViewPassword
singleton . Conf . Oauth2 . Admin = sf . Admin
2022-04-15 08:34:25 -04:00
// 保证NotificationTag不为空
if singleton . Conf . IPChangeNotificationTag == "" {
singleton . Conf . IPChangeNotificationTag = "default"
}
2022-01-08 22:54:14 -05:00
if err := singleton . Conf . Save ( ) ; err != nil {
2020-12-09 06:05:40 -05:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusBadRequest ,
Message : fmt . Sprintf ( "请求错误:%s" , err ) ,
} )
return
}
2022-04-29 12:48:39 -04:00
// 更新系统语言
singleton . InitLocalizer ( )
2024-10-18 10:06:01 -04:00
// 更新DNS服务器
singleton . OnNameserverUpdate ( )
2020-12-09 06:05:40 -05:00
c . JSON ( http . StatusOK , model . Response {
Code : http . StatusOK ,
} )
}
2023-06-13 12:23:47 -04:00
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 )
}