Init V4 community edition (#2265)

* Init V4 community edition

* Init V4 community edition
This commit is contained in:
AaronLiu
2025-04-20 17:31:25 +08:00
committed by GitHub
parent da4e44b77a
commit 21d158db07
597 changed files with 119415 additions and 41692 deletions

View File

@@ -1,150 +1,90 @@
package share
import (
"net/url"
"context"
"time"
model "github.com/cloudreve/Cloudreve/v3/models"
"github.com/cloudreve/Cloudreve/v3/pkg/hashid"
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
"github.com/cloudreve/Cloudreve/v4/application/dependency"
"github.com/cloudreve/Cloudreve/v4/ent"
"github.com/cloudreve/Cloudreve/v4/inventory"
"github.com/cloudreve/Cloudreve/v4/inventory/types"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/manager"
"github.com/cloudreve/Cloudreve/v4/pkg/serializer"
"github.com/cloudreve/Cloudreve/v4/service/explorer"
"github.com/gin-gonic/gin"
)
// ShareCreateService 创建新分享服务
type ShareCreateService struct {
SourceID string `json:"id" binding:"required"`
IsDir bool `json:"is_dir"`
Password string `json:"password" binding:"max=255"`
RemainDownloads int `json:"downloads"`
Expire int `json:"expire"`
Preview bool `json:"preview"`
type (
// ShareCreateService 创建新分享服务
ShareCreateService struct {
Uri string `json:"uri" binding:"required"`
IsPrivate bool `json:"is_private"`
RemainDownloads int `json:"downloads"`
Expire int `json:"expire"`
}
ShareCreateParamCtx struct{}
)
// Upsert 创建或更新分享
func (service *ShareCreateService) Upsert(c *gin.Context, existed int) (string, error) {
dep := dependency.FromContext(c)
user := inventory.UserFromContext(c)
m := manager.NewFileManager(dep, user)
defer m.Recycle()
// Check group permission for creating share link
if !user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionShare)) {
return "", serializer.NewError(serializer.CodeGroupNotAllowed, "Group permission denied", nil)
}
uri, err := fs.NewUriFromString(service.Uri)
if err != nil {
return "", serializer.NewError(serializer.CodeParamErr, "unknown uri", err)
}
var expires *time.Time
if service.Expire > 0 {
expires = new(time.Time)
*expires = time.Now().Add(time.Duration(service.Expire) * time.Second)
}
share, err := m.CreateOrUpdateShare(c, uri, &manager.CreateShareArgs{
IsPrivate: service.IsPrivate,
RemainDownloads: service.RemainDownloads,
Expire: expires,
ExistedShareID: existed,
})
if err != nil {
return "", err
}
base := dep.SettingProvider().SiteURL(c)
return explorer.BuildShareLink(share, dep.HashIDEncoder(), base), nil
}
// ShareUpdateService 分享更新服务
type ShareUpdateService struct {
Prop string `json:"prop" binding:"required,eq=password|eq=preview_enabled"`
Value string `json:"value" binding:"max=255"`
}
func DeleteShare(c *gin.Context, shareId int) error {
dep := dependency.FromContext(c)
user := inventory.UserFromContext(c)
shareClient := dep.ShareClient()
// Delete 删除分享
func (service *Service) Delete(c *gin.Context, user *model.User) serializer.Response {
share := model.GetShareByHashID(c.Param("id"))
if share == nil || share.Creator().ID != user.ID {
return serializer.Err(serializer.CodeShareLinkNotFound, "", nil)
}
if err := share.Delete(); err != nil {
return serializer.DBErr("Failed to delete share record", err)
}
return serializer.Response{}
}
// Update 更新分享属性
func (service *ShareUpdateService) Update(c *gin.Context) serializer.Response {
shareCtx, _ := c.Get("share")
share := shareCtx.(*model.Share)
switch service.Prop {
case "password":
err := share.Update(map[string]interface{}{"password": service.Value})
if err != nil {
return serializer.DBErr("Failed to update share record", err)
}
case "preview_enabled":
value := service.Value == "true"
err := share.Update(map[string]interface{}{"preview_enabled": value})
if err != nil {
return serializer.DBErr("Failed to update share record", err)
}
return serializer.Response{
Data: value,
}
}
return serializer.Response{
Data: service.Value,
}
}
// Create 创建新分享
func (service *ShareCreateService) Create(c *gin.Context) serializer.Response {
userCtx, _ := c.Get("user")
user := userCtx.(*model.User)
// 是否拥有权限
if !user.Group.ShareEnabled {
return serializer.Err(serializer.CodeGroupNotAllowed, "", nil)
}
// 源对象真实ID
ctx := context.WithValue(c, inventory.LoadShareFile{}, true)
var (
sourceID uint
sourceName string
err error
share *ent.Share
err error
)
if service.IsDir {
sourceID, err = hashid.DecodeHashID(service.SourceID, hashid.FolderID)
if user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionIsAdmin)) {
share, err = shareClient.GetByID(ctx, shareId)
} else {
sourceID, err = hashid.DecodeHashID(service.SourceID, hashid.FileID)
share, err = shareClient.GetByIDUser(ctx, shareId, user.ID)
}
if err != nil {
return serializer.Err(serializer.CodeNotFound, "", nil)
return serializer.NewError(serializer.CodeNotFound, "share not found", err)
}
// 对象是否存在
exist := true
if service.IsDir {
folder, err := model.GetFoldersByIDs([]uint{sourceID}, user.ID)
if err != nil || len(folder) == 0 {
exist = false
} else {
sourceName = folder[0].Name
}
} else {
file, err := model.GetFilesByIDs([]uint{sourceID}, user.ID)
if err != nil || len(file) == 0 {
exist = false
} else {
sourceName = file[0].Name
}
}
if !exist {
return serializer.Err(serializer.CodeNotFound, "", nil)
}
newShare := model.Share{
Password: service.Password,
IsDir: service.IsDir,
UserID: user.ID,
SourceID: sourceID,
RemainDownloads: -1,
PreviewEnabled: service.Preview,
SourceName: sourceName,
}
// 如果开启了自动过期
if service.RemainDownloads > 0 {
expires := time.Now().Add(time.Duration(service.Expire) * time.Second)
newShare.RemainDownloads = service.RemainDownloads
newShare.Expires = &expires
}
// 创建分享
id, err := newShare.Create()
if err != nil {
return serializer.DBErr("Failed to create share link record", err)
}
// 获取分享的唯一id
uid := hashid.HashID(id, hashid.ShareID)
// 最终得到分享链接
siteURL := model.GetSiteURL()
sharePath, _ := url.Parse("/s/" + uid)
shareURL := siteURL.ResolveReference(sharePath)
return serializer.Response{
Code: 0,
Data: shareURL.String(),
if err := shareClient.Delete(c, share.ID); err != nil {
return serializer.NewError(serializer.CodeDBError, "Failed to delete share", err)
}
return nil
}