Files
oneterm/backend/internal/acl/resource.go
2025-05-20 16:02:14 +08:00

190 lines
5.0 KiB
Go

package acl
import (
"context"
"fmt"
"github.com/gin-gonic/gin"
"github.com/samber/lo"
"github.com/spf13/cast"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
"github.com/veops/oneterm/internal/model"
"github.com/veops/oneterm/pkg/config"
dbpkg "github.com/veops/oneterm/pkg/db"
"github.com/veops/oneterm/pkg/logger"
"github.com/veops/oneterm/pkg/remote"
)
type ResourceType struct {
Name string `json:"name"`
Perms []string `json:"perms"`
}
type ResourceTypeResp struct {
Groups []*ResourceType `json:"groups"`
}
func MigrateNode() {
ctx := context.Background()
rts, err := GetResourceTypes(ctx)
if err != nil {
logger.L().Fatal("get resource type failed", zap.Error(err))
}
if !lo.ContainsBy(rts, func(rt *ResourceType) bool { return rt.Name == "node" }) {
if err = AddResourceTypes(ctx, &ResourceType{Name: "node", Perms: AllPermissions}); err != nil {
logger.L().Fatal("add resource type failed", zap.Error(err))
}
}
nodes := make([]*model.Node, 0)
if err = dbpkg.DB.Model(&nodes).Where("resource_id = 0").Or("resource_id IS NULL").Find(&nodes).Error; err != nil {
logger.L().Fatal("get nodes failed", zap.Error(err))
}
eg := errgroup.Group{}
for _, n := range nodes {
nd := n
eg.Go(func() error {
r, err := AddResource(ctx, nd.CreatorId, "node", cast.ToString(nd.Id))
if err != nil {
return err
}
if err := dbpkg.DB.Model(&nd).Where("id=?", nd.Id).Update("resource_id", r.ResourceId).Error; err != nil {
return err
}
return nil
})
}
if err = eg.Wait(); err != nil {
logger.L().Fatal("add resource failed", zap.Error(err))
}
}
func GetResourceTypes(ctx context.Context) (rt []*ResourceType, err error) {
token, err := remote.GetAclToken(ctx)
if err != nil {
return
}
data := &ResourceTypeResp{}
url := fmt.Sprintf("%s/acl/resource_types", config.Cfg.Auth.Acl.Url)
resp, err := remote.RC.R().
SetHeaders(map[string]string{
"App-Access-Token": token,
}).
SetQueryParams(map[string]string{
"app_id": "oneterm",
"page_size": "100",
}).
SetResult(data).
Get(url)
err = remote.HandleErr(err, resp, func(dt map[string]any) bool { return true })
rt = data.Groups
return
}
func AddResourceTypes(ctx context.Context, rt *ResourceType) (err error) {
token, err := remote.GetAclToken(ctx)
if err != nil {
return
}
url := fmt.Sprintf("%s/acl/resource_types", config.Cfg.Auth.Acl.Url)
resp, err := remote.RC.R().
SetHeaders(map[string]string{
"App-Access-Token": token,
}).
SetBody(rt).
Post(url)
err = remote.HandleErr(err, resp, func(dt map[string]any) bool { return true })
return
}
func AddResource(ctx context.Context, uid int, resourceTypeId string, name string) (res *Resource, err error) {
token, err := remote.GetAclToken(ctx)
if err != nil {
return
}
res = &Resource{}
url := fmt.Sprintf("%s/acl/resources", config.Cfg.Auth.Acl.Url)
resp, err := remote.RC.R().
SetHeaders(map[string]string{
"App-Access-Token": token,
"X-User-Id": cast.ToString(uid),
"Accept-Language": getAcceptLanguage(ctx)}).
SetBody(map[string]any{
"type_id": resourceTypeId,
"name": name,
"uid": uid,
}).
SetResult(&res).
Post(url)
err = remote.HandleErr(err, resp, func(dt map[string]any) bool { return true })
return
}
func DeleteResource(ctx context.Context, uid int, resourceId int) (err error) {
token, err := remote.GetAclToken(ctx)
if err != nil {
return
}
url := fmt.Sprintf("%v/acl/resources/%v", config.Cfg.Auth.Acl.Url, resourceId)
resp, err := remote.RC.R().
SetHeaders(map[string]string{
"App-Access-Token": token,
"X-User-Id": cast.ToString(uid),
"Accept-Language": getAcceptLanguage(ctx)}).
Delete(url)
err = remote.HandleErr(err, resp, func(dt map[string]any) bool { return true })
return
}
func UpdateResource(ctx context.Context, uid int, resourceId int, updates map[string]string) (err error) {
token, err := remote.GetAclToken(ctx)
if err != nil {
return
}
url := fmt.Sprintf("%s/acl/resources/%d", config.Cfg.Auth.Acl.Url, resourceId)
resp, err := remote.RC.R().
SetHeaders(map[string]string{
"App-Access-Token": token,
"X-User-Id": cast.ToString(uid),
"Accept-Language": getAcceptLanguage(ctx)}).
SetFormData(updates).
Put(url)
err = remote.HandleErr(err, resp, func(dt map[string]any) bool { return true })
return
}
func GetResourcePermissions(ctx context.Context, resourceId int) (res map[string]*ResourcePermissionsRespItem, err error) {
token, err := remote.GetAclToken(ctx)
if err != nil {
return
}
res = make(map[string]*ResourcePermissionsRespItem)
url := fmt.Sprintf("%v/acl/resources/%v/permissions", config.Cfg.Auth.Acl.Url, resourceId) //TODO config
resp, err := remote.RC.R().
SetHeader("App-Access-Token", token).
SetResult(&res).
Get(url)
err = remote.HandleErr(err, resp, func(dt map[string]any) bool { return true })
return
}
func getAcceptLanguage(ctx context.Context) string {
ginCtx, ok := ctx.(*gin.Context)
if !ok {
return ""
}
return ginCtx.GetHeader("Accept-Language")
}