初始化2

This commit is contained in:
2026-07-10 17:33:33 +08:00
parent b51ee98afa
commit 94f6ecf901
59 changed files with 3893 additions and 980 deletions

View File

@@ -8,6 +8,7 @@ import (
"seeyon-filesystem/dto"
"seeyon-filesystem/model"
"seeyon-filesystem/repository"
"seeyon-filesystem/utils"
)
// FolderService 文件夹业务服务
@@ -26,30 +27,35 @@ func NewFolderService() *FolderService {
// Create 创建文件夹
func (s *FolderService) Create(req *dto.CreateFolderRequest, ownerID uint64) (*dto.FolderVO, error) {
parentID := uint64(req.ParentID)
// 构建物化路径
parentPath := "/"
if req.ParentID > 0 {
parent, err := s.folderRepo.FindByID(req.ParentID)
if parentID > 0 {
parent, err := s.folderRepo.FindByID(parentID)
if err != nil {
return nil, errors.New("父文件夹不存在")
}
if parent.OwnerID != ownerID {
if !s.canAccessFolder(parent.OwnerID, ownerID) {
return nil, errors.New("无权访问父文件夹")
}
parentPath = parent.Path
}
// 检查同名文件夹
existing, _ := s.folderRepo.FindByNameAndParent(req.Name, req.ParentID, ownerID)
existing, _ := s.folderRepo.FindByNameAndParent(req.Name, parentID, ownerID)
if existing != nil {
return nil, errors.New("同名文件夹已存在")
}
folderID := utils.GenID()
folder := &model.Folder{
ID: folderID,
BizID: req.BizID,
Name: req.Name,
ParentID: req.ParentID,
ParentID: parentID,
OwnerID: ownerID,
Path: parentPath, // 先创建, 获取ID后再更新路径
Path: fmt.Sprintf("%s%d/", parentPath, folderID),
Status: 1,
}
@@ -57,12 +63,6 @@ func (s *FolderService) Create(req *dto.CreateFolderRequest, ownerID uint64) (*d
return nil, fmt.Errorf("创建文件夹失败: %w", err)
}
// 更新物化路径
folder.Path = fmt.Sprintf("%s%d/", parentPath, folder.ID)
if err := s.folderRepo.Update(folder); err != nil {
return nil, fmt.Errorf("更新文件夹路径失败: %w", err)
}
return s.toFolderVO(folder), nil
}
@@ -72,16 +72,26 @@ func (s *FolderService) GetByID(id uint64, ownerID uint64) (*dto.FolderVO, error
if err != nil {
return nil, errors.New("文件夹不存在")
}
if folder.OwnerID != ownerID {
if !s.canAccessFolder(folder.OwnerID, ownerID) {
return nil, errors.New("无权访问此文件夹")
}
return s.toFolderVO(folder), nil
}
// ListChildren 获取文件夹的子项(文件+文件夹, 基于权限)
func (s *FolderService) ListChildren(folderID uint64, userID uint64) (*dto.FileListVO, error) {
// 获取用户角色IDs
// GetByBizID 根据业务ID获取文件夹
func (s *FolderService) GetByBizID(bizID string, ownerID uint64) (*dto.FolderVO, error) {
folder, err := s.folderRepo.FindByBizID(bizID, ownerID)
if err != nil {
return nil, errors.New("文件夹不存在")
}
return s.toFolderVO(folder), nil
}
// ListChildren 获取文件夹的子项(文件+文件夹, 基于权限, 支持分页)
// 管理员看全部, 非管理员只看自己创建的 + 被授权的
func (s *FolderService) ListChildren(folderID uint64, userID uint64, page, pageSize int) (*dto.FileListVO, error) {
roleIDs := s.getUserRoleIDs(userID)
isAdmin := s.isAdmin(roleIDs)
// 如果指定了文件夹ID, 验证访问权限
if folderID > 0 {
@@ -89,19 +99,32 @@ func (s *FolderService) ListChildren(folderID uint64, userID uint64) (*dto.FileL
if err != nil {
return nil, errors.New("文件夹不存在")
}
if folder.OwnerID != userID {
if !isAdmin && folder.OwnerID != userID {
return nil, errors.New("无权访问此文件夹")
}
}
// 查询子文件夹(暂时只查自己创建的)
folders, err := s.folderRepo.ListByParent(folderID, userID)
if err != nil {
return nil, err
// 查询子文件夹
var folders []model.Folder
var totalFolders int64
if isAdmin {
folders, _ = s.folderRepo.ListByParentAll(folderID)
totalFolders, _ = s.folderRepo.CountByParentAll(folderID)
} else {
folders, _ = s.folderRepo.ListByParent(folderID, userID)
totalFolders, _ = s.folderRepo.CountByParent(folderID, userID)
}
// 查询子文件(基于权限: 自己的 + 被授权的)
files, err := s.fileRepo.ListByFolder(folderID, userID, roleIDs)
// 分页查询子文件
var files []model.File
var totalFiles int64
var err error
if pageSize > 0 {
files, totalFiles, err = s.fileRepo.ListByFolderPaginated(folderID, userID, roleIDs, page, pageSize)
} else {
files, err = s.fileRepo.ListByFolder(folderID, userID, roleIDs)
totalFiles = int64(len(files))
}
if err != nil {
return nil, err
}
@@ -118,18 +141,40 @@ func (s *FolderService) ListChildren(folderID uint64, userID uint64) (*dto.FileL
}
return &dto.FileListVO{
Folders: folderVOs,
Files: fileVOs,
Folders: folderVOs,
Files: fileVOs,
TotalFiles: totalFiles,
TotalFolders: totalFolders,
Page: page,
PageSize: pageSize,
}, nil
}
// canAccessFolder 检查用户是否有权操作该文件夹(owner / admin)
func (s *FolderService) canAccessFolder(folderOwnerID, userID uint64) bool {
if folderOwnerID == userID {
return true
}
return s.isAdmin(s.getUserRoleIDs(userID))
}
// isAdmin 检查用户是否为管理员
func (s *FolderService) isAdmin(roleIDs []uint64) bool {
if len(roleIDs) == 0 {
return false
}
var count int64
config.DB.Model(&model.Role{}).Where("id IN ? AND name = ?", roleIDs, "admin").Count(&count)
return count > 0
}
// Rename 重命名文件夹(乐观锁)
func (s *FolderService) Rename(id uint64, newName string, ownerID uint64, version int) error {
folder, err := s.folderRepo.FindByID(id)
if err != nil {
return errors.New("文件夹不存在")
}
if folder.OwnerID != ownerID {
if !s.canAccessFolder(folder.OwnerID, ownerID) {
return errors.New("无权操作此文件夹")
}
@@ -158,7 +203,7 @@ func (s *FolderService) Delete(id uint64, ownerID uint64) error {
if err != nil {
return errors.New("文件夹不存在")
}
if folder.OwnerID != ownerID {
if !s.canAccessFolder(folder.OwnerID, ownerID) {
return errors.New("无权操作此文件夹")
}
@@ -168,9 +213,12 @@ func (s *FolderService) Delete(id uint64, ownerID uint64) error {
// toFolderVO 转换为视图对象
func (s *FolderService) toFolderVO(folder *model.Folder) *dto.FolderVO {
return &dto.FolderVO{
ID: folder.ID,
ID: dto.StringID(folder.ID),
BizID: folder.BizID,
Name: folder.Name,
ParentID: folder.ParentID,
ParentID: dto.StringID(folder.ParentID),
OwnerID: dto.StringID(folder.OwnerID),
OwnerName: s.getUserName(folder.OwnerID),
Path: folder.Path,
Version: folder.Version,
CreatedAt: folder.CreatedAt,
@@ -178,6 +226,18 @@ func (s *FolderService) toFolderVO(folder *model.Folder) *dto.FolderVO {
}
}
// getUserName 根据用户ID获取显示名称
func (s *FolderService) getUserName(userID uint64) string {
var user model.User
if config.DB.Select("nickname", "username").First(&user, userID).Error != nil {
return ""
}
if user.Nickname != "" {
return user.Nickname
}
return user.Username
}
// getUserRoleIDs 获取用户的角色ID列表
func (s *FolderService) getUserRoleIDs(userID uint64) []uint64 {
var userRoles []model.UserRole
@@ -191,16 +251,31 @@ func (s *FolderService) getUserRoleIDs(userID uint64) []uint64 {
// toFileVO 转换为视图对象
func (s *FolderService) toFileVO(file *model.File) *dto.FileVO {
return &dto.FileVO{
ID: file.ID,
Name: file.Name,
Extension: file.Extension,
FolderID: file.FolderID,
Size: file.Size,
MimeType: file.MimeType,
IsFavorite: file.IsFavorite,
DownloadCount: file.DownloadCount,
CreatedAt: file.CreatedAt,
UpdatedAt: file.UpdatedAt,
vo := &dto.FileVO{
ID: dto.StringID(file.ID),
Name: file.Name,
Extension: file.Extension,
FolderID: dto.StringID(file.FolderID),
OwnerID: dto.StringID(file.OwnerID),
OwnerName: s.getUserName(file.OwnerID),
Size: file.Size,
StorageKey: file.StorageKey,
StoragePolicyID: file.StoragePolicyID,
MimeType: file.MimeType,
IsFavorite: file.IsFavorite,
DownloadCount: file.DownloadCount,
Version: file.Version,
CreatedAt: file.CreatedAt,
UpdatedAt: file.UpdatedAt,
}
// 生成下载/预览链接
if file.StorageKey != "" {
downloadURL, _ := GenerateFileURL(file, "download")
previewURL, _ := GenerateFileURL(file, "preview")
vo.DownloadURL = downloadURL
vo.PreviewURL = previewURL
}
return vo
}