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"
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"
2019-12-08 03:59:58 -05:00
2020-11-10 21:07:45 -05:00
"github.com/naiba/nezha/model"
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"
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 ( "" )
2024-10-19 23:47:45 -04:00
// mr.Use(mygin.Authorize(mygin.AuthorizeOption{
// MemberOnly: true,
// IsPage: false,
// Msg: "访问此接口需要登录",
// Btn: "点此登录",
// Redirect: "/login",
// }))
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 )
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
}
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 "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
}
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 ] )
2024-10-20 11:23:04 -04:00
// s.Tag = req.Group
// // 如果修改了Ta
// oldTag := singleton.ServerList[serverId].Tag
// newTag := s.Tag
// if newTag != oldTag {
// index := -1
// for i := 0; i < len(singleton.ServerTagToIDList[oldTag]); i++ {
// if singleton.ServerTagToIDList[oldTag][i] == s.ID {
// index = i
// break
// }
// }
// if index > -1 {
// // 删除旧 Tag-ID 绑定关系
// singleton.ServerTagToIDList[oldTag] = append(singleton.ServerTagToIDList[oldTag][:index], singleton.ServerTagToIDList[oldTag][index+1:]...)
// if len(singleton.ServerTagToIDList[oldTag]) == 0 {
// delete(singleton.ServerTagToIDList, oldTag)
// }
// }
// // 设置新的 Tag-ID 绑定关系
// 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
2024-10-21 12:04:17 -04:00
Provider string
2024-10-17 09:03:03 -04:00
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 {
2024-10-19 11:14:53 -04:00
// Token: "",
// TokenExpired: time.Now(),
2019-12-20 10:58:09 -05:00
} )
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
2024-10-19 23:47:45 -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 {
2024-10-19 23:47:45 -04:00
SiteName string
2022-04-29 12:48:39 -04:00
Language string
2024-10-18 10:06:01 -04:00
CustomNameservers string
2022-04-14 15:13:53 -04:00
IgnoredIPNotification string
IPChangeNotificationTag string // IP变更提醒的通知组
2024-10-19 23:47:45 -04:00
InstallHost string
2022-04-14 15:13:53 -04:00
Cover uint8
2022-02-19 01:29:06 -05:00
2024-10-19 23:47:45 -04:00
EnableIPChangeNotification string
EnablePlainIPInNotification 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
2024-10-19 23:47:45 -04:00
// if _, yes := model.Themes[sf.Theme]; !yes {
// c.JSON(http.StatusOK, model.Response{
// Code: http.StatusBadRequest,
// Message: fmt.Sprintf("前台主题不存在:%s", sf.Theme),
// })
// return
// }
// if _, yes := model.DashboardThemes[sf.DashboardTheme]; !yes {
// c.JSON(http.StatusOK, model.Response{
// Code: http.StatusBadRequest,
// Message: fmt.Sprintf("后台主题不存在:%s", sf.DashboardTheme),
// })
// return
// }
2022-06-24 08:43:38 -04:00
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"
2022-01-08 22:54:14 -05:00
singleton . Conf . Cover = sf . Cover
2024-10-19 23:47:45 -04:00
singleton . Conf . InstallHost = sf . InstallHost
2022-01-08 22:54:14 -05:00
singleton . Conf . IgnoredIPNotification = sf . IgnoredIPNotification
2022-04-14 15:13:53 -04:00
singleton . Conf . IPChangeNotificationTag = sf . IPChangeNotificationTag
2024-10-19 23:47:45 -04:00
singleton . Conf . SiteName = sf . SiteName
2024-10-18 10:06:01 -04:00
singleton . Conf . DNSServers = sf . CustomNameservers
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
}
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 ,
} )
}