mirror of
https://github.com/veops/oneterm.git
synced 2025-10-07 08:10:57 +08:00
136 lines
4.6 KiB
Go
136 lines
4.6 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/samber/lo"
|
|
"github.com/veops/oneterm/internal/acl"
|
|
"github.com/veops/oneterm/internal/model"
|
|
"github.com/veops/oneterm/internal/repository"
|
|
"github.com/veops/oneterm/internal/schedule"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// AssetService handles asset business logic
|
|
type AssetService struct {
|
|
repo repository.AssetRepository
|
|
}
|
|
|
|
// NewAssetService creates a new asset service
|
|
func NewAssetService() *AssetService {
|
|
return &AssetService{
|
|
repo: repository.NewAssetRepository(),
|
|
}
|
|
}
|
|
|
|
// GetById retrieves an asset by its ID
|
|
func (s *AssetService) GetById(ctx context.Context, id int) (*model.Asset, error) {
|
|
return s.repo.GetById(ctx, id)
|
|
}
|
|
|
|
// PreprocessAssetData preprocesses asset data before saving
|
|
func (s *AssetService) PreprocessAssetData(asset *model.Asset) {
|
|
asset.Ip = strings.TrimSpace(asset.Ip)
|
|
asset.Protocols = lo.Map(asset.Protocols, func(s string, _ int) string { return strings.TrimSpace(s) })
|
|
if asset.Authorization == nil {
|
|
asset.Authorization = make(model.AuthorizationMap)
|
|
}
|
|
|
|
// Handle backward compatibility: convert old format to new format
|
|
// This handles cases where frontend still sends old format: Map[int, Slice[int]]
|
|
s.ensureAuthorizationFormat(asset)
|
|
}
|
|
|
|
// ensureAuthorizationFormat ensures asset.Authorization is in the correct V2 format
|
|
// Handles backward compatibility with old V1 format
|
|
func (s *AssetService) ensureAuthorizationFormat(asset *model.Asset) {
|
|
// Check if we need to convert from old format to new format
|
|
// This is needed for backward compatibility
|
|
for accountId, authData := range asset.Authorization {
|
|
// If permissions is nil, set default permissions (connect only for V1 compatibility)
|
|
if authData.Permissions == nil {
|
|
authData.Permissions = &model.AuthPermissions{
|
|
Connect: true, // Default: allow connect (V1 behavior)
|
|
FileUpload: false, // Default: deny file upload
|
|
FileDownload: false, // Default: deny file download
|
|
Copy: false, // Default: deny copy
|
|
Paste: false, // Default: deny paste
|
|
Share: false, // Default: deny share
|
|
}
|
|
asset.Authorization[accountId] = authData
|
|
}
|
|
}
|
|
}
|
|
|
|
// AttachNodeChain attaches node chain to assets
|
|
func (s *AssetService) AttachNodeChain(ctx context.Context, assets []*model.Asset) error {
|
|
return s.repo.AttachNodeChain(ctx, assets)
|
|
}
|
|
|
|
// BuildQuery constructs asset query with basic filters
|
|
func (s *AssetService) BuildQuery(ctx *gin.Context) (*gorm.DB, error) {
|
|
return s.repo.BuildQuery(ctx)
|
|
}
|
|
|
|
// FilterByParentId filters assets by parent ID
|
|
func (s *AssetService) FilterByParentId(db *gorm.DB, parentId int) (*gorm.DB, error) {
|
|
return s.repo.FilterByParentId(db, parentId)
|
|
}
|
|
|
|
// GetAssetIdsByAuthorization gets asset IDs by authorization using efficient V2 method
|
|
func (s *AssetService) GetAssetIdsByAuthorization(ctx *gin.Context) ([]int, []int, []int, error) {
|
|
// Use efficient V2 method: get authorized resource IDs from ACL, then find V2 rules
|
|
authV2Service := NewAuthorizationV2Service()
|
|
return authV2Service.GetAuthorizationScopeByACL(ctx)
|
|
}
|
|
|
|
// GetIdsByAuthorizationIds extracts node IDs, asset IDs, and account IDs from authorization IDs
|
|
func (s *AssetService) GetIdsByAuthorizationIds(ctx *gin.Context, authorizationIds []*model.AuthorizationIds) ([]int, []int, []int) {
|
|
return s.repo.GetIdsByAuthorizationIds(ctx, authorizationIds)
|
|
}
|
|
|
|
// GetAssetIdsByNodeAccount gets asset IDs by node IDs and account IDs
|
|
func (s *AssetService) GetAssetIdsByNodeAccount(ctx context.Context, nodeIds, accountIds []int) ([]int, error) {
|
|
return s.repo.GetAssetIdsByNodeAccount(ctx, nodeIds, accountIds)
|
|
}
|
|
|
|
// UpdateConnectables updates asset connectability status
|
|
func (s *AssetService) UpdateConnectables(ids ...int) error {
|
|
return schedule.UpdateAssetConnectables(ids...)
|
|
}
|
|
|
|
// BuildQueryWithAuthorization constructs asset query with integrated V2 authorization filter
|
|
func (s *AssetService) BuildQueryWithAuthorization(ctx *gin.Context) (*gorm.DB, error) {
|
|
// Start with base query
|
|
db, err := s.repo.BuildQuery(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
|
|
|
// Administrators have access to all assets
|
|
if acl.IsAdmin(currentUser) {
|
|
return db, nil
|
|
}
|
|
|
|
// Apply V2 authorization filter directly at database level
|
|
authV2Service := NewAuthorizationV2Service()
|
|
_, assetIds, _, err := authV2Service.GetAuthorizationScopeByACL(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Filter by authorized asset IDs at database level (much more efficient)
|
|
if len(assetIds) == 0 {
|
|
// No access to any assets
|
|
db = db.Where("1 = 0") // Returns empty result set efficiently
|
|
} else {
|
|
db = db.Where("id IN ?", assetIds)
|
|
}
|
|
|
|
return db, nil
|
|
}
|