|
|
|
package admin
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
model "github.com/cloudreve/Cloudreve/v3/models"
|
|
|
|
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem"
|
|
|
|
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
|
|
|
|
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
|
|
|
"github.com/cloudreve/Cloudreve/v3/service/explorer"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
)
|
|
|
|
|
|
|
|
// FileService 文件ID服务
|
|
|
|
type FileService struct {
|
|
|
|
ID uint `uri:"id" json:"id" binding:"required"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// FileBatchService 文件批量操作服务
|
|
|
|
type FileBatchService struct {
|
|
|
|
ID []uint `json:"id" binding:"min=1"`
|
|
|
|
Force bool `json:"force"`
|
|
|
|
UnlinkOnly bool `json:"unlink"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListFolderService 列目录结构
|
|
|
|
type ListFolderService struct {
|
|
|
|
Path string `uri:"path" binding:"required,max=65535"`
|
|
|
|
ID uint `uri:"id" binding:"required"`
|
|
|
|
Type string `uri:"type" binding:"eq=policy|eq=user"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// List 列出指定路径下的目录
|
|
|
|
func (service *ListFolderService) List(c *gin.Context) serializer.Response {
|
|
|
|
if service.Type == "policy" {
|
|
|
|
// 列取存储策略中的目录
|
|
|
|
policy, err := model.GetPolicyByID(service.ID)
|
|
|
|
if err != nil {
|
|
|
|
return serializer.Err(serializer.CodePolicyNotExist, "", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 创建文件系统
|
|
|
|
fs, err := filesystem.NewAnonymousFileSystem()
|
|
|
|
if err != nil {
|
|
|
|
return serializer.Err(serializer.CodeCreateFSError, "", err)
|
|
|
|
}
|
|
|
|
defer fs.Recycle()
|
|
|
|
|
|
|
|
// 列取存储策略中的文件
|
|
|
|
fs.Policy = &policy
|
|
|
|
res, err := fs.ListPhysical(c.Request.Context(), service.Path)
|
|
|
|
if err != nil {
|
|
|
|
return serializer.Err(serializer.CodeListFilesError, "", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return serializer.Response{
|
|
|
|
Data: serializer.BuildObjectList(0, res, nil),
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 列取用户空间目录
|
|
|
|
// 查找用户
|
|
|
|
user, err := model.GetUserByID(service.ID)
|
|
|
|
if err != nil {
|
|
|
|
return serializer.Err(serializer.CodeUserNotFound, "", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 创建文件系统
|
|
|
|
fs, err := filesystem.NewFileSystem(&user)
|
|
|
|
if err != nil {
|
|
|
|
return serializer.Err(serializer.CodeCreateFSError, "", err)
|
|
|
|
}
|
|
|
|
defer fs.Recycle()
|
|
|
|
|
|
|
|
// 列取目录
|
|
|
|
res, err := fs.List(c.Request.Context(), service.Path, nil)
|
|
|
|
if err != nil {
|
|
|
|
return serializer.Err(serializer.CodeListFilesError, "", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return serializer.Response{
|
|
|
|
Data: serializer.BuildObjectList(0, res, nil),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete 删除文件
|
|
|
|
func (service *FileBatchService) Delete(c *gin.Context) serializer.Response {
|
|
|
|
files, err := model.GetFilesByIDs(service.ID, 0)
|
|
|
|
if err != nil {
|
|
|
|
return serializer.DBErr("Failed to list files for deleting", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 根据用户分组
|
|
|
|
userFile := make(map[uint][]model.File)
|
|
|
|
for i := 0; i < len(files); i++ {
|
|
|
|
if _, ok := userFile[files[i].UserID]; !ok {
|
|
|
|
userFile[files[i].UserID] = []model.File{}
|
|
|
|
}
|
|
|
|
userFile[files[i].UserID] = append(userFile[files[i].UserID], files[i])
|
|
|
|
}
|
|
|
|
|
|
|
|
// 异步执行删除
|
|
|
|
go func(files map[uint][]model.File) {
|
|
|
|
for uid, file := range files {
|
|
|
|
var (
|
|
|
|
fs *filesystem.FileSystem
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
user, err := model.GetUserByID(uid)
|
|
|
|
if err != nil {
|
|
|
|
fs, err = filesystem.NewAnonymousFileSystem()
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fs, err = filesystem.NewFileSystem(&user)
|
|
|
|
if err != nil {
|
|
|
|
fs.Recycle()
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 汇总文件ID
|
|
|
|
ids := make([]uint, 0, len(file))
|
|
|
|
for i := 0; i < len(file); i++ {
|
|
|
|
ids = append(ids, file[i].ID)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 执行删除
|
|
|
|
fs.Delete(context.Background(), []uint{}, ids, service.Force, service.UnlinkOnly)
|
|
|
|
fs.Recycle()
|
|
|
|
}
|
|
|
|
}(userFile)
|
|
|
|
|
|
|
|
// 分组执行删除
|
|
|
|
return serializer.Response{}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get 预览文件
|
|
|
|
func (service *FileService) Get(c *gin.Context) serializer.Response {
|
|
|
|
file, err := model.GetFilesByIDs([]uint{service.ID}, 0)
|
|
|
|
if err != nil {
|
|
|
|
return serializer.Err(serializer.CodeFileNotFound, "", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := context.WithValue(context.Background(), fsctx.FileModelCtx, &file[0])
|
|
|
|
var subService explorer.FileIDService
|
|
|
|
res := subService.PreviewContent(ctx, c, false)
|
|
|
|
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
// Files 列出文件
|
|
|
|
func (service *AdminListService) Files() serializer.Response {
|
|
|
|
var res []model.File
|
|
|
|
total := 0
|
|
|
|
|
|
|
|
tx := model.DB.Model(&model.File{})
|
|
|
|
if service.OrderBy != "" {
|
|
|
|
tx = tx.Order(service.OrderBy)
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, v := range service.Conditions {
|
|
|
|
tx = tx.Where(k+" = ?", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(service.Searches) > 0 {
|
|
|
|
search := ""
|
|
|
|
for k, v := range service.Searches {
|
|
|
|
search += k + " like '%" + v + "%' OR "
|
|
|
|
}
|
|
|
|
search = strings.TrimSuffix(search, " OR ")
|
|
|
|
tx = tx.Where(search)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 计算总数用于分页
|
|
|
|
tx.Count(&total)
|
|
|
|
|
|
|
|
// 查询记录
|
|
|
|
tx.Limit(service.PageSize).Offset((service.Page - 1) * service.PageSize).Find(&res)
|
|
|
|
|
|
|
|
// 查询对应用户
|
|
|
|
users := make(map[uint]model.User)
|
|
|
|
for _, file := range res {
|
|
|
|
users[file.UserID] = model.User{}
|
|
|
|
}
|
|
|
|
|
|
|
|
userIDs := make([]uint, 0, len(users))
|
|
|
|
for k := range users {
|
|
|
|
userIDs = append(userIDs, k)
|
|
|
|
}
|
|
|
|
|
|
|
|
var userList []model.User
|
|
|
|
model.DB.Where("id in (?)", userIDs).Find(&userList)
|
|
|
|
|
|
|
|
for _, v := range userList {
|
|
|
|
users[v.ID] = v
|
|
|
|
}
|
|
|
|
|
|
|
|
return serializer.Response{Data: map[string]interface{}{
|
|
|
|
"total": total,
|
|
|
|
"items": res,
|
|
|
|
"users": users,
|
|
|
|
}}
|
|
|
|
}
|