Feat: delete objects

This commit is contained in:
HFO4
2019-11-30 15:09:56 +08:00
parent 0cbbe5bb79
commit 93010e3525
26 changed files with 398 additions and 55 deletions

View File

@@ -3,6 +3,7 @@ package model
import (
"github.com/HFO4/cloudreve/pkg/util"
"github.com/jinzhu/gorm"
"path"
)
// File 文件
@@ -31,7 +32,7 @@ func (file *File) Create() (uint, error) {
return file.ID, nil
}
// GetFileByPathAndName 给定路径、文件名、用户ID查找文件
// GetFileByPathAndName 给定路径(s)、文件名、用户ID查找文件
func GetFileByPathAndName(path string, name string, uid uint) (File, error) {
var file File
result := DB.Where("user_id = ? AND dir = ? AND name=?", uid, path, name).First(&file)
@@ -45,6 +46,20 @@ func (folder *Folder) GetChildFile() ([]File, error) {
return files, result.Error
}
// GetChildFilesOfFolders 批量检索目录子文件
func GetChildFilesOfFolders(folders *[]Folder) ([]File, error) {
// 将所有待删除目录ID抽离以便检索文件
folderIDs := make([]uint, 0, len(*folders))
for _, value := range *folders {
folderIDs = append(folderIDs, value.ID)
}
// 检索文件
var files []File
result := DB.Where("folder_id in (?)", folderIDs).Find(&files)
return files, result.Error
}
// GetPolicy 获取文件所属策略
// TODO:test
func (file *File) GetPolicy() *Policy {
@@ -53,3 +68,52 @@ func (file *File) GetPolicy() *Policy {
}
return &file.Policy
}
// GetFileByPaths 根据给定的文件路径(s)查找文件
func GetFileByPaths(paths []string, uid uint) ([]File, error) {
var files []File
tx := DB
for _, value := range paths {
base := path.Base(value)
dir := path.Dir(value)
tx = tx.Or("dir = ? and name = ? and user_id = ?", dir, base, uid)
}
result := tx.Find(&files)
return files, result.Error
}
// RemoveFilesWithSoftLinks 去除给定的文件列表中有软链接的文件
func RemoveFilesWithSoftLinks(files []File) ([]File, error) {
// 结果值
filteredFiles := make([]File, 0)
// 查询软链接的文件
var filesWithSoftLinks []File
tx := DB
for _, value := range files {
tx = tx.Or("source_name = ? and policy_id = ? and id != ?", value.SourceName, value.GetPolicy().ID, value.ID)
}
result := tx.Find(&filesWithSoftLinks)
if result.Error != nil {
return nil, result.Error
}
// 过滤具有软连接的文件
for i := 0; i < len(files); i++ {
for _, value := range filesWithSoftLinks {
if value.PolicyID != files[i].PolicyID || value.SourceName != files[i].SourceName {
filteredFiles = append(filteredFiles, files[i])
break
}
}
}
return filteredFiles, nil
}
// DeleteFileByIDs 根据给定ID批量删除文件记录
func DeleteFileByIDs(ids []uint) error {
result := DB.Where("id in (?)", ids).Delete(&File{})
return result.Error
}

View File

@@ -38,3 +38,17 @@ func (folder *Folder) GetChildFolder() ([]Folder, error) {
result := DB.Where("parent_id = ?", folder.ID).Find(&folders)
return folders, result.Error
}
// GetRecursiveChildFolder 查找所有递归子目录
func GetRecursiveChildFolder(dirs []string, uid uint) ([]Folder, error) {
folders := make([]Folder, 0, len(dirs))
search := util.BuildRegexp(dirs, "^", "/", "|")
result := DB.Where("(owner_id = ? and position_absolute REGEXP ?) or position_absolute in (?)", uid, search, dirs).Find(&folders)
return folders, result.Error
}
// DeleteFolderByIDs 根据给定ID批量删除目录记录
func DeleteFolderByIDs(ids []uint) error {
result := DB.Where("id in (?)", ids).Delete(&Folder{})
return result.Error
}

View File

@@ -54,17 +54,17 @@ func migration() {
}
func addDefaultPolicy() {
_, err := GetPolicyByID(1)
_, err := GetPolicyByID(uint(1))
// 未找到初始存储策略时,则创建
if gorm.IsRecordNotFoundError(err) {
defaultPolicy := Policy{
Name: "默认上传策略",
Name: "默认存储策略",
Type: "local",
Server: "/Api/V3/File/Upload",
Server: "/api/v3/file/upload",
BaseURL: "http://cloudreve.org/public/uploads/",
MaxSize: 10 * 1024 * 1024 * 1024,
AutoRename: true,
DirNameRule: "{date}/{uid}",
DirNameRule: "uploads/{uid}/{path}",
FileNameRule: "{uid}_{randomkey8}_{originname}",
IsOriginLinkEnable: false,
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/jinzhu/gorm"
"path/filepath"
"strconv"
"sync"
"time"
)
@@ -41,16 +42,36 @@ type PolicyOption struct {
RangeTransferEnabled bool `json:"range_transfer_enabled"`
}
// 存储策略缓存,部分情况下需要频繁查询存储策略
var policyCache = make(map[uint]Policy)
var rw sync.RWMutex
// GetPolicyByID 用ID获取存储策略
func GetPolicyByID(ID interface{}) (Policy, error) {
// 尝试读取缓存
rw.RLock()
if policy, ok := policyCache[ID.(uint)]; ok {
rw.RUnlock()
return policy, nil
}
rw.RUnlock()
var policy Policy
result := DB.First(&policy, ID)
// 写入缓存
if result.Error == nil {
rw.Lock()
policyCache[policy.ID] = policy
rw.Unlock()
}
return policy, result.Error
}
// AfterFind 找到上传策略后的钩子
// AfterFind 找到存储策略后的钩子
func (policy *Policy) AfterFind() (err error) {
// 解析上传策略设置到OptionsSerialized
// 解析存储策略设置到OptionsSerialized
err = json.Unmarshal([]byte(policy.Options), &policy.OptionsSerialized)
if policy.OptionsSerialized.FileType == nil {
policy.OptionsSerialized.FileType = []string{}

View File

@@ -13,16 +13,16 @@ func TestGetPolicyByID(t *testing.T) {
asserts := assert.New(t)
rows := sqlmock.NewRows([]string{"name", "type", "options"}).
AddRow("默认上传策略", "local", "{\"op_name\":\"123\"}")
AddRow("默认存储策略", "local", "{\"op_name\":\"123\"}")
mock.ExpectQuery("^SELECT \\* FROM `(.+)` WHERE `(.+)`\\.`deleted_at` IS NULL AND \\(\\(`policies`.`id` = 1\\)\\)(.+)$").WillReturnRows(rows)
policy, err := GetPolicyByID(1)
policy, err := GetPolicyByID(uint(1))
asserts.NoError(err)
asserts.Equal("默认上传策略", policy.Name)
asserts.Equal("默认存储策略", policy.Name)
asserts.Equal("123", policy.OptionsSerialized.OPName)
rows = sqlmock.NewRows([]string{"name", "type", "options"})
mock.ExpectQuery("^SELECT \\* FROM `(.+)` WHERE `(.+)`\\.`deleted_at` IS NULL AND \\(\\(`policies`.`id` = 1\\)\\)(.+)$").WillReturnRows(rows)
policy, err = GetPolicyByID(1)
policy, err = GetPolicyByID(uint(1))
asserts.Error(err)
}

View File

@@ -83,7 +83,7 @@ func (user *User) GetRemainingCapacity() uint64 {
return user.Group.MaxStorage - user.Storage
}
// GetPolicyID 获取用户当前的上传策略ID
// GetPolicyID 获取用户当前的存储策略ID
func (user *User) GetPolicyID() uint {
// 用户未指定时,返回可用的第一个
if user.OptionsSerialized.PreferredPolicy == 0 {

View File

@@ -22,7 +22,7 @@ func TestGetUserByID(t *testing.T) {
mock.ExpectQuery("^SELECT (.+)").WillReturnRows(groupRows)
policyRows := sqlmock.NewRows([]string{"id", "name"}).
AddRow(1, "默认上传策略")
AddRow(1, "默认存储策略")
mock.ExpectQuery("^SELECT (.+)").WillReturnRows(policyRows)
user, err := GetUserByID(1)
@@ -50,7 +50,7 @@ func TestGetUserByID(t *testing.T) {
OptionsSerialized: PolicyOption{
FileType: []string{},
},
Name: "默认上传策略",
Name: "默认存储策略",
},
}, user)
@@ -105,7 +105,7 @@ func TestUser_AfterFind(t *testing.T) {
asserts := assert.New(t)
policyRows := sqlmock.NewRows([]string{"id", "name"}).
AddRow(1, "默认上传策略")
AddRow(1, "默认存储策略")
mock.ExpectQuery("^SELECT (.+)").WillReturnRows(policyRows)
newUser := NewUser()
@@ -117,7 +117,7 @@ func TestUser_AfterFind(t *testing.T) {
asserts.NoError(err)
asserts.NoError(mock.ExpectationsWereMet())
asserts.Equal(expected, newUser.OptionsSerialized)
asserts.Equal("默认上传策略", newUser.Policy.Name)
asserts.Equal("默认存储策略", newUser.Policy.Name)
}
func TestUser_BeforeSave(t *testing.T) {
@@ -199,7 +199,7 @@ func TestUser_DeductionCapacity(t *testing.T) {
mock.ExpectQuery("^SELECT (.+)").WillReturnRows(groupRows)
policyRows := sqlmock.NewRows([]string{"id", "name"}).
AddRow(1, "默认上传策略")
AddRow(1, "默认存储策略")
mock.ExpectQuery("^SELECT (.+)").WillReturnRows(policyRows)
newUser, err := GetUserByID(1)