diff --git a/models/share.go b/models/share.go index f08b0df..3cbdfb7 100644 --- a/models/share.go +++ b/models/share.go @@ -19,6 +19,11 @@ type Share struct { RemainDownloads int // 剩余下载配额,负值标识无限制 Expires *time.Time // 过期时间,空值表示无过期时间 Score int // 每人次下载扣除积分 + + // 数据库忽略字段 + 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 创建分享 @@ -32,6 +37,7 @@ func (share *Share) Create() (uint, error) { } // GetShareByHashID 根据HashID查找分享 +// TODO 测试 func GetShareByHashID(hashID string) *Share { id, err := hashid.DecodeHashID(hashID, hashid.ShareID) if err != nil { @@ -45,3 +51,59 @@ func GetShareByHashID(hashID string) *Share { return &share } + +// IsAvailable 返回此分享是否可用(是否过期) +// TODO 测试 +func (share *Share) IsAvailable() bool { + if share.RemainDownloads == 0 { + return false + } + if share.Expires != nil && time.Now().After(*share.Expires) { + return false + } + + // 检查源对象是否存在 + var sourceID uint + if share.IsDir { + folder := share.GetSourceFolder() + sourceID = folder.ID + } else { + file := share.GetSourceFile() + sourceID = file.ID + } + if sourceID == 0 { + return false + } + + return true +} + +// GetCreator 获取分享的创建者 +func (share *Share) GetCreator() *User { + if share.User.ID == 0 { + share.User, _ = GetUserByID(share.UserID) + } + return &share.User +} + +// GetSourceFolder 获取源目录 +func (share *Share) GetSourceFolder() *Folder { + if share.Folder.ID == 0 { + folders, _ := GetFoldersByIDs([]uint{share.SourceID}, share.UserID) + if len(folders) > 0 { + share.Folder = folders[0] + } + } + return &share.Folder +} + +// GetSourceFile 获取源文件 +func (share *Share) GetSourceFile() *File { + if share.File.ID == 0 { + files, _ := GetFilesByIDs([]uint{share.SourceID}, share.UserID) + if len(files) > 0 { + share.File = files[0] + } + } + return &share.File +} diff --git a/pkg/serializer/share.go b/pkg/serializer/share.go new file mode 100644 index 0000000..20c9265 --- /dev/null +++ b/pkg/serializer/share.go @@ -0,0 +1,70 @@ +package serializer + +import ( + model "github.com/HFO4/cloudreve/models" + "github.com/HFO4/cloudreve/pkg/hashid" + "time" +) + +// Share 分享序列化 +type Share struct { + Locked bool `json:"locked"` + IsDir bool `json:"is_dir"` + Score int `json:"score"` + CreateDate string `json:"create_date,omitempty"` + Downloads int `json:"downloads"` + Views int `json:"views"` + Expire int64 `json:"expire"` + Creator *shareCreator `json:"creator,omitempty"` + Source *shareSource `json:"source,omitempty"` +} + +type shareCreator struct { + Key string `json:"key"` + Nick string `json:"nick"` + GroupName string `json:"group_name"` +} + +type shareSource struct { + Name string `json:"name"` + Size uint64 `json:"size"` +} + +// BuildShareResponse 构建获取分享信息响应 +func BuildShareResponse(share *model.Share, unlocked bool) Share { + creator := share.GetCreator() + resp := Share{ + Locked: !unlocked, + Creator: &shareCreator{ + Key: hashid.HashID(creator.ID, hashid.UserID), + Nick: creator.Nick, + GroupName: creator.Group.Name, + }, + Score: share.Score, + CreateDate: share.CreatedAt.Format("2006-01-02 15:04:05"), + } + + if !unlocked { + return resp + } + + resp.IsDir = share.IsDir + resp.Downloads = share.Downloads + resp.Views = share.Views + if share.Expires != nil { + resp.Expire = share.Expires.Unix() - time.Now().Unix() + } + + if share.IsDir { + + } else { + source := share.GetSourceFile() + resp.Source = &shareSource{ + Name: source.Name, + Size: source.Size, + } + } + + return resp + +} diff --git a/service/share/manage.go b/service/share/manage.go index c70f529..dda8a34 100644 --- a/service/share/manage.go +++ b/service/share/manage.go @@ -19,11 +19,6 @@ type ShareCreateService struct { Score int `json:"score" binding:"gte=0"` } -// ShareGetService 获取分享服务 -type ShareGetService struct { - Password string `form:"password" binding:"max=255"` -} - // Create 创建新分享 func (service *ShareCreateService) Create(c *gin.Context) serializer.Response { user := currentUser(c) @@ -51,11 +46,12 @@ func (service *ShareCreateService) Create(c *gin.Context) serializer.Response { } newShare := model.Share{ - Password: service.Password, - IsDir: service.IsDir, - UserID: user.ID, - SourceID: service.SourceID, - Score: service.Score, + Password: service.Password, + IsDir: service.IsDir, + UserID: user.ID, + SourceID: service.SourceID, + Score: service.Score, + RemainDownloads: -1, } // 如果开启了自动过期 @@ -85,20 +81,6 @@ func (service *ShareCreateService) Create(c *gin.Context) serializer.Response { } -// Get 获取分享内容 -func (service *ShareGetService) Get(c *gin.Context) serializer.Response { - user := currentUser(c) - share := model.GetShareByHashID(c.Param("id")) - if share == nil { - return serializer.Err(serializer.CodeNotFound, "分享不存在或已被取消", nil) - } - - return serializer.Response{ - Code: 0, - Data: user, - } -} - func currentUser(c *gin.Context) *model.User { var user *model.User if userCtx, ok := c.Get("user"); ok { diff --git a/service/share/visit.go b/service/share/visit.go new file mode 100644 index 0000000..7514dce --- /dev/null +++ b/service/share/visit.go @@ -0,0 +1,41 @@ +package share + +import ( + "fmt" + model "github.com/HFO4/cloudreve/models" + "github.com/HFO4/cloudreve/pkg/serializer" + "github.com/HFO4/cloudreve/pkg/util" + "github.com/gin-gonic/gin" +) + +// ShareGetService 获取分享服务 +type ShareGetService struct { + Password string `form:"password" binding:"max=255"` +} + +// Get 获取分享内容 +func (service *ShareGetService) Get(c *gin.Context) serializer.Response { + share := model.GetShareByHashID(c.Param("id")) + if share == nil || !share.IsAvailable() { + return serializer.Err(serializer.CodeNotFound, "分享不存在或已被取消", nil) + } + + // 是否已解锁 + unlocked := true + if share.Password != "" { + sessionKey := fmt.Sprintf("share_unlock_%d", share.ID) + unlocked = util.GetSession(c, sessionKey) != nil + if !unlocked && service.Password != "" { + // 如果未解锁,且指定了密码,则尝试解锁 + if service.Password == share.Password { + unlocked = true + util.SetSession(c, map[string]interface{}{sessionKey: true}) + } + } + } + + return serializer.Response{ + Code: 0, + Data: serializer.BuildShareResponse(share, unlocked), + } +}