forked from cloudreve/Cloudreve
-
Notifications
You must be signed in to change notification settings - Fork 0
/
share.go
245 lines (214 loc) · 6.31 KB
/
share.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
package model
import (
"errors"
"fmt"
"github.com/HFO4/cloudreve/pkg/cache"
"github.com/HFO4/cloudreve/pkg/hashid"
"github.com/HFO4/cloudreve/pkg/util"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
"strings"
"time"
)
// Share 分享模型
type Share struct {
gorm.Model
Password string // 分享密码,空值为非加密分享
IsDir bool // 原始资源是否为目录
UserID uint // 创建用户ID
SourceID uint // 原始资源ID
Views int // 浏览数
Downloads int // 下载数
RemainDownloads int // 剩余下载配额,负值标识无限制
Expires *time.Time // 过期时间,空值表示无过期时间
PreviewEnabled bool // 是否允许直接预览
SourceName string `gorm:"index:source"` // 用于搜索的字段
// 数据库忽略字段
User User `gorm:"PRELOAD:false,association_autoupdate:false"`
File File `gorm:"PRELOAD:false,association_autoupdate:false"`
Folder Folder `gorm:"PRELOAD:false,association_autoupdate:false"`
}
// Create 创建分享
func (share *Share) Create() (uint, error) {
if err := DB.Create(share).Error; err != nil {
util.Log().Warning("无法插入数据库记录, %s", err)
return 0, err
}
return share.ID, nil
}
// GetShareByHashID 根据HashID查找分享
func GetShareByHashID(hashID string) *Share {
id, err := hashid.DecodeHashID(hashID, hashid.ShareID)
if err != nil {
return nil
}
var share Share
result := DB.First(&share, id)
if result.Error != nil {
return nil
}
return &share
}
// IsAvailable 返回此分享是否可用(是否过期)
func (share *Share) IsAvailable() bool {
if share.RemainDownloads == 0 {
return false
}
if share.Expires != nil && time.Now().After(*share.Expires) {
return false
}
// 检查创建者状态
if share.Creator().Status != Active {
return false
}
// 检查源对象是否存在
var sourceID uint
if share.IsDir {
folder := share.SourceFolder()
sourceID = folder.ID
} else {
file := share.SourceFile()
sourceID = file.ID
}
if sourceID == 0 {
// TODO 是否要在这里删除这个无效分享?
return false
}
return true
}
// Creator 获取分享的创建者
func (share *Share) Creator() *User {
if share.User.ID == 0 {
share.User, _ = GetUserByID(share.UserID)
}
return &share.User
}
// Source 返回源对象
func (share *Share) Source() interface{} {
if share.IsDir {
return share.SourceFolder()
}
return share.SourceFile()
}
// SourceFolder 获取源目录
func (share *Share) SourceFolder() *Folder {
if share.Folder.ID == 0 {
folders, _ := GetFoldersByIDs([]uint{share.SourceID}, share.UserID)
if len(folders) > 0 {
share.Folder = folders[0]
}
}
return &share.Folder
}
// SourceFile 获取源文件
func (share *Share) SourceFile() *File {
if share.File.ID == 0 {
files, _ := GetFilesByIDs([]uint{share.SourceID}, share.UserID)
if len(files) > 0 {
share.File = files[0]
}
}
return &share.File
}
// CanBeDownloadBy 返回此分享是否可以被给定用户下载
func (share *Share) CanBeDownloadBy(user *User) error {
// 用户组权限
if !user.Group.OptionsSerialized.ShareDownload {
if user.IsAnonymous() {
return errors.New("未登录用户无法下载")
}
return errors.New("您当前的用户组无权下载")
}
return nil
}
// WasDownloadedBy 返回分享是否已被用户下载过
func (share *Share) WasDownloadedBy(user *User, c *gin.Context) (exist bool) {
if user.IsAnonymous() {
exist = util.GetSession(c, fmt.Sprintf("share_%d_%d", share.ID, user.ID)) != nil
} else {
_, exist = cache.Get(fmt.Sprintf("share_%d_%d", share.ID, user.ID))
}
return exist
}
// DownloadBy 增加下载次数,匿名用户不会缓存
func (share *Share) DownloadBy(user *User, c *gin.Context) error {
if !share.WasDownloadedBy(user, c) {
share.Downloaded()
if !user.IsAnonymous() {
cache.Set(fmt.Sprintf("share_%d_%d", share.ID, user.ID), true,
GetIntSetting("share_download_session_timeout", 2073600))
} else {
util.SetSession(c, map[string]interface{}{fmt.Sprintf("share_%d_%d", share.ID, user.ID): true})
}
}
return nil
}
// Viewed 增加访问次数
func (share *Share) Viewed() {
share.Views++
DB.Model(share).UpdateColumn("views", gorm.Expr("views + ?", 1))
}
// Downloaded 增加下载次数
func (share *Share) Downloaded() {
share.Downloads++
if share.RemainDownloads > 0 {
share.RemainDownloads--
}
DB.Model(share).Updates(map[string]interface{}{
"downloads": share.Downloads,
"remain_downloads": share.RemainDownloads,
})
}
// Update 更新分享属性
func (share *Share) Update(props map[string]interface{}) error {
return DB.Model(share).Updates(props).Error
}
// Delete 删除分享
func (share *Share) Delete() error {
return DB.Model(share).Delete(share).Error
}
// DeleteShareBySourceIDs 根据原始资源类型和ID删除文件
func DeleteShareBySourceIDs(sources []uint, isDir bool) error {
return DB.Where("source_id in (?) and is_dir = ?", sources, isDir).Delete(&Share{}).Error
}
// ListShares 列出UID下的分享
func ListShares(uid uint, page, pageSize int, order string, publicOnly bool) ([]Share, int) {
var (
shares []Share
total int
)
dbChain := DB
dbChain = dbChain.Where("user_id = ?", uid)
if publicOnly {
dbChain = dbChain.Where("password = ?", "")
}
// 计算总数用于分页
dbChain.Model(&Share{}).Count(&total)
// 查询记录
dbChain.Limit(pageSize).Offset((page - 1) * pageSize).Order(order).Find(&shares)
return shares, total
}
// SearchShares 根据关键字搜索分享
func SearchShares(page, pageSize int, order, keywords string) ([]Share, int) {
var (
shares []Share
total int
)
keywordList := strings.Split(keywords, " ")
availableList := make([]string, 0, len(keywordList))
for i := 0; i < len(keywordList); i++ {
if len(keywordList[i]) > 0 {
availableList = append(availableList, keywordList[i])
}
}
if len(availableList) == 0 {
return shares, 0
}
dbChain := DB
dbChain = dbChain.Where("password = ? and remain_downloads <> 0 and (expires is NULL or expires > ?) and source_name like ?", "", time.Now(), "%"+strings.Join(availableList, "%")+"%")
// 计算总数用于分页
dbChain.Model(&Share{}).Count(&total)
// 查询记录
dbChain.Limit(pageSize).Offset((page - 1) * pageSize).Order(order).Find(&shares)
return shares, total
}