Files
cloudreve/service/share/manage.go
scholar7r 0e19b28e81 feat: implement batch delete share service (#3356)
* feat: implement batch delete service

* refactor: implement `GetByHashIDs` to make sure only query database once

* refactor: use decode instead of `Get` before `Delete`

- fix incorrect `DeleteBatch` method (for admin) calling
- implement DeleteBatchByUserID
2026-03-18 09:23:43 +08:00

127 lines
3.6 KiB
Go

package share
import (
"context"
"fmt"
"time"
"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/hashid"
"github.com/cloudreve/Cloudreve/v4/pkg/serializer"
"github.com/cloudreve/Cloudreve/v4/service/explorer"
"github.com/gin-gonic/gin"
)
type (
// ShareCreateService 创建新分享服务
ShareCreateService struct {
Uri string `json:"uri" binding:"required"`
IsPrivate bool `json:"is_private"`
Password string `json:"password" binding:"omitempty,max=32,alphanum"`
RemainDownloads int `json:"downloads"`
Expire int `json:"expire"`
ShareView bool `json:"share_view"`
ShowReadMe bool `json:"show_readme"`
}
ShareCreateParamCtx struct{}
BatchDeleteShareService struct {
ShareIDs []string `json:"ids" binding:"required"`
}
BatchDeleteParamCtx struct{}
)
func (service *BatchDeleteShareService) Delete(c *gin.Context) error {
dep := dependency.FromContext(c)
uid := inventory.UserIDFromContext(c)
shareClient := dep.ShareClient()
var ids []int
for _, v := range service.ShareIDs {
id, err := dep.HashIDEncoder().Decode(v, hashid.ShareID)
if err != nil {
return fmt.Errorf("failed to decode hash id %q: %w", v, err)
}
ids = append(ids, id)
}
if err := shareClient.DeleteBatchByUserID(c, uid, ids); err != nil {
return serializer.NewError(serializer.CodeDBError, "Failed to delete shares", err)
}
return nil
}
// 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,
Password: service.Password,
RemainDownloads: service.RemainDownloads,
Expire: expires,
ExistedShareID: existed,
ShareView: service.ShareView,
ShowReadMe: service.ShowReadMe,
})
if err != nil {
return "", err
}
base := dep.SettingProvider().SiteURL(c)
return explorer.BuildShareLink(share, dep.HashIDEncoder(), base, true), nil
}
func DeleteShare(c *gin.Context, shareId int) error {
dep := dependency.FromContext(c)
user := inventory.UserFromContext(c)
shareClient := dep.ShareClient()
ctx := context.WithValue(c, inventory.LoadShareFile{}, true)
var (
share *ent.Share
err error
)
if user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionIsAdmin)) {
share, err = shareClient.GetByID(ctx, shareId)
} else {
share, err = shareClient.GetByIDUser(ctx, shareId, user.ID)
}
if err != nil {
return serializer.NewError(serializer.CodeNotFound, "share not found", err)
}
if err := shareClient.Delete(c, share.ID); err != nil {
return serializer.NewError(serializer.CodeDBError, "Failed to delete share", err)
}
return nil
}