[WIP] feat: user roles

This commit is contained in:
uubulb 2024-12-16 19:40:37 +08:00
parent 1acb4d0330
commit af7427666a
5 changed files with 60 additions and 7 deletions

View File

@ -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 {

View File

@ -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],
}) })

View File

@ -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 {

View File

@ -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)
}

View File

@ -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 {