Files
SeeyonFileSystem/server/service/storage_assign_service.go
2026-07-10 17:33:33 +08:00

337 lines
9.5 KiB
Go

package service
import (
"errors"
"sort"
"seeyon-filesystem/config"
"seeyon-filesystem/dto"
"seeyon-filesystem/model"
)
// StorageAssignService 存储策略分配服务
type StorageAssignService struct{}
func NewStorageAssignService() *StorageAssignService {
return &StorageAssignService{}
}
// UserStorageInfo 用户存储策略信息
type UserStorageInfo struct {
PolicyID uint64 // 当前使用的策略ID(最高优先级)
PolicyName string
PolicyType string
TotalQuota int64 // 总配额(所有策略叠加)
UsedStorage int64 // 已用空间
UsedPercent float64
AccessMode string
MaxFileSize int64 // 单文件大小上限(字节), 0=不限制
ChunkThreshold int64 // 分片上传阈值(字节)
Assignments []model.StorageAssignment // 所有关联的分配规则
}
// ResolvePolicyID 确定用户上传时应使用的存储策略
// 优先级: 用户专属 > 角色(按priority排序) > 系统默认
// 多角色时取优先级最高的策略
func (s *StorageAssignService) ResolvePolicyID(userID uint64) uint64 {
assignments := s.getUserAssignments(userID)
if len(assignments) == 0 {
return uint64(config.AppConfig.Storage.DefaultPolicyID)
}
// 已按priority DESC排序, 取第一个
return assignments[0].PolicyID
}
// ResolveAccessMode 确定用户的访问模式
func (s *StorageAssignService) ResolveAccessMode(userID uint64) string {
assignments := s.getUserAssignments(userID)
for _, a := range assignments {
if a.AccessMode != "" {
return a.AccessMode
}
}
return ""
}
// GetUserStorageInfo 获取用户完整的存储策略信息(含配额叠加)
func (s *StorageAssignService) GetUserStorageInfo(userID uint64) (*UserStorageInfo, error) {
assignments := s.getUserAssignments(userID)
var user model.User
config.DB.First(&user, userID)
info := &UserStorageInfo{
UsedStorage: user.UsedStorage,
Assignments: assignments,
}
if len(assignments) == 0 {
// 使用默认策略
info.PolicyID = uint64(config.AppConfig.Storage.DefaultPolicyID)
info.TotalQuota = user.StorageQuota
} else {
// 最高优先级策略
info.PolicyID = assignments[0].PolicyID
info.AccessMode = assignments[0].AccessMode
// 配额叠加: 所有策略的配额之和
var totalQuota int64
for _, a := range assignments {
if a.StorageQuota > 0 {
totalQuota += a.StorageQuota
}
}
if totalQuota > 0 {
info.TotalQuota = totalQuota
} else {
info.TotalQuota = user.StorageQuota
}
}
// 获取策略详情
var policy model.StoragePolicy
if config.DB.First(&policy, info.PolicyID).Error == nil {
info.PolicyName = policy.Name
info.PolicyType = policy.PolicyType
}
if info.TotalQuota > 0 {
info.UsedPercent = float64(info.UsedStorage) / float64(info.TotalQuota) * 100
}
// 根据角色确定文件大小限制
info.MaxFileSize, info.ChunkThreshold = s.getFileSizeLimit(userID)
return info, nil
}
// getFileSizeLimit 根据用户角色返回单文件大小限制和分片阈值
// 返回: maxFileSize(字节), chunkThreshold(字节)
func (s *StorageAssignService) getFileSizeLimit(userID uint64) (int64, int64) {
// 获取用户角色
var userRoles []model.UserRole
config.DB.Where("user_id = ?", userID).Find(&userRoles)
roleIDs := make([]uint64, 0, len(userRoles))
for _, ur := range userRoles {
roleIDs = append(roleIDs, ur.RoleID)
}
// 检查角色名称确定限制
var roles []model.Role
if len(roleIDs) > 0 {
config.DB.Where("id IN ?", roleIDs).Find(&roles)
}
for _, r := range roles {
switch r.Name {
case "admin":
return 0, 100 * 1024 * 1024 // 不限大小, 100MB分片
case "staff":
return 500 * 1024 * 1024, 50 * 1024 * 1024 // 500MB上限, 50MB分片
case "user":
return 100 * 1024 * 1024, 10 * 1024 * 1024 // 100MB上限, 10MB分片
case "guest":
return 0, 0 // 不允许上传
}
}
// 默认
return 100 * 1024 * 1024, 10 * 1024 * 1024
}
// getUserAssignments 获取用户的所有存储分配(去重+排序)
func (s *StorageAssignService) getUserAssignments(userID uint64) []model.StorageAssignment {
var all []model.StorageAssignment
// 1. 用户专属分配
var userAssigns []model.StorageAssignment
config.DB.Where("user_id = ? AND status = 1", userID).Find(&userAssigns)
all = append(all, userAssigns...)
// 2. 角色分配(用户所属的所有角色)
var userRoles []model.UserRole
config.DB.Where("user_id = ?", userID).Find(&userRoles)
for _, ur := range userRoles {
var roleAssigns []model.StorageAssignment
config.DB.Where("group_id = ? AND status = 1", ur.RoleID).Find(&roleAssigns)
all = append(all, roleAssigns...)
}
// 3. 系统默认
if len(all) == 0 {
var defaultAssign model.StorageAssignment
config.DB.Where("is_default = 1 AND status = 1").First(&defaultAssign)
if defaultAssign.ID > 0 {
all = append(all, defaultAssign)
}
}
// 去重(按PolicyID)
seen := make(map[uint64]bool)
unique := make([]model.StorageAssignment, 0, len(all))
for _, a := range all {
if !seen[a.PolicyID] {
seen[a.PolicyID] = true
unique = append(unique, a)
}
}
// 按优先级降序排序
sort.Slice(unique, func(i, j int) bool {
return unique[i].Priority > unique[j].Priority
})
return unique
}
// ========== 管理接口 ==========
// ListAssignments 获取所有分配规则
func (s *StorageAssignService) ListAssignments() ([]dto.StorageAssignmentVO, error) {
var assignments []model.StorageAssignment
if err := config.DB.Order("is_default DESC, priority DESC, group_id ASC").Find(&assignments).Error; err != nil {
return nil, err
}
vos := make([]dto.StorageAssignmentVO, 0, len(assignments))
for _, a := range assignments {
vo := dto.StorageAssignmentVO{
ID: a.ID,
PolicyID: a.PolicyID,
UserID: a.UserID,
GroupID: a.GroupID,
IsDefault: a.IsDefault,
Priority: a.Priority,
StorageQuota: a.StorageQuota,
AccessMode: a.AccessMode,
Status: a.Status,
}
var policy model.StoragePolicy
if config.DB.First(&policy, a.PolicyID).Error == nil {
vo.PolicyName = policy.Name
}
if a.UserID > 0 {
var user model.User
if config.DB.First(&user, a.UserID).Error == nil {
vo.UserName = user.Nickname
}
}
if a.GroupID > 0 {
var role model.Role
if config.DB.First(&role, a.GroupID).Error == nil {
vo.RoleName = role.DisplayName
}
}
vos = append(vos, vo)
}
return vos, nil
}
// SetDefault 设置系统默认存储策略
func (s *StorageAssignService) SetDefault(policyID uint64) error {
// 先清除旧的默认
config.DB.Model(&model.StorageAssignment{}).Where("is_default = 1").Update("is_default", 0)
// 查找或创建默认记录
var existing model.StorageAssignment
err := config.DB.Where("is_default = 0 AND user_id = 0 AND group_id = 0").First(&existing).Error
if err == nil {
// 更新现有记录
existing.PolicyID = policyID
existing.IsDefault = 1
return config.DB.Save(&existing).Error
}
// 创建新记录
return config.DB.Create(&model.StorageAssignment{
PolicyID: policyID,
IsDefault: 1,
Status: 1,
}).Error
}
// AssignToRole 为角色分配存储策略(支持多策略)
func (s *StorageAssignService) AssignToRole(roleID, policyID uint64, quota int64, priority int, accessMode string) error {
// 检查是否已存在相同分配
var existing model.StorageAssignment
err := config.DB.Where("group_id = ? AND policy_id = ?", roleID, policyID).First(&existing).Error
if err == nil {
// 更新
existing.StorageQuota = quota
existing.Priority = priority
existing.AccessMode = accessMode
return config.DB.Save(&existing).Error
}
return config.DB.Create(&model.StorageAssignment{
GroupID: roleID,
PolicyID: policyID,
StorageQuota: quota,
Priority: priority,
AccessMode: accessMode,
Status: 1,
}).Error
}
// AssignToUser 为用户分配存储策略(覆盖角色策略)
func (s *StorageAssignService) AssignToUser(userID, policyID uint64, quota int64, accessMode string) error {
var existing model.StorageAssignment
err := config.DB.Where("user_id = ?", userID).First(&existing).Error
if err == nil {
existing.PolicyID = policyID
existing.StorageQuota = quota
existing.AccessMode = accessMode
return config.DB.Save(&existing).Error
}
return config.DB.Create(&model.StorageAssignment{
UserID: userID,
PolicyID: policyID,
StorageQuota: quota,
Priority: 100, // 用户专属最高优先级
AccessMode: accessMode,
Status: 1,
}).Error
}
// UpdateAssignment 更新分配规则
func (s *StorageAssignService) UpdateAssignment(id uint64, policyID uint64, priority *int, quota *int64, accessMode string) error {
var assignment model.StorageAssignment
if err := config.DB.First(&assignment, id).Error; err != nil {
return errors.New("分配规则不存在")
}
updates := make(map[string]interface{})
if policyID > 0 {
updates["policy_id"] = policyID
}
if priority != nil {
updates["priority"] = *priority
}
if quota != nil {
updates["storage_quota"] = *quota
}
if accessMode != "" {
updates["access_mode"] = accessMode
}
if len(updates) == 0 {
return errors.New("没有需要更新的字段")
}
return config.DB.Model(&model.StorageAssignment{}).Where("id = ?", id).Updates(updates).Error
}
// DeleteAssignment 删除分配规则
func (s *StorageAssignService) DeleteAssignment(id uint64) error {
var assignment model.StorageAssignment
if err := config.DB.First(&assignment, id).Error; err != nil {
return errors.New("分配规则不存在")
}
if assignment.IsDefault == 1 {
return errors.New("不能删除默认分配规则")
}
return config.DB.Delete(&model.StorageAssignment{}, id).Error
}