mirror of
https://github.com/nezhahq/nezha.git
synced 2025-01-22 20:58:14 -05:00
[WIP] feat: user roles
This commit is contained in:
parent
1acb4d0330
commit
af7427666a
@ -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"
|
||||||
@ -58,7 +59,7 @@ func routers(r *gin.Engine, frontendDist fs.FS) {
|
|||||||
|
|
||||||
optionalAuth := api.Group("", optionalAuthMiddleware(authMiddleware))
|
optionalAuth := api.Group("", optionalAuthMiddleware(authMiddleware))
|
||||||
optionalAuth.GET("/ws/server", commonHandler(serverStream))
|
optionalAuth.GET("/ws/server", commonHandler(serverStream))
|
||||||
optionalAuth.GET("/server-group", commonHandler(listServerGroup))
|
optionalAuth.GET("/server-group", listHandler(listServerGroup))
|
||||||
|
|
||||||
optionalAuth.GET("/service", commonHandler(showService))
|
optionalAuth.GET("/service", commonHandler(showService))
|
||||||
optionalAuth.GET("/service/:id", commonHandler(listServiceHistory))
|
optionalAuth.GET("/service/:id", commonHandler(listServiceHistory))
|
||||||
@ -111,19 +112,19 @@ func routers(r *gin.Engine, frontendDist fs.FS) {
|
|||||||
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))
|
||||||
@ -212,6 +213,24 @@ func commonHandler[T any](handler handlerFunc[T]) func(*gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
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 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 {
|
||||||
|
@ -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],
|
||||||
})
|
})
|
||||||
|
@ -2,6 +2,8 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -17,6 +19,26 @@ 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) 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 {
|
||||||
|
HasPermission(*gin.Context) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Response struct {
|
type Response struct {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
type ServerGroupForm struct {
|
type ServerGroupForm struct {
|
||||||
Name string `json:"name" minLength:"1"`
|
Name string `json:"name" minLength:"1"`
|
||||||
Servers []uint64 `json:"servers"`
|
Servers []uint64 `json:"servers"`
|
||||||
@ -9,3 +11,7 @@ type ServerGroupResponseItem struct {
|
|||||||
Group ServerGroup `json:"group"`
|
Group ServerGroup `json:"group"`
|
||||||
Servers []uint64 `json:"servers"`
|
Servers []uint64 `json:"servers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sg *ServerGroupResponseItem) HasPermission(c *gin.Context) bool {
|
||||||
|
return sg.Group.HasPermission(c)
|
||||||
|
}
|
||||||
|
@ -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