mirror of https://github.com/cloudreve/Cloudreve
fix compile errors to support group array in user edge
parent
0b9822ecd4
commit
ca080fc758
|
@ -3,6 +3,7 @@ package migrator
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudreve/Cloudreve/v4/application/migrator/model"
|
||||
"github.com/cloudreve/Cloudreve/v4/ent/user"
|
||||
"github.com/cloudreve/Cloudreve/v4/inventory/types"
|
||||
|
@ -71,7 +72,7 @@ func (m *Migrator) migrateUser() error {
|
|||
SetNick(u.Nick).
|
||||
SetStatus(userStatus).
|
||||
SetStorage(int64(u.Storage)).
|
||||
SetGroupID(int(u.GroupID)).
|
||||
AddGroupIDs(int(u.GroupID)).
|
||||
SetSettings(setting).
|
||||
SetPassword(u.Password)
|
||||
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
package ent
|
||||
|
||||
import (
|
||||
"github.com/cloudreve/Cloudreve/v4/inventory/types"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func (u *User) AnyGroup(predict func(*Group) bool) bool {
|
||||
return !lo.NoneBy(u.Edges.Group, predict)
|
||||
}
|
||||
|
||||
func (u *User) EnforceGroupPermission(perm types.GroupPermission) bool {
|
||||
return !lo.NoneBy(u.Edges.Group, func(item *Group) bool {
|
||||
return item.Permissions.Enabled(int(perm))
|
||||
})
|
||||
}
|
||||
|
||||
func (u *User) GroupMaxStorage() int64 {
|
||||
return lo.MaxBy(u.Edges.Group, func(a *Group, b *Group) bool {
|
||||
return a.MaxStorage > b.MaxStorage
|
||||
}).MaxStorage
|
||||
}
|
||||
|
||||
func (u *User) GroupMaxWalkedFiles() int {
|
||||
return max(lo.MaxBy(u.Edges.Group, func(a *Group, b *Group) bool {
|
||||
return a.Settings.MaxWalkedFiles > b.Settings.MaxWalkedFiles
|
||||
}).Settings.MaxWalkedFiles, 1)
|
||||
}
|
||||
|
||||
func (u *User) GroupMaxTrashRetention() int {
|
||||
return lo.MaxBy(u.Edges.Group, func(a *Group, b *Group) bool {
|
||||
return a.Settings.TrashRetention > b.Settings.TrashRetention
|
||||
}).Settings.TrashRetention
|
||||
}
|
||||
|
||||
func (u *User) GroupMaxDecompressSize() int64 {
|
||||
return lo.MaxBy(u.Edges.Group, func(a *Group, b *Group) bool {
|
||||
return a.Settings.DecompressSize > b.Settings.DecompressSize
|
||||
}).Settings.DecompressSize
|
||||
}
|
||||
|
||||
func (u *User) GroupMaxCompressSize() int64 {
|
||||
return lo.MaxBy(u.Edges.Group, func(a *Group, b *Group) bool {
|
||||
return a.Settings.CompressSize > b.Settings.CompressSize
|
||||
}).Settings.CompressSize
|
||||
}
|
||||
|
||||
func (u *User) GroupMaxSpeedLimit() int {
|
||||
return lo.MaxBy(u.Edges.Group, func(a *Group, b *Group) bool {
|
||||
return a.SpeedLimit > b.SpeedLimit
|
||||
}).SpeedLimit
|
||||
}
|
||||
|
||||
func (u *User) GroupMaxSourceBatchSize() int {
|
||||
return lo.MaxBy(u.Edges.Group, func(a *Group, b *Group) bool {
|
||||
return a.Settings.SourceBatchSize > b.Settings.SourceBatchSize
|
||||
}).Settings.SourceBatchSize
|
||||
}
|
||||
|
||||
func (u *User) GroupMaxAria2BatchSize() int {
|
||||
return lo.MaxBy(u.Edges.Group, func(a *Group, b *Group) bool {
|
||||
return a.Settings.Aria2BatchSize > b.Settings.Aria2BatchSize
|
||||
}).Settings.Aria2BatchSize
|
||||
}
|
||||
|
||||
func (u *User) GetPrimaryGroup() *Group {
|
||||
// TODO: design user primary group
|
||||
panic("implement me")
|
||||
}
|
2
go.mod
2
go.mod
|
@ -46,7 +46,7 @@ require (
|
|||
github.com/qiniu/go-sdk/v7 v7.19.0
|
||||
github.com/rafaeljusto/redigomock v0.0.0-20191117212112-00b2509252a1
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/samber/lo v1.38.1
|
||||
github.com/samber/lo v1.51.0
|
||||
github.com/speps/go-hashids v2.0.0+incompatible
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
|
|
4
go.sum
4
go.sum
|
@ -864,8 +864,8 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
|||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc=
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||
github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI=
|
||||
github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/cloudreve/Cloudreve/v4/ent"
|
||||
"github.com/cloudreve/Cloudreve/v4/ent/davaccount"
|
||||
"github.com/cloudreve/Cloudreve/v4/ent/file"
|
||||
"github.com/cloudreve/Cloudreve/v4/ent/group"
|
||||
"github.com/cloudreve/Cloudreve/v4/ent/passkey"
|
||||
"github.com/cloudreve/Cloudreve/v4/ent/schema"
|
||||
"github.com/cloudreve/Cloudreve/v4/ent/task"
|
||||
|
@ -309,7 +310,7 @@ func (c *userClient) Create(ctx context.Context, args *NewUserArgs) (*ent.User,
|
|||
SetEmail(args.Email).
|
||||
SetNick(nick).
|
||||
SetStatus(args.Status).
|
||||
SetGroupID(args.GroupID).
|
||||
AddGroupIDs(args.GroupID).
|
||||
SetAvatar(args.Avatar)
|
||||
|
||||
if args.PlainPassword != "" {
|
||||
|
@ -334,7 +335,7 @@ func (c *userClient) Create(ctx context.Context, args *NewUserArgs) (*ent.User,
|
|||
|
||||
if newUser.ID == 1 {
|
||||
// For the first user registered, elevate it to admin group.
|
||||
if _, err := newUser.Update().SetGroupID(1).Save(ctx); err != nil {
|
||||
if _, err := newUser.Update().AddGroupIDs(1).Save(ctx); err != nil {
|
||||
return newUser, fmt.Errorf("failed to elevate user to admin: %w", err)
|
||||
}
|
||||
}
|
||||
|
@ -434,14 +435,14 @@ func (c *userClient) AnonymousUser(ctx context.Context) (*ent.User, error) {
|
|||
anonymous := &ent.User{
|
||||
Settings: &types.UserSetting{},
|
||||
}
|
||||
anonymous.SetGroup(anonymousGroup)
|
||||
anonymous.SetGroup([]*ent.Group{anonymousGroup})
|
||||
return anonymous, nil
|
||||
}
|
||||
|
||||
func (c *userClient) ListUsers(ctx context.Context, args *ListUserParameters) (*ListUserResult, error) {
|
||||
query := c.client.User.Query()
|
||||
if args.GroupID != 0 {
|
||||
query = query.Where(user.GroupUsers(args.GroupID))
|
||||
query = query.Where(user.HasGroupWith(group.ID(args.GroupID)))
|
||||
}
|
||||
if args.Status != "" {
|
||||
query = query.Where(user.StatusEQ(args.Status))
|
||||
|
@ -482,7 +483,7 @@ func (c *userClient) Upsert(ctx context.Context, u *ent.User, password, twoFa st
|
|||
SetNick(u.Nick).
|
||||
SetAvatar(u.Avatar).
|
||||
SetStatus(u.Status).
|
||||
SetGroupID(u.GroupUsers).
|
||||
AddGroup(u.Edges.Group...).
|
||||
SetPassword(u.Password).
|
||||
SetSettings(&types.UserSetting{})
|
||||
|
||||
|
@ -502,7 +503,7 @@ func (c *userClient) Upsert(ctx context.Context, u *ent.User, password, twoFa st
|
|||
SetNick(u.Nick).
|
||||
SetAvatar(u.Avatar).
|
||||
SetStatus(u.Status).
|
||||
SetGroupID(u.GroupUsers)
|
||||
AddGroup(u.Edges.Group...)
|
||||
|
||||
if password != "" {
|
||||
pwdDigest, err := digestPassword(password)
|
||||
|
|
|
@ -144,15 +144,7 @@ func WebDAVAuth() gin.HandlerFunc {
|
|||
}
|
||||
|
||||
// 用户组已启用WebDAV?
|
||||
group, err := expectedUser.Edges.GroupOrErr()
|
||||
if err != nil {
|
||||
l.Debug("WebDAVAuth: user group not found: %s", err)
|
||||
c.Status(http.StatusInternalServerError)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if !group.Permissions.Enabled(int(types.GroupPermissionWebDAV)) {
|
||||
if !expectedUser.EnforceGroupPermission(types.GroupPermissionWebDAV) {
|
||||
c.Status(http.StatusForbidden)
|
||||
l.Debug("WebDAVAuth: user %q does not have WebDAV permission.", expectedUser.Email)
|
||||
c.Abort()
|
||||
|
@ -262,7 +254,7 @@ func OSSCallbackAuth() gin.HandlerFunc {
|
|||
func IsAdmin() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
user := inventory.UserFromContext(c)
|
||||
if !user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionIsAdmin)) {
|
||||
if !user.EnforceGroupPermission(types.GroupPermissionIsAdmin) {
|
||||
c.JSON(200, serializer.ErrWithDetails(c, serializer.CodeNoPermissionErr, "", nil))
|
||||
c.Abort()
|
||||
return
|
||||
|
|
|
@ -229,13 +229,8 @@ func (f *DBFS) Capacity(ctx context.Context, u *ent.User) (*fs.Capacity, error)
|
|||
res = &fs.Capacity{}
|
||||
)
|
||||
|
||||
requesterGroup, err := u.Edges.GroupOrErr()
|
||||
if err != nil {
|
||||
return nil, serializer.NewError(serializer.CodeDBError, "Failed to get user's group", err)
|
||||
}
|
||||
|
||||
res.Used = f.user.Storage
|
||||
res.Total = requesterGroup.MaxStorage
|
||||
res.Total = f.user.GroupMaxStorage()
|
||||
return res, nil
|
||||
}
|
||||
|
||||
|
@ -426,7 +421,7 @@ func (f *DBFS) Get(ctx context.Context, path *fs.URI, opts ...fs.Option) (fs.Fil
|
|||
}
|
||||
|
||||
target.FileExtendedInfo = extendedInfo
|
||||
if target.OwnerID() == f.user.ID || f.user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionIsAdmin)) {
|
||||
if target.OwnerID() == f.user.ID || f.user.EnforceGroupPermission(types.GroupPermissionIsAdmin) {
|
||||
target.FileExtendedInfo.Shares = target.Model.Edges.Shares
|
||||
if target.Model.Props != nil {
|
||||
target.FileExtendedInfo.View = target.Model.Props.View
|
||||
|
@ -463,7 +458,7 @@ func (f *DBFS) Get(ctx context.Context, path *fs.URI, opts ...fs.Option) (fs.Fil
|
|||
if f.user.Edges.Group == nil {
|
||||
return nil, fmt.Errorf("user group not loaded")
|
||||
}
|
||||
limit := max(f.user.Edges.Group.Settings.MaxWalkedFiles, 1)
|
||||
limit := f.user.GroupMaxWalkedFiles()
|
||||
|
||||
// disable load metadata to speed up
|
||||
ctxWalk := context.WithValue(ctx, inventory.LoadFilePublicMetadata{}, false)
|
||||
|
@ -552,7 +547,7 @@ func (f *DBFS) Walk(ctx context.Context, path *fs.URI, depth int, walk fs.WalkFu
|
|||
if f.user.Edges.Group == nil {
|
||||
return fmt.Errorf("user group not loaded")
|
||||
}
|
||||
limit := max(f.user.Edges.Group.Settings.MaxWalkedFiles, 1)
|
||||
limit := f.user.GroupMaxWalkedFiles()
|
||||
|
||||
if err := navigator.Walk(ctx, []*File{target}, limit, depth, func(files []*File, l int) error {
|
||||
for _, file := range files {
|
||||
|
@ -647,7 +642,7 @@ func (f *DBFS) createFile(ctx context.Context, parent *File, name string, fileTy
|
|||
|
||||
// getPreferredPolicy tries to get the preferred storage policy for the given file.
|
||||
func (f *DBFS) getPreferredPolicy(ctx context.Context, file *File) (*ent.StoragePolicy, error) {
|
||||
ownerGroup := file.Owner().Edges.Group
|
||||
ownerGroup := file.Owner().GetPrimaryGroup()
|
||||
if ownerGroup == nil {
|
||||
return nil, fmt.Errorf("owner group not loaded")
|
||||
}
|
||||
|
|
|
@ -290,7 +290,7 @@ func (f *DBFS) SoftDelete(ctx context.Context, path ...*fs.URI) error {
|
|||
if err := fc.UpsertMetadata(ctx, target.Model, map[string]string{
|
||||
MetadataRestoreUri: target.Uri(true).String(),
|
||||
MetadataExpectedCollectTime: strconv.FormatInt(
|
||||
time.Now().Add(time.Duration(target.Owner().Edges.Group.Settings.TrashRetention)*time.Second).Unix(),
|
||||
time.Now().Add(time.Duration(target.Owner().GroupMaxTrashRetention())*time.Second).Unix(),
|
||||
10),
|
||||
}, nil); err != nil {
|
||||
_ = inventory.Rollback(tx)
|
||||
|
@ -665,7 +665,7 @@ func (f *DBFS) TraverseFile(ctx context.Context, fileID int) (fs.File, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if fileModel.OwnerID != f.user.ID && !f.user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionIsAdmin)) {
|
||||
if fileModel.OwnerID != f.user.ID && !f.user.EnforceGroupPermission(types.GroupPermissionIsAdmin) {
|
||||
return nil, fs.ErrOwnerOnly.WithError(fmt.Errorf("only file owner can traverse file's uri"))
|
||||
}
|
||||
|
||||
|
@ -800,7 +800,7 @@ func (f *DBFS) copyFiles(ctx context.Context, targets map[Navigator][]*File, des
|
|||
if f.user.Edges.Group == nil {
|
||||
return nil, nil, fmt.Errorf("user group not loaded")
|
||||
}
|
||||
limit := max(f.user.Edges.Group.Settings.MaxWalkedFiles, 1)
|
||||
limit := f.user.GroupMaxWalkedFiles()
|
||||
capacity, err := f.Capacity(ctx, destination.Owner())
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("copy files: failed to destination owner capacity: %w", err)
|
||||
|
|
|
@ -3,6 +3,7 @@ package dbfs
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudreve/Cloudreve/v4/inventory/types"
|
||||
|
||||
"github.com/cloudreve/Cloudreve/v4/ent"
|
||||
|
@ -92,7 +93,7 @@ func (n *myNavigator) To(ctx context.Context, path *fs.URI) (*File, error) {
|
|||
return nil, fs.ErrPathNotExist.WithError(fmt.Errorf("user not found: %w", err))
|
||||
}
|
||||
|
||||
if targetUser.Status != user.StatusActive && !n.user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionIsAdmin)) {
|
||||
if targetUser.Status != user.StatusActive && !n.user.EnforceGroupPermission(types.GroupPermissionIsAdmin) {
|
||||
return nil, fs.ErrPathNotExist.WithError(fmt.Errorf("inactive user"))
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ func (f *DBFS) PatchProps(ctx context.Context, uri *fs.URI, props *types.FilePro
|
|||
return fmt.Errorf("failed to get target file: %w", err)
|
||||
}
|
||||
|
||||
if target.OwnerID() != f.user.ID && !f.user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionIsAdmin)) {
|
||||
if target.OwnerID() != f.user.ID && !f.user.EnforceGroupPermission(types.GroupPermissionIsAdmin) {
|
||||
return fs.ErrOwnerOnly.WithError(fmt.Errorf("only file owner can modify file props"))
|
||||
}
|
||||
|
||||
|
|
|
@ -156,7 +156,7 @@ func (n *shareNavigator) Root(ctx context.Context, path *fs.URI) (*File, error)
|
|||
return nil, ErrShareNotFound
|
||||
}
|
||||
|
||||
if n.user.ID != n.owner.ID && !n.user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionShareDownload)) {
|
||||
if n.user.ID != n.owner.ID && !n.user.EnforceGroupPermission(types.GroupPermissionShareDownload) {
|
||||
if inventory.IsAnonymousUser(n.user) {
|
||||
return nil, serializer.NewError(
|
||||
serializer.CodeAnonymouseAccessDenied,
|
||||
|
|
|
@ -95,8 +95,8 @@ func (m *manager) ListArchiveFiles(ctx context.Context, uri *fs.URI, entity, zip
|
|||
}
|
||||
|
||||
// Validate file size
|
||||
if m.user.Edges.Group.Settings.DecompressSize > 0 && file.Size() > m.user.Edges.Group.Settings.DecompressSize {
|
||||
return nil, fs.ErrFileSizeTooBig.WithError(fmt.Errorf("file size %d exceeds the limit %d", file.Size(), m.user.Edges.Group.Settings.DecompressSize))
|
||||
if m.user.GroupMaxDecompressSize() > 0 && file.Size() > m.user.GroupMaxDecompressSize() {
|
||||
return nil, fs.ErrFileSizeTooBig.WithError(fmt.Errorf("file size %d exceeds the limit %d", file.Size(), m.user.GroupMaxDecompressSize()))
|
||||
}
|
||||
|
||||
found, targetEntity := fs.FindDesiredEntity(file, entity, m.hasher, nil)
|
||||
|
|
|
@ -61,7 +61,7 @@ type (
|
|||
func (m *manager) GetDirectLink(ctx context.Context, urls ...*fs.URI) ([]DirectLink, error) {
|
||||
ae := serializer.NewAggregateError()
|
||||
res := make([]DirectLink, 0, len(urls))
|
||||
useRedirect := m.user.Edges.Group.Settings.RedirectedSource
|
||||
useRedirect := m.user.GetPrimaryGroup().Settings.RedirectedSource
|
||||
fileClient := m.dep.FileClient()
|
||||
siteUrl := m.settings.SiteURL(ctx)
|
||||
|
||||
|
@ -76,7 +76,7 @@ func (m *manager) GetDirectLink(ctx context.Context, urls ...*fs.URI) ([]DirectL
|
|||
continue
|
||||
}
|
||||
|
||||
if file.OwnerID() != m.user.ID && !m.user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionIsAdmin)) {
|
||||
if file.OwnerID() != m.user.ID && !m.user.EnforceGroupPermission(types.GroupPermissionIsAdmin) {
|
||||
ae.Add(url.String(), fs.ErrOwnerOnly)
|
||||
continue
|
||||
}
|
||||
|
@ -98,9 +98,9 @@ func (m *manager) GetDirectLink(ctx context.Context, urls ...*fs.URI) ([]DirectL
|
|||
}
|
||||
|
||||
if useRedirect {
|
||||
reuseExisting := !m.user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionUniqueRedirectDirectLink))
|
||||
reuseExisting := !m.user.EnforceGroupPermission(types.GroupPermissionUniqueRedirectDirectLink)
|
||||
// Use redirect source
|
||||
link, err := fileClient.CreateDirectLink(ctx, file.ID(), file.Name(), m.user.Edges.Group.SpeedLimit, reuseExisting)
|
||||
link, err := fileClient.CreateDirectLink(ctx, file.ID(), file.Name(), m.user.GroupMaxSpeedLimit(), reuseExisting)
|
||||
if err != nil {
|
||||
ae.Add(url.String(), err)
|
||||
continue
|
||||
|
@ -122,7 +122,7 @@ func (m *manager) GetDirectLink(ctx context.Context, urls ...*fs.URI) ([]DirectL
|
|||
source := entitysource.NewEntitySource(target, d, policy, m.auth, m.settings, m.hasher, m.dep.RequestClient(),
|
||||
m.l, m.config, m.dep.MimeDetector(ctx))
|
||||
sourceUrl, err := source.Url(ctx,
|
||||
entitysource.WithSpeedLimit(int64(m.user.Edges.Group.SpeedLimit)),
|
||||
entitysource.WithSpeedLimit(int64(m.user.GroupMaxSpeedLimit())),
|
||||
entitysource.WithDisplayName(file.Name()),
|
||||
)
|
||||
if err != nil {
|
||||
|
|
|
@ -233,7 +233,7 @@ func (m *CreateArchiveTask) listEntitiesAndSendToSlave(ctx context.Context, dep
|
|||
}
|
||||
}
|
||||
}),
|
||||
fs.WithMaxArchiveSize(user.Edges.Group.Settings.CompressSize),
|
||||
fs.WithMaxArchiveSize(user.GroupMaxCompressSize()),
|
||||
)
|
||||
if err != nil {
|
||||
return task.StatusError, fmt.Errorf("failed to compress files: %w", err)
|
||||
|
@ -390,7 +390,7 @@ func (m *CreateArchiveTask) createArchiveFile(ctx context.Context, dep dependenc
|
|||
m.Unlock()
|
||||
failed, err := fm.CreateArchive(ctx, uris, zipFile,
|
||||
fs.WithArchiveCompression(true),
|
||||
fs.WithMaxArchiveSize(user.Edges.Group.Settings.CompressSize),
|
||||
fs.WithMaxArchiveSize(user.GroupMaxCompressSize()),
|
||||
fs.WithProgressFunc(func(current, diff int64, total int64) {
|
||||
atomic.AddInt64(&m.progress[ProgressTypeArchiveSize].Current, diff)
|
||||
atomic.AddInt64(&m.progress[ProgressTypeArchiveCount].Current, 1)
|
||||
|
|
|
@ -182,9 +182,9 @@ func (m *ExtractArchiveTask) createSlaveExtractTask(ctx context.Context, dep dep
|
|||
}
|
||||
|
||||
// Validate file size
|
||||
if user.Edges.Group.Settings.DecompressSize > 0 && archiveFile.Size() > user.Edges.Group.Settings.DecompressSize {
|
||||
if user.GroupMaxDecompressSize() > 0 && archiveFile.Size() > user.GroupMaxDecompressSize() {
|
||||
return task.StatusError,
|
||||
fmt.Errorf("file size %d exceeds the limit %d (%w)", archiveFile.Size(), user.Edges.Group.Settings.DecompressSize, queue.CriticalErr)
|
||||
fmt.Errorf("file size %d exceeds the limit %d (%w)", archiveFile.Size(), user.GroupMaxDecompressSize(), queue.CriticalErr)
|
||||
}
|
||||
|
||||
// Create slave task
|
||||
|
@ -269,9 +269,9 @@ func (m *ExtractArchiveTask) masterExtractArchive(ctx context.Context, dep depen
|
|||
}
|
||||
|
||||
// Validate file size
|
||||
if user.Edges.Group.Settings.DecompressSize > 0 && archiveFile.Size() > user.Edges.Group.Settings.DecompressSize {
|
||||
if user.GroupMaxDecompressSize() > 0 && archiveFile.Size() > user.GroupMaxDecompressSize() {
|
||||
return task.StatusError,
|
||||
fmt.Errorf("file size %d exceeds the limit %d (%w)", archiveFile.Size(), user.Edges.Group.Settings.DecompressSize, queue.CriticalErr)
|
||||
fmt.Errorf("file size %d exceeds the limit %d (%w)", archiveFile.Size(), user.GroupMaxDecompressSize(), queue.CriticalErr)
|
||||
}
|
||||
|
||||
es, err := fm.GetEntitySource(ctx, 0, fs.WithEntity(archiveFile.PrimaryEntity()))
|
||||
|
|
|
@ -199,7 +199,7 @@ func (m *RemoteDownloadTask) createDownloadTask(ctx context.Context, dep depende
|
|||
}
|
||||
|
||||
// Create download task
|
||||
handle, err := m.d.CreateTask(ctx, torrentUrl, user.Edges.Group.Settings.RemoteDownloadOptions)
|
||||
handle, err := m.d.CreateTask(ctx, torrentUrl, user.GetPrimaryGroup().Settings.RemoteDownloadOptions)
|
||||
if err != nil {
|
||||
return task.StatusError, fmt.Errorf("failed to create download task: %w", err)
|
||||
}
|
||||
|
|
|
@ -347,10 +347,10 @@ func handleGetHeadPost(c *gin.Context, user *ent.User, fm manager.FileManager) (
|
|||
|
||||
defer es.Close()
|
||||
|
||||
es.Apply(entitysource.WithSpeedLimit(int64(user.Edges.Group.SpeedLimit)))
|
||||
es.Apply(entitysource.WithSpeedLimit(int64(user.GroupMaxSpeedLimit())))
|
||||
if es.ShouldInternalProxy() ||
|
||||
(user.Edges.DavAccounts[0].Options.Enabled(int(types.DavAccountProxy)) &&
|
||||
user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionWebDAVProxy))) {
|
||||
user.EnforceGroupPermission(types.GroupPermissionWebDAVProxy)) {
|
||||
es.Serve(c.Writer, c.Request)
|
||||
} else {
|
||||
settings := dependency.FromContext(c).SettingProvider()
|
||||
|
|
|
@ -2,7 +2,9 @@ package admin
|
|||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"strconv"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/cloudreve/Cloudreve/v4/application/dependency"
|
||||
"github.com/cloudreve/Cloudreve/v4/ent"
|
||||
|
@ -154,8 +156,10 @@ func (s *UpsertUserService) Update(c *gin.Context) (*GetUserResponse, error) {
|
|||
return nil, serializer.NewError(serializer.CodeDBError, "Failed to get user", err)
|
||||
}
|
||||
|
||||
if s.User.ID == 1 && existing.Edges.Group.Permissions.Enabled(int(types.GroupPermissionIsAdmin)) {
|
||||
if s.User.GroupUsers != existing.GroupUsers {
|
||||
if s.User.ID == 1 && existing.EnforceGroupPermission(types.GroupPermissionIsAdmin) {
|
||||
if !slices.EqualFunc(s.User.Edges.Group, existing.Edges.Group, func(a *ent.Group, b *ent.Group) bool {
|
||||
return a.ID == b.ID
|
||||
}) {
|
||||
return nil, serializer.NewError(serializer.CodeInvalidActionOnDefaultUser, "Cannot change default user's group", nil)
|
||||
}
|
||||
|
||||
|
@ -165,7 +169,7 @@ func (s *UpsertUserService) Update(c *gin.Context) (*GetUserResponse, error) {
|
|||
|
||||
}
|
||||
|
||||
if s.Password != "" && len(s.Password) > 128 {
|
||||
if s.Password != "" && utf8.RuneCountInString(s.Password) > 128 {
|
||||
return nil, serializer.NewError(serializer.CodeParamErr, "Password too long", nil)
|
||||
}
|
||||
|
||||
|
|
|
@ -100,11 +100,11 @@ func (s *GetDirectLinkService) Get(c *gin.Context) ([]DirectLinkResponse, error)
|
|||
dep := dependency.FromContext(c)
|
||||
u := inventory.UserFromContext(c)
|
||||
|
||||
if u.Edges.Group.Settings.SourceBatchSize == 0 {
|
||||
if u.GroupMaxSourceBatchSize() == 0 {
|
||||
return nil, serializer.NewError(serializer.CodeGroupNotAllowed, "", nil)
|
||||
}
|
||||
|
||||
if len(s.Uris) > u.Edges.Group.Settings.SourceBatchSize {
|
||||
if len(s.Uris) > u.GroupMaxSourceBatchSize() {
|
||||
return nil, serializer.NewError(serializer.CodeBatchSourceSize, "", nil)
|
||||
}
|
||||
|
||||
|
@ -394,7 +394,7 @@ func (s *FileURLService) GetArchiveDownloadSession(c *gin.Context) (*FileURLResp
|
|||
return nil, serializer.NewError(serializer.CodeParamErr, "unknown uri", err)
|
||||
}
|
||||
|
||||
if !user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionArchiveDownload)) {
|
||||
if !user.EnforceGroupPermission(types.GroupPermissionArchiveDownload) {
|
||||
return nil, serializer.NewError(serializer.CodeGroupNotAllowed, "", nil)
|
||||
}
|
||||
|
||||
|
@ -454,7 +454,7 @@ func (s *FileURLService) Get(c *gin.Context) (*FileURLResponse, error) {
|
|||
}
|
||||
|
||||
res, earliestExpire, err := m.GetEntityUrls(ctx, urlReq,
|
||||
fs.WithDownloadSpeed(int64(user.Edges.Group.SpeedLimit)),
|
||||
fs.WithDownloadSpeed(int64(user.GroupMaxSpeedLimit())),
|
||||
fs.WithIsDownload(s.Download),
|
||||
fs.WithNoCache(s.NoCache),
|
||||
fs.WithUrlExpire(&expire),
|
||||
|
@ -547,7 +547,7 @@ func (s *DeleteFileService) Delete(c *gin.Context) error {
|
|||
return serializer.NewError(serializer.CodeParamErr, "unknown uri", err)
|
||||
}
|
||||
|
||||
if s.UnlinkOnly && !user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionAdvanceDelete)) {
|
||||
if s.UnlinkOnly && !user.EnforceGroupPermission(types.GroupPermissionAdvanceDelete) {
|
||||
return serializer.NewError(serializer.CodeNoPermissionErr, "advance delete permission is required", nil)
|
||||
}
|
||||
|
||||
|
@ -731,7 +731,7 @@ func (s *ArchiveListFilesService) List(c *gin.Context) (*ArchiveListFilesRespons
|
|||
user := inventory.UserFromContext(c)
|
||||
m := manager.NewFileManager(dep, user)
|
||||
defer m.Recycle()
|
||||
if !user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionArchiveTask)) {
|
||||
if !user.EnforceGroupPermission(types.GroupPermissionArchiveTask) {
|
||||
return nil, serializer.NewError(serializer.CodeGroupNotAllowed, "Group not allowed to extract archive files", nil)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,10 @@ package explorer
|
|||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/hashid"
|
||||
"time"
|
||||
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/hashid"
|
||||
|
||||
"github.com/cloudreve/Cloudreve/v4/application/dependency"
|
||||
"github.com/cloudreve/Cloudreve/v4/ent"
|
||||
"github.com/cloudreve/Cloudreve/v4/ent/task"
|
||||
|
@ -85,7 +86,7 @@ func (service *DownloadWorkflowService) CreateDownloadTask(c *gin.Context) ([]*T
|
|||
m := manager.NewFileManager(dep, user)
|
||||
defer m.Recycle()
|
||||
|
||||
if !user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionRemoteDownload)) {
|
||||
if !user.EnforceGroupPermission(types.GroupPermissionRemoteDownload) {
|
||||
return nil, serializer.NewError(serializer.CodeGroupNotAllowed, "Group not allowed to download files", nil)
|
||||
}
|
||||
|
||||
|
@ -111,7 +112,7 @@ func (service *DownloadWorkflowService) CreateDownloadTask(c *gin.Context) ([]*T
|
|||
}
|
||||
|
||||
// 检查批量任务数量
|
||||
limit := user.Edges.Group.Settings.Aria2BatchSize
|
||||
limit := user.GroupMaxAria2BatchSize()
|
||||
if limit > 0 && len(service.Src) > limit {
|
||||
return nil, serializer.NewError(serializer.CodeBatchAria2Size, "", nil)
|
||||
}
|
||||
|
@ -186,7 +187,7 @@ func (service *ArchiveWorkflowService) CreateExtractTask(c *gin.Context) (*TaskR
|
|||
m := manager.NewFileManager(dep, user)
|
||||
defer m.Recycle()
|
||||
|
||||
if !user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionArchiveTask)) {
|
||||
if !user.EnforceGroupPermission(types.GroupPermissionArchiveTask) {
|
||||
return nil, serializer.NewError(serializer.CodeGroupNotAllowed, "Group not allowed to compress files", nil)
|
||||
}
|
||||
|
||||
|
@ -225,7 +226,7 @@ func (service *ArchiveWorkflowService) CreateCompressTask(c *gin.Context) (*Task
|
|||
m := manager.NewFileManager(dep, user)
|
||||
defer m.Recycle()
|
||||
|
||||
if !user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionArchiveTask)) {
|
||||
if !user.EnforceGroupPermission(types.GroupPermissionArchiveTask) {
|
||||
return nil, serializer.NewError(serializer.CodeGroupNotAllowed, "Group not allowed to compress files", nil)
|
||||
}
|
||||
|
||||
|
@ -280,7 +281,7 @@ func (service *ImportWorkflowService) CreateImportTask(c *gin.Context) (*TaskRes
|
|||
m := manager.NewFileManager(dep, user)
|
||||
defer m.Recycle()
|
||||
|
||||
if !user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionIsAdmin)) {
|
||||
if !user.EnforceGroupPermission(types.GroupPermissionIsAdmin) {
|
||||
return nil, serializer.NewError(serializer.CodeGroupNotAllowed, "Only admin can import files", nil)
|
||||
}
|
||||
|
||||
|
@ -388,7 +389,7 @@ func TaskPhaseProgress(c *gin.Context, taskID int) (queue.Progresses, error) {
|
|||
u := inventory.UserFromContext(c)
|
||||
r := dep.TaskRegistry()
|
||||
t, found := r.Get(taskID)
|
||||
if !found || (t.Owner().ID != u.ID && !u.Edges.Group.Permissions.Enabled(int(types.GroupPermissionIsAdmin))) {
|
||||
if !found || (t.Owner().ID != u.ID && !u.EnforceGroupPermission(types.GroupPermissionIsAdmin)) {
|
||||
return queue.Progresses{}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@ func (service *CreateDavAccountService) Update(c *gin.Context) (*DavAccount, err
|
|||
}
|
||||
|
||||
func (service *CreateDavAccountService) validateAndGetBs(user *ent.User) (*boolset.BooleanSet, error) {
|
||||
if !user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionWebDAV)) {
|
||||
if !user.EnforceGroupPermission(types.GroupPermissionWebDAV) {
|
||||
return nil, serializer.NewError(serializer.CodeGroupNotAllowed, "WebDAV is not enabled for this user group", nil)
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,7 @@ func (service *CreateDavAccountService) validateAndGetBs(user *ent.User) (*bools
|
|||
boolset.Set(types.DavAccountDisableSysFiles, true, &bs)
|
||||
}
|
||||
|
||||
if service.Proxy && user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionWebDAVProxy)) {
|
||||
if service.Proxy && user.EnforceGroupPermission(types.GroupPermissionWebDAVProxy) {
|
||||
boolset.Set(types.DavAccountProxy, true, &bs)
|
||||
}
|
||||
return &bs, nil
|
||||
|
|
|
@ -37,7 +37,7 @@ func (service *ShareCreateService) Upsert(c *gin.Context, existed int) (string,
|
|||
defer m.Recycle()
|
||||
|
||||
// Check group permission for creating share link
|
||||
if !user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionShare)) {
|
||||
if !user.EnforceGroupPermission(types.GroupPermissionShare) {
|
||||
return "", serializer.NewError(serializer.CodeGroupNotAllowed, "Group permission denied", nil)
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ func DeleteShare(c *gin.Context, shareId int) error {
|
|||
share *ent.Share
|
||||
err error
|
||||
)
|
||||
if user.Edges.Group.Permissions.Enabled(int(types.GroupPermissionIsAdmin)) {
|
||||
if user.EnforceGroupPermission(types.GroupPermissionIsAdmin) {
|
||||
share, err = shareClient.GetByID(ctx, shareId)
|
||||
} else {
|
||||
share, err = shareClient.GetByIDUser(ctx, shareId, user.ID)
|
||||
|
|
|
@ -107,7 +107,7 @@ type User struct {
|
|||
CreatedAt time.Time `json:"created_at"`
|
||||
PreferredTheme string `json:"preferred_theme,omitempty"`
|
||||
Anonymous bool `json:"anonymous,omitempty"`
|
||||
Group *Group `json:"group,omitempty"`
|
||||
Groups []*Group `json:"groups,omitempty"`
|
||||
Pined []types.PinedFile `json:"pined,omitempty"`
|
||||
Language string `json:"language,omitempty"`
|
||||
DisableViewSync bool `json:"disable_view_sync,omitempty"`
|
||||
|
@ -156,15 +156,17 @@ func BuildWebAuthnList(credentials []webauthn.Credential) []WebAuthnCredentials
|
|||
// BuildUser 序列化用户
|
||||
func BuildUser(user *ent.User, idEncoder hashid.Encoder) User {
|
||||
return User{
|
||||
ID: hashid.EncodeUserID(idEncoder, user.ID),
|
||||
Email: user.Email,
|
||||
Nickname: user.Nick,
|
||||
Status: user.Status,
|
||||
Avatar: user.Avatar,
|
||||
CreatedAt: user.CreatedAt,
|
||||
PreferredTheme: user.Settings.PreferredTheme,
|
||||
Anonymous: user.ID == 0,
|
||||
Group: BuildGroup(user.Edges.Group, idEncoder),
|
||||
ID: hashid.EncodeUserID(idEncoder, user.ID),
|
||||
Email: user.Email,
|
||||
Nickname: user.Nick,
|
||||
Status: user.Status,
|
||||
Avatar: user.Avatar,
|
||||
CreatedAt: user.CreatedAt,
|
||||
PreferredTheme: user.Settings.PreferredTheme,
|
||||
Anonymous: user.ID == 0,
|
||||
Groups: lo.Map(user.Edges.Group, func(item *ent.Group, index int) *Group {
|
||||
return BuildGroup(item, idEncoder)
|
||||
}),
|
||||
Pined: user.Settings.Pined,
|
||||
Language: user.Settings.Language,
|
||||
DisableViewSync: user.Settings.DisableViewSync,
|
||||
|
@ -202,10 +204,9 @@ func BuildUserRedacted(u *ent.User, level int, idEncoder hashid.Encoder) User {
|
|||
Avatar: userRaw.Avatar,
|
||||
CreatedAt: userRaw.CreatedAt,
|
||||
ShareLinksInProfile: userRaw.ShareLinksInProfile,
|
||||
}
|
||||
|
||||
if userRaw.Group != nil {
|
||||
user.Group = RedactedGroup(userRaw.Group)
|
||||
Groups: lo.Map(userRaw.Groups, func(item *Group, level int) *Group {
|
||||
return RedactedGroup(item)
|
||||
}),
|
||||
}
|
||||
|
||||
if level == RedactLevelUser {
|
||||
|
|
Loading…
Reference in New Issue