mirror of
https://github.com/nezhahq/nezha.git
synced 2025-02-08 12:38:13 -05:00
Merge e39e793b5b
into d835aeb486
This commit is contained in:
commit
59b5f4598d
@ -50,6 +50,9 @@ func createAlertRule(c *gin.Context) (uint64, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uid := getUid(c)
|
||||||
|
|
||||||
|
r.UserID = uid
|
||||||
r.Name = arf.Name
|
r.Name = arf.Name
|
||||||
r.Rules = arf.Rules
|
r.Rules = arf.Rules
|
||||||
r.FailTriggerTasks = arf.FailTriggerTasks
|
r.FailTriggerTasks = arf.FailTriggerTasks
|
||||||
@ -100,6 +103,10 @@ func updateAlertRule(c *gin.Context) (any, error) {
|
|||||||
return nil, singleton.Localizer.ErrorT("alert id %d does not exist", id)
|
return nil, singleton.Localizer.ErrorT("alert id %d does not exist", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !r.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
|
||||||
r.Name = arf.Name
|
r.Name = arf.Name
|
||||||
r.Rules = arf.Rules
|
r.Rules = arf.Rules
|
||||||
r.FailTriggerTasks = arf.FailTriggerTasks
|
r.FailTriggerTasks = arf.FailTriggerTasks
|
||||||
@ -133,12 +140,24 @@ func updateAlertRule(c *gin.Context) (any, error) {
|
|||||||
// @Success 200 {object} model.CommonResponse[any]
|
// @Success 200 {object} model.CommonResponse[any]
|
||||||
// @Router /batch-delete/alert-rule [post]
|
// @Router /batch-delete/alert-rule [post]
|
||||||
func batchDeleteAlertRule(c *gin.Context) (any, error) {
|
func batchDeleteAlertRule(c *gin.Context) (any, error) {
|
||||||
var ar []uint64
|
var arr []uint64
|
||||||
|
if err := c.ShouldBindJSON(&arr); err != nil {
|
||||||
if err := c.ShouldBindJSON(&ar); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ars []model.AlertRule
|
||||||
|
if err := singleton.DB.Where("id in (?)", arr).Find(&ars).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ar []uint64
|
||||||
|
for _, a := range ars {
|
||||||
|
if !a.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
ar = append(ar, a.ID)
|
||||||
|
}
|
||||||
|
|
||||||
if err := singleton.DB.Unscoped().Delete(&model.AlertRule{}, "id in (?)", ar).Error; err != nil {
|
if err := singleton.DB.Unscoped().Delete(&model.AlertRule{}, "id in (?)", ar).Error; err != nil {
|
||||||
return nil, newGormError("%v", err)
|
return nil, newGormError("%v", err)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
jwt "github.com/appleboy/gin-jwt/v2"
|
jwt "github.com/appleboy/gin-jwt/v2"
|
||||||
@ -79,10 +80,10 @@ func routers(r *gin.Engine, frontendDist fs.FS) {
|
|||||||
auth.GET("/profile", commonHandler(getProfile))
|
auth.GET("/profile", commonHandler(getProfile))
|
||||||
auth.POST("/profile", commonHandler(updateProfile))
|
auth.POST("/profile", commonHandler(updateProfile))
|
||||||
auth.GET("/user", commonHandler(listUser))
|
auth.GET("/user", commonHandler(listUser))
|
||||||
auth.POST("/user", commonHandler(createUser))
|
auth.POST("/user", adminHandler(createUser))
|
||||||
auth.POST("/batch-delete/user", commonHandler(batchDeleteUser))
|
auth.POST("/batch-delete/user", adminHandler(batchDeleteUser))
|
||||||
|
|
||||||
auth.GET("/service/list", commonHandler(listService))
|
auth.GET("/service/list", listHandler(listService))
|
||||||
auth.POST("/service", commonHandler(createService))
|
auth.POST("/service", commonHandler(createService))
|
||||||
auth.PATCH("/service/:id", commonHandler(updateService))
|
auth.PATCH("/service/:id", commonHandler(updateService))
|
||||||
auth.POST("/batch-delete/service", commonHandler(batchDeleteService))
|
auth.POST("/batch-delete/service", commonHandler(batchDeleteService))
|
||||||
@ -96,42 +97,42 @@ func routers(r *gin.Engine, frontendDist fs.FS) {
|
|||||||
auth.PATCH("/notification-group/:id", commonHandler(updateNotificationGroup))
|
auth.PATCH("/notification-group/:id", commonHandler(updateNotificationGroup))
|
||||||
auth.POST("/batch-delete/notification-group", commonHandler(batchDeleteNotificationGroup))
|
auth.POST("/batch-delete/notification-group", commonHandler(batchDeleteNotificationGroup))
|
||||||
|
|
||||||
auth.GET("/server", commonHandler(listServer))
|
auth.GET("/server", listHandler(listServer))
|
||||||
auth.PATCH("/server/:id", commonHandler(updateServer))
|
auth.PATCH("/server/:id", commonHandler(updateServer))
|
||||||
auth.POST("/batch-delete/server", commonHandler(batchDeleteServer))
|
auth.POST("/batch-delete/server", commonHandler(batchDeleteServer))
|
||||||
auth.POST("/force-update/server", commonHandler(forceUpdateServer))
|
auth.POST("/force-update/server", commonHandler(forceUpdateServer))
|
||||||
|
|
||||||
auth.GET("/notification", commonHandler(listNotification))
|
auth.GET("/notification", listHandler(listNotification))
|
||||||
auth.POST("/notification", commonHandler(createNotification))
|
auth.POST("/notification", commonHandler(createNotification))
|
||||||
auth.PATCH("/notification/:id", commonHandler(updateNotification))
|
auth.PATCH("/notification/:id", commonHandler(updateNotification))
|
||||||
auth.POST("/batch-delete/notification", commonHandler(batchDeleteNotification))
|
auth.POST("/batch-delete/notification", commonHandler(batchDeleteNotification))
|
||||||
|
|
||||||
auth.GET("/alert-rule", commonHandler(listAlertRule))
|
auth.GET("/alert-rule", listHandler(listAlertRule))
|
||||||
auth.POST("/alert-rule", commonHandler(createAlertRule))
|
auth.POST("/alert-rule", commonHandler(createAlertRule))
|
||||||
auth.PATCH("/alert-rule/:id", commonHandler(updateAlertRule))
|
auth.PATCH("/alert-rule/:id", commonHandler(updateAlertRule))
|
||||||
auth.POST("/batch-delete/alert-rule", commonHandler(batchDeleteAlertRule))
|
auth.POST("/batch-delete/alert-rule", commonHandler(batchDeleteAlertRule))
|
||||||
|
|
||||||
auth.GET("/cron", commonHandler(listCron))
|
auth.GET("/cron", listHandler(listCron))
|
||||||
auth.POST("/cron", commonHandler(createCron))
|
auth.POST("/cron", commonHandler(createCron))
|
||||||
auth.PATCH("/cron/:id", commonHandler(updateCron))
|
auth.PATCH("/cron/:id", commonHandler(updateCron))
|
||||||
auth.GET("/cron/:id/manual", commonHandler(manualTriggerCron))
|
auth.GET("/cron/:id/manual", commonHandler(manualTriggerCron))
|
||||||
auth.POST("/batch-delete/cron", commonHandler(batchDeleteCron))
|
auth.POST("/batch-delete/cron", commonHandler(batchDeleteCron))
|
||||||
|
|
||||||
auth.GET("/ddns", commonHandler(listDDNS))
|
auth.GET("/ddns", listHandler(listDDNS))
|
||||||
auth.GET("/ddns/providers", commonHandler(listProviders))
|
auth.GET("/ddns/providers", commonHandler(listProviders))
|
||||||
auth.POST("/ddns", commonHandler(createDDNS))
|
auth.POST("/ddns", commonHandler(createDDNS))
|
||||||
auth.PATCH("/ddns/:id", commonHandler(updateDDNS))
|
auth.PATCH("/ddns/:id", commonHandler(updateDDNS))
|
||||||
auth.POST("/batch-delete/ddns", commonHandler(batchDeleteDDNS))
|
auth.POST("/batch-delete/ddns", commonHandler(batchDeleteDDNS))
|
||||||
|
|
||||||
auth.GET("/nat", commonHandler(listNAT))
|
auth.GET("/nat", listHandler(listNAT))
|
||||||
auth.POST("/nat", commonHandler(createNAT))
|
auth.POST("/nat", commonHandler(createNAT))
|
||||||
auth.PATCH("/nat/:id", commonHandler(updateNAT))
|
auth.PATCH("/nat/:id", commonHandler(updateNAT))
|
||||||
auth.POST("/batch-delete/nat", commonHandler(batchDeleteNAT))
|
auth.POST("/batch-delete/nat", commonHandler(batchDeleteNAT))
|
||||||
|
|
||||||
auth.GET("/waf", commonHandler(listBlockedAddress))
|
auth.GET("/waf", commonHandler(listBlockedAddress))
|
||||||
auth.POST("/batch-delete/waf", commonHandler(batchDeleteBlockedAddress))
|
auth.POST("/batch-delete/waf", adminHandler(batchDeleteBlockedAddress))
|
||||||
|
|
||||||
auth.PATCH("/setting", commonHandler(updateConfig))
|
auth.PATCH("/setting", adminHandler(updateConfig))
|
||||||
|
|
||||||
r.NoRoute(fallbackToFrontend(frontendDist))
|
r.NoRoute(fallbackToFrontend(frontendDist))
|
||||||
}
|
}
|
||||||
@ -189,29 +190,74 @@ func (we *wsError) Error() string {
|
|||||||
|
|
||||||
func commonHandler[T any](handler handlerFunc[T]) func(*gin.Context) {
|
func commonHandler[T any](handler handlerFunc[T]) func(*gin.Context) {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
data, err := handler(c)
|
handle(c, handler)
|
||||||
if err == nil {
|
}
|
||||||
c.JSON(http.StatusOK, model.CommonResponse[T]{Success: true, Data: data})
|
}
|
||||||
|
|
||||||
|
func adminHandler[T any](handler handlerFunc[T]) func(*gin.Context) {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
auth, ok := c.Get(model.CtxKeyAuthorizedUser)
|
||||||
|
if !ok {
|
||||||
|
c.JSON(http.StatusOK, newErrorResponse(singleton.Localizer.ErrorT("unauthorized")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch err.(type) {
|
|
||||||
case *gormError:
|
user := *auth.(*model.User)
|
||||||
log.Printf("NEZHA>> gorm error: %v", err)
|
if user.Role != model.RoleAdmin {
|
||||||
c.JSON(http.StatusOK, newErrorResponse(singleton.Localizer.ErrorT("database error")))
|
c.JSON(http.StatusOK, newErrorResponse(singleton.Localizer.ErrorT("permission denied")))
|
||||||
return
|
return
|
||||||
case *wsError:
|
}
|
||||||
// Connection is upgraded to WebSocket, so c.Writer is no longer usable
|
|
||||||
if msg := err.Error(); msg != "" {
|
handle(c, handler)
|
||||||
log.Printf("NEZHA>> websocket error: %v", err)
|
}
|
||||||
}
|
}
|
||||||
return
|
|
||||||
default:
|
func handle[T any](c *gin.Context, handler handlerFunc[T]) {
|
||||||
|
data, err := handler(c)
|
||||||
|
if err == nil {
|
||||||
|
c.JSON(http.StatusOK, model.CommonResponse[T]{Success: true, Data: data})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch err.(type) {
|
||||||
|
case *gormError:
|
||||||
|
log.Printf("NEZHA>> gorm error: %v", err)
|
||||||
|
c.JSON(http.StatusOK, newErrorResponse(singleton.Localizer.ErrorT("database error")))
|
||||||
|
return
|
||||||
|
case *wsError:
|
||||||
|
// Connection is upgraded to WebSocket, so c.Writer is no longer usable
|
||||||
|
if msg := err.Error(); msg != "" {
|
||||||
|
log.Printf("NEZHA>> websocket error: %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
c.JSON(http.StatusOK, newErrorResponse(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func listHandler[S ~[]E, E model.CommonInterface](handler handlerFunc[S]) func(*gin.Context) {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
data, err := handler(c)
|
||||||
|
if err != nil {
|
||||||
c.JSON(http.StatusOK, newErrorResponse(err))
|
c.JSON(http.StatusOK, newErrorResponse(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, filter(c, data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func filter[S ~[]E, E model.CommonInterface](ctx *gin.Context, s S) S {
|
||||||
|
return slices.DeleteFunc(s, func(e E) bool {
|
||||||
|
return e.HasPermission(ctx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUid(c *gin.Context) uint64 {
|
||||||
|
user, _ := c.MustGet(model.CtxKeyAuthorizedUser).(*model.User)
|
||||||
|
return user.ID
|
||||||
|
}
|
||||||
|
|
||||||
func fallbackToFrontend(frontendDist fs.FS) func(*gin.Context) {
|
func fallbackToFrontend(frontendDist fs.FS) func(*gin.Context) {
|
||||||
checkLocalFileOrFs := func(c *gin.Context, fs fs.FS, path string) bool {
|
checkLocalFileOrFs := func(c *gin.Context, fs fs.FS, path string) bool {
|
||||||
if _, err := os.Stat(path); err == nil {
|
if _, err := os.Stat(path); err == nil {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -50,6 +49,7 @@ func createCron(c *gin.Context) (uint64, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cr.UserID = getUid(c)
|
||||||
cr.TaskType = cf.TaskType
|
cr.TaskType = cf.TaskType
|
||||||
cr.Name = cf.Name
|
cr.Name = cf.Name
|
||||||
cr.Scheduler = cf.Scheduler
|
cr.Scheduler = cf.Scheduler
|
||||||
@ -106,7 +106,11 @@ func updateCron(c *gin.Context) (any, error) {
|
|||||||
|
|
||||||
var cr model.Cron
|
var cr model.Cron
|
||||||
if err := singleton.DB.First(&cr, id).Error; err != nil {
|
if err := singleton.DB.First(&cr, id).Error; err != nil {
|
||||||
return nil, fmt.Errorf("task id %d does not exist", id)
|
return nil, singleton.Localizer.ErrorT("task id %d does not exist", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cr.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
}
|
}
|
||||||
|
|
||||||
cr.TaskType = cf.TaskType
|
cr.TaskType = cf.TaskType
|
||||||
@ -156,12 +160,15 @@ func manualTriggerCron(c *gin.Context) (any, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var cr model.Cron
|
singleton.CronLock.RLock()
|
||||||
if err := singleton.DB.First(&cr, id).Error; err != nil {
|
cr, ok := singleton.Crons[id]
|
||||||
|
if !ok {
|
||||||
|
singleton.CronLock.RUnlock()
|
||||||
return nil, singleton.Localizer.ErrorT("task id %d does not exist", id)
|
return nil, singleton.Localizer.ErrorT("task id %d does not exist", id)
|
||||||
}
|
}
|
||||||
|
singleton.CronLock.RUnlock()
|
||||||
|
|
||||||
singleton.ManualTrigger(&cr)
|
singleton.ManualTrigger(cr)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,12 +184,24 @@ func manualTriggerCron(c *gin.Context) (any, error) {
|
|||||||
// @Success 200 {object} model.CommonResponse[any]
|
// @Success 200 {object} model.CommonResponse[any]
|
||||||
// @Router /batch-delete/cron [post]
|
// @Router /batch-delete/cron [post]
|
||||||
func batchDeleteCron(c *gin.Context) (any, error) {
|
func batchDeleteCron(c *gin.Context) (any, error) {
|
||||||
var cr []uint64
|
var crr []uint64
|
||||||
|
if err := c.ShouldBindJSON(&crr); err != nil {
|
||||||
if err := c.ShouldBindJSON(&cr); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cr []uint64
|
||||||
|
singleton.CronLock.RLock()
|
||||||
|
for _, crID := range crr {
|
||||||
|
if crn, ok := singleton.Crons[crID]; ok {
|
||||||
|
if !crn.HasPermission(c) {
|
||||||
|
singleton.CronLock.RUnlock()
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
cr = append(cr, crn.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
singleton.CronLock.RUnlock()
|
||||||
|
|
||||||
if err := singleton.DB.Unscoped().Delete(&model.Cron{}, "id in (?)", cr).Error; err != nil {
|
if err := singleton.DB.Unscoped().Delete(&model.Cron{}, "id in (?)", cr).Error; err != nil {
|
||||||
return nil, newGormError("%v", err)
|
return nil, newGormError("%v", err)
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,7 @@ func createDDNS(c *gin.Context) (uint64, error) {
|
|||||||
return 0, singleton.Localizer.ErrorT("the retry count must be an integer between 1 and 10")
|
return 0, singleton.Localizer.ErrorT("the retry count must be an integer between 1 and 10")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.UserID = getUid(c)
|
||||||
p.Name = df.Name
|
p.Name = df.Name
|
||||||
enableIPv4 := df.EnableIPv4
|
enableIPv4 := df.EnableIPv4
|
||||||
enableIPv6 := df.EnableIPv6
|
enableIPv6 := df.EnableIPv6
|
||||||
@ -125,6 +126,10 @@ func updateDDNS(c *gin.Context) (any, error) {
|
|||||||
return nil, singleton.Localizer.ErrorT("profile id %d does not exist", id)
|
return nil, singleton.Localizer.ErrorT("profile id %d does not exist", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !p.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
|
||||||
p.Name = df.Name
|
p.Name = df.Name
|
||||||
enableIPv4 := df.EnableIPv4
|
enableIPv4 := df.EnableIPv4
|
||||||
enableIPv6 := df.EnableIPv6
|
enableIPv6 := df.EnableIPv6
|
||||||
@ -172,12 +177,25 @@ func updateDDNS(c *gin.Context) (any, error) {
|
|||||||
// @Success 200 {object} model.CommonResponse[any]
|
// @Success 200 {object} model.CommonResponse[any]
|
||||||
// @Router /batch-delete/ddns [post]
|
// @Router /batch-delete/ddns [post]
|
||||||
func batchDeleteDDNS(c *gin.Context) (any, error) {
|
func batchDeleteDDNS(c *gin.Context) (any, error) {
|
||||||
var ddnsConfigs []uint64
|
var ddnsConfigsr []uint64
|
||||||
|
|
||||||
if err := c.ShouldBindJSON(&ddnsConfigs); err != nil {
|
if err := c.ShouldBindJSON(&ddnsConfigsr); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ddnsConfigs []uint64
|
||||||
|
singleton.DDNSCacheLock.RLock()
|
||||||
|
for _, pid := range ddnsConfigsr {
|
||||||
|
if p, ok := singleton.DDNSCache[pid]; ok {
|
||||||
|
if !p.HasPermission(c) {
|
||||||
|
singleton.DDNSCacheLock.RUnlock()
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
ddnsConfigs = append(ddnsConfigs, p.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
singleton.DDNSCacheLock.RUnlock()
|
||||||
|
|
||||||
if err := singleton.DB.Unscoped().Delete(&model.DDNSProfile{}, "id in (?)", ddnsConfigs).Error; err != nil {
|
if err := singleton.DB.Unscoped().Delete(&model.DDNSProfile{}, "id in (?)", ddnsConfigs).Error; err != nil {
|
||||||
return nil, newGormError("%v", err)
|
return nil, newGormError("%v", err)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/hashicorp/go-uuid"
|
"github.com/hashicorp/go-uuid"
|
||||||
|
|
||||||
"github.com/nezhahq/nezha/model"
|
"github.com/nezhahq/nezha/model"
|
||||||
"github.com/nezhahq/nezha/pkg/utils"
|
"github.com/nezhahq/nezha/pkg/utils"
|
||||||
"github.com/nezhahq/nezha/pkg/websocketx"
|
"github.com/nezhahq/nezha/pkg/websocketx"
|
||||||
@ -31,13 +32,6 @@ func createFM(c *gin.Context) (*model.CreateFMResponse, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
streamId, err := uuid.GenerateUUID()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
rpc.NezhaHandlerSingleton.CreateStream(streamId)
|
|
||||||
|
|
||||||
singleton.ServerLock.RLock()
|
singleton.ServerLock.RLock()
|
||||||
server := singleton.ServerList[id]
|
server := singleton.ServerList[id]
|
||||||
singleton.ServerLock.RUnlock()
|
singleton.ServerLock.RUnlock()
|
||||||
@ -45,6 +39,17 @@ func createFM(c *gin.Context) (*model.CreateFMResponse, error) {
|
|||||||
return nil, singleton.Localizer.ErrorT("server not found or not connected")
|
return nil, singleton.Localizer.ErrorT("server not found or not connected")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !server.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
|
||||||
|
streamId, err := uuid.GenerateUUID()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc.NezhaHandlerSingleton.CreateStream(streamId)
|
||||||
|
|
||||||
fmData, _ := utils.Json.Marshal(&model.TaskFM{
|
fmData, _ := utils.Json.Marshal(&model.TaskFM{
|
||||||
StreamID: streamId,
|
StreamID: streamId,
|
||||||
})
|
})
|
||||||
|
@ -51,6 +51,9 @@ func createNAT(c *gin.Context) (uint64, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uid := getUid(c)
|
||||||
|
|
||||||
|
n.UserID = uid
|
||||||
n.Name = nf.Name
|
n.Name = nf.Name
|
||||||
n.Domain = nf.Domain
|
n.Domain = nf.Domain
|
||||||
n.Host = nf.Host
|
n.Host = nf.Host
|
||||||
@ -95,6 +98,10 @@ func updateNAT(c *gin.Context) (any, error) {
|
|||||||
return nil, singleton.Localizer.ErrorT("profile id %d does not exist", id)
|
return nil, singleton.Localizer.ErrorT("profile id %d does not exist", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !n.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
|
||||||
n.Name = nf.Name
|
n.Name = nf.Name
|
||||||
n.Domain = nf.Domain
|
n.Domain = nf.Domain
|
||||||
n.Host = nf.Host
|
n.Host = nf.Host
|
||||||
@ -121,12 +128,24 @@ func updateNAT(c *gin.Context) (any, error) {
|
|||||||
// @Success 200 {object} model.CommonResponse[any]
|
// @Success 200 {object} model.CommonResponse[any]
|
||||||
// @Router /batch-delete/nat [post]
|
// @Router /batch-delete/nat [post]
|
||||||
func batchDeleteNAT(c *gin.Context) (any, error) {
|
func batchDeleteNAT(c *gin.Context) (any, error) {
|
||||||
var n []uint64
|
var nr []uint64
|
||||||
|
if err := c.ShouldBindJSON(&nr); err != nil {
|
||||||
if err := c.ShouldBindJSON(&n); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var n []uint64
|
||||||
|
singleton.NATCacheRwLock.RLock()
|
||||||
|
for _, id := range nr {
|
||||||
|
if p, ok := singleton.NATCache[singleton.NATIDToDomain[id]]; ok {
|
||||||
|
if !p.HasPermission(c) {
|
||||||
|
singleton.NATCacheRwLock.RUnlock()
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
n = append(n, p.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
singleton.NATCacheRwLock.RUnlock()
|
||||||
|
|
||||||
if err := singleton.DB.Unscoped().Delete(&model.NAT{}, "id in (?)", n).Error; err != nil {
|
if err := singleton.DB.Unscoped().Delete(&model.NAT{}, "id in (?)", n).Error; err != nil {
|
||||||
return nil, newGormError("%v", err)
|
return nil, newGormError("%v", err)
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ func createNotification(c *gin.Context) (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var n model.Notification
|
var n model.Notification
|
||||||
|
n.UserID = getUid(c)
|
||||||
n.Name = nf.Name
|
n.Name = nf.Name
|
||||||
n.RequestMethod = nf.RequestMethod
|
n.RequestMethod = nf.RequestMethod
|
||||||
n.RequestType = nf.RequestType
|
n.RequestType = nf.RequestType
|
||||||
@ -106,6 +107,10 @@ func updateNotification(c *gin.Context) (any, error) {
|
|||||||
return nil, singleton.Localizer.ErrorT("notification id %d does not exist", id)
|
return nil, singleton.Localizer.ErrorT("notification id %d does not exist", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !n.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
|
||||||
n.Name = nf.Name
|
n.Name = nf.Name
|
||||||
n.RequestMethod = nf.RequestMethod
|
n.RequestMethod = nf.RequestMethod
|
||||||
n.RequestType = nf.RequestType
|
n.RequestType = nf.RequestType
|
||||||
@ -148,12 +153,23 @@ func updateNotification(c *gin.Context) (any, error) {
|
|||||||
// @Success 200 {object} model.CommonResponse[any]
|
// @Success 200 {object} model.CommonResponse[any]
|
||||||
// @Router /batch-delete/notification [post]
|
// @Router /batch-delete/notification [post]
|
||||||
func batchDeleteNotification(c *gin.Context) (any, error) {
|
func batchDeleteNotification(c *gin.Context) (any, error) {
|
||||||
var n []uint64
|
var nr []uint64
|
||||||
|
if err := c.ShouldBindJSON(&nr); err != nil {
|
||||||
if err := c.ShouldBindJSON(&n); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var n []uint64
|
||||||
|
singleton.NotificationsLock.RLock()
|
||||||
|
for _, nid := range nr {
|
||||||
|
if ns, ok := singleton.NotificationMap[nid]; ok {
|
||||||
|
if !ns.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
n = append(n, ns.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
singleton.NotificationsLock.RUnlock()
|
||||||
|
|
||||||
err := singleton.DB.Transaction(func(tx *gorm.DB) error {
|
err := singleton.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
if err := tx.Unscoped().Delete(&model.Notification{}, "id in (?)", n).Error; err != nil {
|
if err := tx.Unscoped().Delete(&model.Notification{}, "id in (?)", n).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} model.CommonResponse[[]model.NotificationGroupResponseItem]
|
// @Success 200 {object} model.CommonResponse[[]model.NotificationGroupResponseItem]
|
||||||
// @Router /notification-group [get]
|
// @Router /notification-group [get]
|
||||||
func listNotificationGroup(c *gin.Context) ([]model.NotificationGroupResponseItem, error) {
|
func listNotificationGroup(c *gin.Context) ([]*model.NotificationGroupResponseItem, error) {
|
||||||
var ng []model.NotificationGroup
|
var ng []model.NotificationGroup
|
||||||
if err := singleton.DB.Find(&ng).Error; err != nil {
|
if err := singleton.DB.Find(&ng).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -39,9 +39,9 @@ func listNotificationGroup(c *gin.Context) ([]model.NotificationGroupResponseIte
|
|||||||
groupNotifications[n.NotificationGroupID] = append(groupNotifications[n.NotificationGroupID], n.NotificationID)
|
groupNotifications[n.NotificationGroupID] = append(groupNotifications[n.NotificationGroupID], n.NotificationID)
|
||||||
}
|
}
|
||||||
|
|
||||||
ngRes := make([]model.NotificationGroupResponseItem, 0, len(ng))
|
ngRes := make([]*model.NotificationGroupResponseItem, 0, len(ng))
|
||||||
for _, n := range ng {
|
for _, n := range ng {
|
||||||
ngRes = append(ngRes, model.NotificationGroupResponseItem{
|
ngRes = append(ngRes, &model.NotificationGroupResponseItem{
|
||||||
Group: n,
|
Group: n,
|
||||||
Notifications: groupNotifications[n.ID],
|
Notifications: groupNotifications[n.ID],
|
||||||
})
|
})
|
||||||
@ -68,8 +68,11 @@ func createNotificationGroup(c *gin.Context) (uint64, error) {
|
|||||||
}
|
}
|
||||||
ngf.Notifications = slices.Compact(ngf.Notifications)
|
ngf.Notifications = slices.Compact(ngf.Notifications)
|
||||||
|
|
||||||
|
uid := getUid(c)
|
||||||
|
|
||||||
var ng model.NotificationGroup
|
var ng model.NotificationGroup
|
||||||
ng.Name = ngf.Name
|
ng.Name = ngf.Name
|
||||||
|
ng.UserID = uid
|
||||||
|
|
||||||
var count int64
|
var count int64
|
||||||
if err := singleton.DB.Model(&model.Notification{}).Where("id in (?)", ngf.Notifications).Count(&count).Error; err != nil {
|
if err := singleton.DB.Model(&model.Notification{}).Where("id in (?)", ngf.Notifications).Count(&count).Error; err != nil {
|
||||||
@ -86,6 +89,9 @@ func createNotificationGroup(c *gin.Context) (uint64, error) {
|
|||||||
}
|
}
|
||||||
for _, n := range ngf.Notifications {
|
for _, n := range ngf.Notifications {
|
||||||
if err := tx.Create(&model.NotificationGroupNotification{
|
if err := tx.Create(&model.NotificationGroupNotification{
|
||||||
|
Common: model.Common{
|
||||||
|
UserID: uid,
|
||||||
|
},
|
||||||
NotificationGroupID: ng.ID,
|
NotificationGroupID: ng.ID,
|
||||||
NotificationID: n,
|
NotificationID: n,
|
||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
@ -131,6 +137,10 @@ func updateNotificationGroup(c *gin.Context) (any, error) {
|
|||||||
return nil, singleton.Localizer.ErrorT("group id %d does not exist", id)
|
return nil, singleton.Localizer.ErrorT("group id %d does not exist", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !ngDB.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
|
||||||
ngDB.Name = ngf.Name
|
ngDB.Name = ngf.Name
|
||||||
ngf.Notifications = slices.Compact(ngf.Notifications)
|
ngf.Notifications = slices.Compact(ngf.Notifications)
|
||||||
|
|
||||||
@ -142,6 +152,8 @@ func updateNotificationGroup(c *gin.Context) (any, error) {
|
|||||||
return nil, singleton.Localizer.ErrorT("have invalid notification id")
|
return nil, singleton.Localizer.ErrorT("have invalid notification id")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uid := getUid(c)
|
||||||
|
|
||||||
err = singleton.DB.Transaction(func(tx *gorm.DB) error {
|
err = singleton.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
if err := tx.Save(&ngDB).Error; err != nil {
|
if err := tx.Save(&ngDB).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
@ -152,6 +164,9 @@ func updateNotificationGroup(c *gin.Context) (any, error) {
|
|||||||
|
|
||||||
for _, n := range ngf.Notifications {
|
for _, n := range ngf.Notifications {
|
||||||
if err := tx.Create(&model.NotificationGroupNotification{
|
if err := tx.Create(&model.NotificationGroupNotification{
|
||||||
|
Common: model.Common{
|
||||||
|
UserID: uid,
|
||||||
|
},
|
||||||
NotificationGroupID: ngDB.ID,
|
NotificationGroupID: ngDB.ID,
|
||||||
NotificationID: n,
|
NotificationID: n,
|
||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
@ -180,11 +195,24 @@ func updateNotificationGroup(c *gin.Context) (any, error) {
|
|||||||
// @Success 200 {object} model.CommonResponse[any]
|
// @Success 200 {object} model.CommonResponse[any]
|
||||||
// @Router /batch-delete/notification-group [post]
|
// @Router /batch-delete/notification-group [post]
|
||||||
func batchDeleteNotificationGroup(c *gin.Context) (any, error) {
|
func batchDeleteNotificationGroup(c *gin.Context) (any, error) {
|
||||||
var ngn []uint64
|
var ngnr []uint64
|
||||||
if err := c.ShouldBindJSON(&ngn); err != nil {
|
if err := c.ShouldBindJSON(&ngnr); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ng []model.NotificationGroup
|
||||||
|
if err := singleton.DB.Where("id in (?)", ng).Find(&ng).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ngn []uint64
|
||||||
|
for _, n := range ng {
|
||||||
|
if !n.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
ngn = append(ngn, n.ID)
|
||||||
|
}
|
||||||
|
|
||||||
err := singleton.DB.Transaction(func(tx *gorm.DB) error {
|
err := singleton.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
if err := tx.Unscoped().Delete(&model.NotificationGroup{}, "id in (?)", ngn).Error; err != nil {
|
if err := tx.Unscoped().Delete(&model.NotificationGroup{}, "id in (?)", ngn).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -61,6 +61,10 @@ func updateServer(c *gin.Context) (any, error) {
|
|||||||
return nil, singleton.Localizer.ErrorT("server id %d does not exist", id)
|
return nil, singleton.Localizer.ErrorT("server id %d does not exist", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !s.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
|
||||||
s.Name = sf.Name
|
s.Name = sf.Name
|
||||||
s.DisplayIndex = sf.DisplayIndex
|
s.DisplayIndex = sf.DisplayIndex
|
||||||
s.Note = sf.Note
|
s.Note = sf.Note
|
||||||
@ -99,11 +103,24 @@ func updateServer(c *gin.Context) (any, error) {
|
|||||||
// @Success 200 {object} model.CommonResponse[any]
|
// @Success 200 {object} model.CommonResponse[any]
|
||||||
// @Router /batch-delete/server [post]
|
// @Router /batch-delete/server [post]
|
||||||
func batchDeleteServer(c *gin.Context) (any, error) {
|
func batchDeleteServer(c *gin.Context) (any, error) {
|
||||||
var servers []uint64
|
var serversRaw []uint64
|
||||||
if err := c.ShouldBindJSON(&servers); err != nil {
|
if err := c.ShouldBindJSON(&serversRaw); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var servers []uint64
|
||||||
|
singleton.ServerLock.RLock()
|
||||||
|
for _, sid := range serversRaw {
|
||||||
|
if s, ok := singleton.ServerList[sid]; ok {
|
||||||
|
if !s.HasPermission(c) {
|
||||||
|
singleton.ServerLock.RUnlock()
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
servers = append(servers, s.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
singleton.ServerLock.RUnlock()
|
||||||
|
|
||||||
err := singleton.DB.Transaction(func(tx *gorm.DB) error {
|
err := singleton.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
if err := tx.Unscoped().Delete(&model.Server{}, "id in (?)", servers).Error; err != nil {
|
if err := tx.Unscoped().Delete(&model.Server{}, "id in (?)", servers).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} model.CommonResponse[[]model.ServerGroupResponseItem]
|
// @Success 200 {object} model.CommonResponse[[]model.ServerGroupResponseItem]
|
||||||
// @Router /server-group [get]
|
// @Router /server-group [get]
|
||||||
func listServerGroup(c *gin.Context) ([]model.ServerGroupResponseItem, error) {
|
func listServerGroup(c *gin.Context) ([]*model.ServerGroupResponseItem, error) {
|
||||||
var sg []model.ServerGroup
|
var sg []model.ServerGroup
|
||||||
if err := singleton.DB.Find(&sg).Error; err != nil {
|
if err := singleton.DB.Find(&sg).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -38,9 +38,9 @@ func listServerGroup(c *gin.Context) ([]model.ServerGroupResponseItem, error) {
|
|||||||
groupServers[s.ServerGroupId] = append(groupServers[s.ServerGroupId], s.ServerId)
|
groupServers[s.ServerGroupId] = append(groupServers[s.ServerGroupId], s.ServerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
var sgRes []model.ServerGroupResponseItem
|
var sgRes []*model.ServerGroupResponseItem
|
||||||
for _, s := range sg {
|
for _, s := range sg {
|
||||||
sgRes = append(sgRes, model.ServerGroupResponseItem{
|
sgRes = append(sgRes, &model.ServerGroupResponseItem{
|
||||||
Group: s,
|
Group: s,
|
||||||
Servers: groupServers[s.ID],
|
Servers: groupServers[s.ID],
|
||||||
})
|
})
|
||||||
@ -67,8 +67,11 @@ func createServerGroup(c *gin.Context) (uint64, error) {
|
|||||||
}
|
}
|
||||||
sgf.Servers = slices.Compact(sgf.Servers)
|
sgf.Servers = slices.Compact(sgf.Servers)
|
||||||
|
|
||||||
|
uid := getUid(c)
|
||||||
|
|
||||||
var sg model.ServerGroup
|
var sg model.ServerGroup
|
||||||
sg.Name = sgf.Name
|
sg.Name = sgf.Name
|
||||||
|
sg.UserID = uid
|
||||||
|
|
||||||
var count int64
|
var count int64
|
||||||
if err := singleton.DB.Model(&model.Server{}).Where("id in (?)", sgf.Servers).Count(&count).Error; err != nil {
|
if err := singleton.DB.Model(&model.Server{}).Where("id in (?)", sgf.Servers).Count(&count).Error; err != nil {
|
||||||
@ -84,6 +87,9 @@ func createServerGroup(c *gin.Context) (uint64, error) {
|
|||||||
}
|
}
|
||||||
for _, s := range sgf.Servers {
|
for _, s := range sgf.Servers {
|
||||||
if err := tx.Create(&model.ServerGroupServer{
|
if err := tx.Create(&model.ServerGroupServer{
|
||||||
|
Common: model.Common{
|
||||||
|
UserID: uid,
|
||||||
|
},
|
||||||
ServerGroupId: sg.ID,
|
ServerGroupId: sg.ID,
|
||||||
ServerId: s,
|
ServerId: s,
|
||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
@ -129,6 +135,11 @@ func updateServerGroup(c *gin.Context) (any, error) {
|
|||||||
if err := singleton.DB.First(&sgDB, id).Error; err != nil {
|
if err := singleton.DB.First(&sgDB, id).Error; err != nil {
|
||||||
return nil, singleton.Localizer.ErrorT("group id %d does not exist", id)
|
return nil, singleton.Localizer.ErrorT("group id %d does not exist", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !sgDB.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("unauthorized")
|
||||||
|
}
|
||||||
|
|
||||||
sgDB.Name = sg.Name
|
sgDB.Name = sg.Name
|
||||||
|
|
||||||
var count int64
|
var count int64
|
||||||
@ -139,6 +150,8 @@ func updateServerGroup(c *gin.Context) (any, error) {
|
|||||||
return nil, singleton.Localizer.ErrorT("have invalid server id")
|
return nil, singleton.Localizer.ErrorT("have invalid server id")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uid := getUid(c)
|
||||||
|
|
||||||
err = singleton.DB.Transaction(func(tx *gorm.DB) error {
|
err = singleton.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
if err := tx.Save(&sgDB).Error; err != nil {
|
if err := tx.Save(&sgDB).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
@ -149,6 +162,9 @@ func updateServerGroup(c *gin.Context) (any, error) {
|
|||||||
|
|
||||||
for _, s := range sg.Servers {
|
for _, s := range sg.Servers {
|
||||||
if err := tx.Create(&model.ServerGroupServer{
|
if err := tx.Create(&model.ServerGroupServer{
|
||||||
|
Common: model.Common{
|
||||||
|
UserID: uid,
|
||||||
|
},
|
||||||
ServerGroupId: sgDB.ID,
|
ServerGroupId: sgDB.ID,
|
||||||
ServerId: s,
|
ServerId: s,
|
||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
@ -176,11 +192,24 @@ func updateServerGroup(c *gin.Context) (any, error) {
|
|||||||
// @Success 200 {object} model.CommonResponse[any]
|
// @Success 200 {object} model.CommonResponse[any]
|
||||||
// @Router /batch-delete/server-group [post]
|
// @Router /batch-delete/server-group [post]
|
||||||
func batchDeleteServerGroup(c *gin.Context) (any, error) {
|
func batchDeleteServerGroup(c *gin.Context) (any, error) {
|
||||||
var sgs []uint64
|
var sgsr []uint64
|
||||||
if err := c.ShouldBindJSON(&sgs); err != nil {
|
if err := c.ShouldBindJSON(&sgsr); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sg []model.ServerGroup
|
||||||
|
if err := singleton.DB.Where("id in (?)", sgsr).Find(&sg).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var sgs []uint64
|
||||||
|
for _, s := range sg {
|
||||||
|
if !s.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
sgs = append(sgs, s.ID)
|
||||||
|
}
|
||||||
|
|
||||||
err := singleton.DB.Transaction(func(tx *gorm.DB) error {
|
err := singleton.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
if err := tx.Unscoped().Delete(&model.ServerGroup{}, "id in (?)", sgs).Error; err != nil {
|
if err := tx.Unscoped().Delete(&model.ServerGroup{}, "id in (?)", sgs).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -190,7 +190,10 @@ func createService(c *gin.Context) (uint64, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uid := getUid(c)
|
||||||
|
|
||||||
var m model.Service
|
var m model.Service
|
||||||
|
m.UserID = uid
|
||||||
m.Name = mf.Name
|
m.Name = mf.Name
|
||||||
m.Target = strings.TrimSpace(mf.Target)
|
m.Target = strings.TrimSpace(mf.Target)
|
||||||
m.Type = mf.Type
|
m.Type = mf.Type
|
||||||
@ -260,6 +263,11 @@ func updateService(c *gin.Context) (any, error) {
|
|||||||
if err := singleton.DB.First(&m, id).Error; err != nil {
|
if err := singleton.DB.First(&m, id).Error; err != nil {
|
||||||
return nil, singleton.Localizer.ErrorT("service id %d does not exist", id)
|
return nil, singleton.Localizer.ErrorT("service id %d does not exist", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !m.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
|
||||||
m.Name = mf.Name
|
m.Name = mf.Name
|
||||||
m.Target = strings.TrimSpace(mf.Target)
|
m.Target = strings.TrimSpace(mf.Target)
|
||||||
m.Type = mf.Type
|
m.Type = mf.Type
|
||||||
@ -314,10 +322,24 @@ func updateService(c *gin.Context) (any, error) {
|
|||||||
// @Success 200 {object} model.CommonResponse[any]
|
// @Success 200 {object} model.CommonResponse[any]
|
||||||
// @Router /batch-delete/service [post]
|
// @Router /batch-delete/service [post]
|
||||||
func batchDeleteService(c *gin.Context) (any, error) {
|
func batchDeleteService(c *gin.Context) (any, error) {
|
||||||
var ids []uint64
|
var idsr []uint64
|
||||||
if err := c.ShouldBindJSON(&ids); err != nil {
|
if err := c.ShouldBindJSON(&idsr); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ids []uint64
|
||||||
|
singleton.ServiceSentinelShared.ServicesLock.RLock()
|
||||||
|
for _, id := range idsr {
|
||||||
|
if ss, ok := singleton.ServiceSentinelShared.Services[id]; ok {
|
||||||
|
if !ss.HasPermission(c) {
|
||||||
|
singleton.ServiceSentinelShared.ServicesLock.RUnlock()
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
ids = append(ids, ss.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
singleton.ServiceSentinelShared.ServicesLock.RUnlock()
|
||||||
|
|
||||||
err := singleton.DB.Transaction(func(tx *gorm.DB) error {
|
err := singleton.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
if err := tx.Unscoped().Delete(&model.Service{}, "id in (?)", ids).Error; err != nil {
|
if err := tx.Unscoped().Delete(&model.Service{}, "id in (?)", ids).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/hashicorp/go-uuid"
|
"github.com/hashicorp/go-uuid"
|
||||||
|
|
||||||
"github.com/nezhahq/nezha/model"
|
"github.com/nezhahq/nezha/model"
|
||||||
"github.com/nezhahq/nezha/pkg/utils"
|
"github.com/nezhahq/nezha/pkg/utils"
|
||||||
"github.com/nezhahq/nezha/pkg/websocketx"
|
"github.com/nezhahq/nezha/pkg/websocketx"
|
||||||
@ -29,13 +30,6 @@ func createTerminal(c *gin.Context) (*model.CreateTerminalResponse, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
streamId, err := uuid.GenerateUUID()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
rpc.NezhaHandlerSingleton.CreateStream(streamId)
|
|
||||||
|
|
||||||
singleton.ServerLock.RLock()
|
singleton.ServerLock.RLock()
|
||||||
server := singleton.ServerList[createTerminalReq.ServerID]
|
server := singleton.ServerList[createTerminalReq.ServerID]
|
||||||
singleton.ServerLock.RUnlock()
|
singleton.ServerLock.RUnlock()
|
||||||
@ -43,6 +37,17 @@ func createTerminal(c *gin.Context) (*model.CreateTerminalResponse, error) {
|
|||||||
return nil, singleton.Localizer.ErrorT("server not found or not connected")
|
return nil, singleton.Localizer.ErrorT("server not found or not connected")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !server.HasPermission(c) {
|
||||||
|
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||||
|
}
|
||||||
|
|
||||||
|
streamId, err := uuid.GenerateUUID()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc.NezhaHandlerSingleton.CreateStream(streamId)
|
||||||
|
|
||||||
terminalData, _ := utils.Json.Marshal(&model.TerminalTask{
|
terminalData, _ := utils.Json.Marshal(&model.TerminalTask{
|
||||||
StreamID: streamId,
|
StreamID: streamId,
|
||||||
})
|
})
|
||||||
|
@ -114,6 +114,7 @@ func createUser(c *gin.Context) (uint64, error) {
|
|||||||
|
|
||||||
var u model.User
|
var u model.User
|
||||||
u.Username = uf.Username
|
u.Username = uf.Username
|
||||||
|
u.Role = model.RoleMember
|
||||||
|
|
||||||
hash, err := bcrypt.GenerateFromPassword([]byte(uf.Password), bcrypt.DefaultCost)
|
hash, err := bcrypt.GenerateFromPassword([]byte(uf.Password), bcrypt.DefaultCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2,6 +2,8 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -17,6 +19,31 @@ type Common struct {
|
|||||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at,omitempty"`
|
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at,omitempty"`
|
||||||
// Do not use soft deletion
|
// Do not use soft deletion
|
||||||
// DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`
|
// DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`
|
||||||
|
|
||||||
|
UserID uint64 `json:"user_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Common) GetID() uint64 {
|
||||||
|
return c.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Common) HasPermission(ctx *gin.Context) bool {
|
||||||
|
auth, ok := ctx.Get(CtxKeyAuthorizedUser)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
user := *auth.(*User)
|
||||||
|
if user.Role == RoleAdmin {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return user.ID == c.UserID
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommonInterface interface {
|
||||||
|
GetID() uint64
|
||||||
|
HasPermission(*gin.Context) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Response struct {
|
type Response struct {
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
|
const (
|
||||||
|
RoleAdmin uint8 = iota
|
||||||
|
RoleMember
|
||||||
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Common
|
Common
|
||||||
Username string `json:"username,omitempty" gorm:"uniqueIndex"`
|
Username string `json:"username,omitempty" gorm:"uniqueIndex"`
|
||||||
Password string `json:"password,omitempty" gorm:"type:char(72)"`
|
Password string `json:"password,omitempty" gorm:"type:char(72)"`
|
||||||
|
Role uint8 `json:"role,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Profile struct {
|
type Profile struct {
|
||||||
|
Loading…
Reference in New Issue
Block a user