From 0bcfc3332384d8a5cd3686873ef957a3971c7069 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Mon, 7 Mar 2022 12:19:09 +0100 Subject: [PATCH 1/6] add driveAlias --- changelog/unreleased/space-aliases.md | 5 +++ pkg/storage/utils/decomposedfs/spaces.go | 44 +++++++++++++------ .../utils/decomposedfs/xattrs/xattrs.go | 1 + 3 files changed, 36 insertions(+), 14 deletions(-) create mode 100644 changelog/unreleased/space-aliases.md diff --git a/changelog/unreleased/space-aliases.md b/changelog/unreleased/space-aliases.md new file mode 100644 index 0000000000..3e01e0b102 --- /dev/null +++ b/changelog/unreleased/space-aliases.md @@ -0,0 +1,5 @@ +Enhancement: Add space aliases + +Space aliases can be used to resolve spaceIDs in a client. + +https://github.com/cs3org/reva/pull/2623 diff --git a/pkg/storage/utils/decomposedfs/spaces.go b/pkg/storage/utils/decomposedfs/spaces.go index 651c758798..ef928f13d2 100644 --- a/pkg/storage/utils/decomposedfs/spaces.go +++ b/pkg/storage/utils/decomposedfs/spaces.go @@ -62,22 +62,18 @@ func (fs *Decomposedfs) CreateStorageSpace(ctx context.Context, req *provider.Cr // "everything is a resource" this is the unique ID for the Space resource. spaceID := uuid.New().String() // allow sending a space id - if req.Opaque != nil && req.Opaque.Map != nil { - if e, ok := req.Opaque.Map["spaceid"]; ok && e.Decoder == "plain" { - spaceID = string(e.Value) - } + if reqSpaceID := utils.ReadPlainFromOpaque(req.Opaque, "spaceid"); reqSpaceID != "" { + spaceID = reqSpaceID } // allow sending a space description - var description string - if req.Opaque != nil && req.Opaque.Map != nil { - if e, ok := req.Opaque.Map["description"]; ok && e.Decoder == "plain" { - description = string(e.Value) - } - } + description := utils.ReadPlainFromOpaque(req.Opaque, "description") + // allow sending a spaceAlias + alias := utils.ReadPlainFromOpaque(req.Opaque, "spaceAlias") // TODO enforce a uuid? // TODO clarify if we want to enforce a single personal storage space or if we want to allow sending the spaceid if req.Type == spaceTypePersonal { spaceID = req.GetOwner().GetId().GetOpaqueId() + alias = spaceTypePersonal + "/" + req.GetOwner().GetUsername() } root, err := node.ReadNode(ctx, fs.lu, spaceID, spaceID) @@ -129,6 +125,10 @@ func (fs *Decomposedfs) CreateStorageSpace(ctx context.Context, req *provider.Cr metadata[xattrs.SpaceDescriptionAttr] = description } + if alias != "" { + metadata[xattrs.SpaceAliasAttr] = alias + } + if err := xattrs.SetMultiple(root.InternalPath(), metadata); err != nil { return nil, err } @@ -428,6 +428,9 @@ func (fs *Decomposedfs) UpdateStorageSpace(ctx context.Context, req *provider.Up metadata[xattrs.SpaceDescriptionAttr] = string(description.Value) hasDescription = true } + if alias, ok := space.Opaque.Map["spaceAlias"]; ok { + metadata[xattrs.SpaceAliasAttr] = string(alias.Value) + } if image, ok := space.Opaque.Map["image"]; ok { imageID := resourceid.OwnCloudResourceIDUnwrap(string(image.Value)) if imageID == nil { @@ -699,10 +702,16 @@ func (fs *Decomposedfs) storageSpaceFromNode(ctx context.Context, n *node.Node, } spaceImage, ok := spaceAttributes[xattrs.SpaceImageAttr] if ok { - space.Opaque.Map["image"] = &types.OpaqueEntry{ - Decoder: "plain", - Value: []byte(resourceid.OwnCloudResourceIDWrap(&provider.ResourceId{StorageId: space.Root.StorageId, OpaqueId: spaceImage})), - } + space.Opaque = utils.AppendPlainToOpaque( + space.Opaque, + "image", + resourceid.OwnCloudResourceIDWrap( + &provider.ResourceId{ + StorageId: space.Root.StorageId, + OpaqueId: spaceImage, + }, + ), + ) } spaceDescription, ok := spaceAttributes[xattrs.SpaceDescriptionAttr] if ok { @@ -718,6 +727,13 @@ func (fs *Decomposedfs) storageSpaceFromNode(ctx context.Context, n *node.Node, Value: []byte(resourceid.OwnCloudResourceIDWrap(&provider.ResourceId{StorageId: space.Root.StorageId, OpaqueId: spaceReadme})), } } + spaceAlias, ok := spaceAttributes[xattrs.SpaceAliasAttr] + if ok { + space.Opaque.Map["spaceAlias"] = &types.OpaqueEntry{ + Decoder: "plain", + Value: []byte(spaceAlias), + } + } return space, nil } diff --git a/pkg/storage/utils/decomposedfs/xattrs/xattrs.go b/pkg/storage/utils/decomposedfs/xattrs/xattrs.go index 65dd18ad9e..664b9bcb32 100644 --- a/pkg/storage/utils/decomposedfs/xattrs/xattrs.go +++ b/pkg/storage/utils/decomposedfs/xattrs/xattrs.go @@ -96,6 +96,7 @@ const ( SpaceDescriptionAttr string = OcisPrefix + "space.description" SpaceReadmeAttr string = OcisPrefix + "space.readme" SpaceImageAttr string = OcisPrefix + "space.image" + SpaceAliasAttr string = OcisPrefix + "space.alias" UserAcePrefix string = "u:" GroupAcePrefix string = "g:" From 71b6cbbf2dc19110d9c6fc01c4adcf52056e82f0 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Tue, 8 Mar 2022 16:36:02 +0100 Subject: [PATCH 2/6] add unit test --- Makefile | 2 +- .../utils/decomposedfs/recycle_test.go | 10 ++-- pkg/storage/utils/decomposedfs/spaces_test.go | 58 +++++++++++++++++++ .../utils/decomposedfs/testhelpers/helpers.go | 2 +- 4 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 pkg/storage/utils/decomposedfs/spaces_test.go diff --git a/Makefile b/Makefile index 3a59bea137..1de6e3e747 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ build-reva: imports go build -ldflags ${BUILD_FLAGS} -o ./cmd/reva/reva ./cmd/reva test: off - go test -coverprofile coverage.out -race $$(go list ./... | grep -v /tests/integration) + go test -v -coverprofile coverage.out -race $$(go list ./... | grep -v /tests/integration) test-integration: build-ci cd tests/integration && go test -race ./... diff --git a/pkg/storage/utils/decomposedfs/recycle_test.go b/pkg/storage/utils/decomposedfs/recycle_test.go index 6fdcec20e1..f9b4787217 100644 --- a/pkg/storage/utils/decomposedfs/recycle_test.go +++ b/pkg/storage/utils/decomposedfs/recycle_test.go @@ -48,7 +48,7 @@ var _ = Describe("Recycle", func() { BeforeEach(func() { // in this scenario user "u-s-e-r-id" has this permissions: - registerPermissions(env.Permissions, "u-s-e-r-id", &provider.ResourcePermissions{ + registerPermissions(env.Permissions, "25b69780-5f39-43be-a7ac-a9b9e9fe4230", &provider.ResourcePermissions{ InitiateFileUpload: true, Delete: true, ListRecycle: true, @@ -133,7 +133,7 @@ var _ = Describe("Recycle", func() { }) // in this scenario user "u-s-e-r-id" has this permissions: - registerPermissions(env.Permissions, "u-s-e-r-id", &provider.ResourcePermissions{ + registerPermissions(env.Permissions, "25b69780-5f39-43be-a7ac-a9b9e9fe4230", &provider.ResourcePermissions{ InitiateFileUpload: true, Delete: true, ListRecycle: true, @@ -246,7 +246,7 @@ var _ = Describe("Recycle", func() { Expect(projectID).ToNot(BeNil()) // in this scenario user "u-s-e-r-id" has this permissions: - registerPermissions(env.Permissions, "u-s-e-r-id", &provider.ResourcePermissions{ + registerPermissions(env.Permissions, "25b69780-5f39-43be-a7ac-a9b9e9fe4230", &provider.ResourcePermissions{ InitiateFileUpload: true, Delete: true, ListRecycle: true, @@ -318,7 +318,7 @@ var _ = Describe("Recycle", func() { }) // in this scenario user "u-s-e-r-id" has this permissions: - registerPermissions(env.Permissions, "u-s-e-r-id", &provider.ResourcePermissions{ + registerPermissions(env.Permissions, "25b69780-5f39-43be-a7ac-a9b9e9fe4230", &provider.ResourcePermissions{ Delete: true, ListRecycle: true, PurgeRecycle: true, @@ -403,7 +403,7 @@ var _ = Describe("Recycle", func() { }) // in this scenario user "userid" has this permissions: - registerPermissions(env.Permissions, "u-s-e-r-id", &provider.ResourcePermissions{ + registerPermissions(env.Permissions, "25b69780-5f39-43be-a7ac-a9b9e9fe4230", &provider.ResourcePermissions{ Delete: true, ListRecycle: true, PurgeRecycle: true, diff --git a/pkg/storage/utils/decomposedfs/spaces_test.go b/pkg/storage/utils/decomposedfs/spaces_test.go new file mode 100644 index 0000000000..bad47780a0 --- /dev/null +++ b/pkg/storage/utils/decomposedfs/spaces_test.go @@ -0,0 +1,58 @@ +// Copyright 2018-2022 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package decomposedfs_test + +import ( + permissionsv1beta1 "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1" + rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + helpers "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/testhelpers" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/stretchr/testify/mock" +) + +var _ = Describe("Home is Created", func() { + var ( + env *helpers.TestEnv + ) + + BeforeEach(func() { + var err error + env, err = helpers.NewTestEnv() + Expect(err).ToNot(HaveOccurred()) + env.PermissionsClient.On("CheckPermission", mock.Anything, mock.Anything, mock.Anything).Return(&permissionsv1beta1.CheckPermissionResponse{Status: &rpcv1beta1.Status{Code: rpcv1beta1.Code_CODE_OK}}, nil) + }) + + AfterEach(func() { + if env != nil { + env.Cleanup() + } + }) + + Context("during login", func() { + It("space is created", func() { + resp, err := env.Fs.ListStorageSpaces(env.Ctx, nil) + Expect(err).ToNot(HaveOccurred()) + Expect(len(resp)).To(Equal(1)) + Expect(string(resp[0].Opaque.GetMap()["spaceAlias"].Value)).To(Equal("personal/username")) + Expect(resp[0].Name).To(Equal("username")) + Expect(resp[0].SpaceType).To(Equal("personal")) + }) + }) +}) diff --git a/pkg/storage/utils/decomposedfs/testhelpers/helpers.go b/pkg/storage/utils/decomposedfs/testhelpers/helpers.go index 8b2c5fbec2..d441ced685 100644 --- a/pkg/storage/utils/decomposedfs/testhelpers/helpers.go +++ b/pkg/storage/utils/decomposedfs/testhelpers/helpers.go @@ -85,7 +85,7 @@ func NewTestEnv() (*TestEnv, error) { owner := &userpb.User{ Id: &userpb.UserId{ Idp: "idp", - OpaqueId: "u-s-e-r-id", + OpaqueId: "25b69780-5f39-43be-a7ac-a9b9e9fe4230", Type: userpb.UserType_USER_TYPE_PRIMARY, }, Username: "username", From 34d2f49420f9fb63b4cb212d41f42e7bbf398536 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Wed, 9 Mar 2022 00:02:41 +0100 Subject: [PATCH 3/6] code cleanup --- .../utils/decomposedfs/recycle_test.go | 8 +-- pkg/storage/utils/decomposedfs/spaces.go | 49 ++++++------------- 2 files changed, 20 insertions(+), 37 deletions(-) diff --git a/pkg/storage/utils/decomposedfs/recycle_test.go b/pkg/storage/utils/decomposedfs/recycle_test.go index f9b4787217..59a916166b 100644 --- a/pkg/storage/utils/decomposedfs/recycle_test.go +++ b/pkg/storage/utils/decomposedfs/recycle_test.go @@ -47,7 +47,7 @@ var _ = Describe("Recycle", func() { When("a user deletes files from the same space", func() { BeforeEach(func() { - // in this scenario user "u-s-e-r-id" has this permissions: + // in this scenario user "25b69780-5f39-43be-a7ac-a9b9e9fe4230" has this permissions: registerPermissions(env.Permissions, "25b69780-5f39-43be-a7ac-a9b9e9fe4230", &provider.ResourcePermissions{ InitiateFileUpload: true, Delete: true, @@ -132,7 +132,7 @@ var _ = Describe("Recycle", func() { Username: "anotherusername", }) - // in this scenario user "u-s-e-r-id" has this permissions: + // in this scenario user "25b69780-5f39-43be-a7ac-a9b9e9fe4230" has this permissions: registerPermissions(env.Permissions, "25b69780-5f39-43be-a7ac-a9b9e9fe4230", &provider.ResourcePermissions{ InitiateFileUpload: true, Delete: true, @@ -245,7 +245,7 @@ var _ = Describe("Recycle", func() { Expect(err).ToNot(HaveOccurred()) Expect(projectID).ToNot(BeNil()) - // in this scenario user "u-s-e-r-id" has this permissions: + // in this scenario user "25b69780-5f39-43be-a7ac-a9b9e9fe4230" has this permissions: registerPermissions(env.Permissions, "25b69780-5f39-43be-a7ac-a9b9e9fe4230", &provider.ResourcePermissions{ InitiateFileUpload: true, Delete: true, @@ -317,7 +317,7 @@ var _ = Describe("Recycle", func() { Username: "readusername", }) - // in this scenario user "u-s-e-r-id" has this permissions: + // in this scenario user "25b69780-5f39-43be-a7ac-a9b9e9fe4230" has this permissions: registerPermissions(env.Permissions, "25b69780-5f39-43be-a7ac-a9b9e9fe4230", &provider.ResourcePermissions{ Delete: true, ListRecycle: true, diff --git a/pkg/storage/utils/decomposedfs/spaces.go b/pkg/storage/utils/decomposedfs/spaces.go index ef928f13d2..0d1fe84b5f 100644 --- a/pkg/storage/utils/decomposedfs/spaces.go +++ b/pkg/storage/utils/decomposedfs/spaces.go @@ -105,7 +105,7 @@ func (fs *Decomposedfs) CreateStorageSpace(ctx context.Context, req *provider.Cr return nil, err } - metadata := make(map[string]string, 3) + metadata := make(map[string]string, 6) // always enable propagation on the storage space root // mark the space root node as the end of propagation @@ -428,11 +428,11 @@ func (fs *Decomposedfs) UpdateStorageSpace(ctx context.Context, req *provider.Up metadata[xattrs.SpaceDescriptionAttr] = string(description.Value) hasDescription = true } - if alias, ok := space.Opaque.Map["spaceAlias"]; ok { - metadata[xattrs.SpaceAliasAttr] = string(alias.Value) + if alias := utils.ReadPlainFromOpaque(space.Opaque, "spaceAlias"); alias != "" { + metadata[xattrs.SpaceAliasAttr] = alias } - if image, ok := space.Opaque.Map["image"]; ok { - imageID := resourceid.OwnCloudResourceIDUnwrap(string(image.Value)) + if image := utils.ReadPlainFromOpaque(space.Opaque, "image"); image != "" { + imageID := resourceid.OwnCloudResourceIDUnwrap(image) if imageID == nil { return &provider.UpdateStorageSpaceResponse{ Status: &v1beta11.Status{Code: v1beta11.Code_CODE_NOT_FOUND, Message: "decomposedFS: space image resource not found"}, @@ -440,8 +440,8 @@ func (fs *Decomposedfs) UpdateStorageSpace(ctx context.Context, req *provider.Up } metadata[xattrs.SpaceImageAttr] = imageID.OpaqueId } - if readme, ok := space.Opaque.Map["readme"]; ok { - readmeID := resourceid.OwnCloudResourceIDUnwrap(string(readme.Value)) + if readme := utils.ReadPlainFromOpaque(space.Opaque, "readme"); readme != "" { + readmeID := resourceid.OwnCloudResourceIDUnwrap(readme) if readmeID == nil { return &provider.UpdateStorageSpaceResponse{ Status: &v1beta11.Status{Code: v1beta11.Code_CODE_NOT_FOUND, Message: "decomposedFS: space readme resource not found"}, @@ -637,10 +637,7 @@ func (fs *Decomposedfs) storageSpaceFromNode(ctx context.Context, n *node.Node, } if n.SpaceRoot.IsDisabled() { - space.Opaque.Map["trashed"] = &types.OpaqueEntry{ - Decoder: "plain", - Value: []byte("trashed"), - } + space.Opaque = utils.AppendPlainToOpaque(space.Opaque, "trashed", "trashed") } if n.Owner() != nil && n.Owner().OpaqueId != "" { @@ -702,37 +699,23 @@ func (fs *Decomposedfs) storageSpaceFromNode(ctx context.Context, n *node.Node, } spaceImage, ok := spaceAttributes[xattrs.SpaceImageAttr] if ok { - space.Opaque = utils.AppendPlainToOpaque( - space.Opaque, - "image", - resourceid.OwnCloudResourceIDWrap( - &provider.ResourceId{ - StorageId: space.Root.StorageId, - OpaqueId: spaceImage, - }, - ), - ) + space.Opaque = utils.AppendPlainToOpaque(space.Opaque, "image", resourceid.OwnCloudResourceIDWrap( + &provider.ResourceId{StorageId: space.Root.StorageId, OpaqueId: spaceImage}, + )) } spaceDescription, ok := spaceAttributes[xattrs.SpaceDescriptionAttr] if ok { - space.Opaque.Map["description"] = &types.OpaqueEntry{ - Decoder: "plain", - Value: []byte(spaceDescription), - } + space.Opaque = utils.AppendPlainToOpaque(space.Opaque, "description", spaceDescription) } spaceReadme, ok := spaceAttributes[xattrs.SpaceReadmeAttr] if ok { - space.Opaque.Map["readme"] = &types.OpaqueEntry{ - Decoder: "plain", - Value: []byte(resourceid.OwnCloudResourceIDWrap(&provider.ResourceId{StorageId: space.Root.StorageId, OpaqueId: spaceReadme})), - } + space.Opaque = utils.AppendPlainToOpaque(space.Opaque, "readme", resourceid.OwnCloudResourceIDWrap( + &provider.ResourceId{StorageId: space.Root.StorageId, OpaqueId: spaceReadme}, + )) } spaceAlias, ok := spaceAttributes[xattrs.SpaceAliasAttr] if ok { - space.Opaque.Map["spaceAlias"] = &types.OpaqueEntry{ - Decoder: "plain", - Value: []byte(spaceAlias), - } + space.Opaque = utils.AppendPlainToOpaque(space.Opaque, "spaceAlias", spaceAlias) } return space, nil } From 67a17162e4ccdd32e4c64e38cfe449d9ba44e54b Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Wed, 9 Mar 2022 16:50:52 +0100 Subject: [PATCH 4/6] use configurable templates for space alias --- .../utils/decomposedfs/options/options.go | 11 +++++ pkg/storage/utils/decomposedfs/spaces.go | 7 +++- pkg/storage/utils/templates/templates.go | 40 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/pkg/storage/utils/decomposedfs/options/options.go b/pkg/storage/utils/decomposedfs/options/options.go index 765c0c0c53..16811837a7 100644 --- a/pkg/storage/utils/decomposedfs/options/options.go +++ b/pkg/storage/utils/decomposedfs/options/options.go @@ -48,6 +48,9 @@ type Options struct { // permissions service to use when checking permissions PermissionsSVC string `mapstructure:"permissionssvc"` + + PersonalSpaceAliasTemplate string `mapstructure:"personalspacealias_template"` + GeneralSpaceAliasTemplate string `mapstructure:"generalspacealias_template"` } // New returns a new Options instance for the given configuration @@ -73,5 +76,13 @@ func New(m map[string]interface{}) (*Options, error) { // c.DataDirectory should never end in / unless it is the root o.Root = filepath.Clean(o.Root) + if o.PersonalSpaceAliasTemplate == "" { + o.PersonalSpaceAliasTemplate = "{{.SpaceType}}/{{.User.Username}}" + } + + if o.GeneralSpaceAliasTemplate == "" { + o.GeneralSpaceAliasTemplate = "{{.SpaceType}}/{{.SpaceName | replace \" \" \"-\" | lower}}" + } + return o, nil } diff --git a/pkg/storage/utils/decomposedfs/spaces.go b/pkg/storage/utils/decomposedfs/spaces.go index 0d1fe84b5f..2421db8afe 100644 --- a/pkg/storage/utils/decomposedfs/spaces.go +++ b/pkg/storage/utils/decomposedfs/spaces.go @@ -42,6 +42,7 @@ import ( "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/lookup" "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node" "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/xattrs" + "github.com/cs3org/reva/v2/pkg/storage/utils/templates" "github.com/cs3org/reva/v2/pkg/utils" "github.com/cs3org/reva/v2/pkg/utils/resourceid" "github.com/google/uuid" @@ -69,11 +70,15 @@ func (fs *Decomposedfs) CreateStorageSpace(ctx context.Context, req *provider.Cr description := utils.ReadPlainFromOpaque(req.Opaque, "description") // allow sending a spaceAlias alias := utils.ReadPlainFromOpaque(req.Opaque, "spaceAlias") + u := ctxpkg.ContextMustGetUser(ctx) + if alias == "" { + alias = templates.WithSpacePropertiesAndUser(u, req.Type, req.Name, fs.o.GeneralSpaceAliasTemplate) + } // TODO enforce a uuid? // TODO clarify if we want to enforce a single personal storage space or if we want to allow sending the spaceid if req.Type == spaceTypePersonal { spaceID = req.GetOwner().GetId().GetOpaqueId() - alias = spaceTypePersonal + "/" + req.GetOwner().GetUsername() + alias = templates.WithSpacePropertiesAndUser(u, req.Type, req.Name, fs.o.PersonalSpaceAliasTemplate) } root, err := node.ReadNode(ctx, fs.lu, spaceID, spaceID) diff --git a/pkg/storage/utils/templates/templates.go b/pkg/storage/utils/templates/templates.go index 2741073cc6..61c3e5d22e 100644 --- a/pkg/storage/utils/templates/templates.go +++ b/pkg/storage/utils/templates/templates.go @@ -43,6 +43,14 @@ type UserData struct { Email EmailData } +// SpaceData contains the templace placeholders for a space. +// For example {{.SpaceName}} {{.SpaceType}} or {{.User.Id.OpaqueId}} +type SpaceData struct { + *UserData + SpaceType string + SpaceName string +} + // EmailData contains mail data // split into local and domain part. // It is extracted from splitting the username by @. @@ -69,8 +77,30 @@ func WithUser(u *userpb.User, tpl string) string { return b.String() } +// WithSpacePropertiesAndUser generates a layout based on user data and a space type. +func WithSpacePropertiesAndUser(u *userpb.User, spaceType string, spaceName string, tpl string) string { + tpl = clean(tpl) + sd := newSpaceData(u, spaceType, spaceName) + // compile given template tpl + t, err := template.New("tpl").Funcs(sprig.TxtFuncMap()).Parse(tpl) + if err != nil { + err := errors.Wrap(err, fmt.Sprintf("error parsing template: spaceanduser_template:%+v tpl:%s", sd, tpl)) + panic(err) + } + b := bytes.Buffer{} + if err := t.Execute(&b, sd); err != nil { + err := errors.Wrap(err, fmt.Sprintf("error executing template: spaceanduser_template:%+v tpl:%s", sd, tpl)) + panic(err) + } + return b.String() +} + func newUserData(u *userpb.User) *UserData { usernameSplit := strings.Split(u.Username, "@") + if u.Mail != "" { + usernameSplit = strings.Split(u.Mail, "@") + } + if len(usernameSplit) == 1 { usernameSplit = append(usernameSplit, "_unknown") } @@ -88,6 +118,16 @@ func newUserData(u *userpb.User) *UserData { return ut } +func newSpaceData(u *userpb.User, st string, n string) *SpaceData { + userData := newUserData(u) + sd := &SpaceData{ + userData, + st, + n, + } + return sd +} + func clean(a string) string { return path.Clean(a) } From bfdae74f67f1eb23367fd97f294d2cba083ab55f Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Wed, 9 Mar 2022 17:21:21 +0100 Subject: [PATCH 5/6] add more tests --- pkg/storage/utils/decomposedfs/spaces_test.go | 14 +++++++++++++- .../drone/storage-users-ocis.toml | 2 ++ .../oc-integration-tests/local/storage-users.toml | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/pkg/storage/utils/decomposedfs/spaces_test.go b/pkg/storage/utils/decomposedfs/spaces_test.go index bad47780a0..1543d647a6 100644 --- a/pkg/storage/utils/decomposedfs/spaces_test.go +++ b/pkg/storage/utils/decomposedfs/spaces_test.go @@ -21,13 +21,14 @@ package decomposedfs_test import ( permissionsv1beta1 "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1" rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" helpers "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/testhelpers" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/stretchr/testify/mock" ) -var _ = Describe("Home is Created", func() { +var _ = Describe("Create Spaces", func() { var ( env *helpers.TestEnv ) @@ -55,4 +56,15 @@ var _ = Describe("Home is Created", func() { Expect(resp[0].SpaceType).To(Equal("personal")) }) }) + Context("when creating a space", func() { + It("project space is created", func() { + resp, err := env.Fs.CreateStorageSpace(env.Ctx, &provider.CreateStorageSpaceRequest{Name: "Mission to Mars", Type: "project"}) + Expect(err).ToNot(HaveOccurred()) + Expect(resp.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK)) + Expect(resp.StorageSpace).ToNot(Equal(nil)) + Expect(string(resp.StorageSpace.Opaque.Map["spaceAlias"].Value)).To(Equal("project/mission-to-mars")) + Expect(resp.StorageSpace.Name).To(Equal("Mission to Mars")) + Expect(resp.StorageSpace.SpaceType).To(Equal("project")) + }) + }) }) diff --git a/tests/oc-integration-tests/drone/storage-users-ocis.toml b/tests/oc-integration-tests/drone/storage-users-ocis.toml index ed175d2850..d076b92bf1 100644 --- a/tests/oc-integration-tests/drone/storage-users-ocis.toml +++ b/tests/oc-integration-tests/drone/storage-users-ocis.toml @@ -23,6 +23,8 @@ root = "/drone/src/tmp/reva/data" treetime_accounting = true treesize_accounting = true permissionssvc = "localhost:10000" +personalspacealias_template = "{{.SpaceType}}/{{.User.Username}}" +generalspacealias_template = "{{.SpaceType}}/{{.SpaceName | replace \" \" \"-\" | lower}}" # we have a locally running dataprovider [http] diff --git a/tests/oc-integration-tests/local/storage-users.toml b/tests/oc-integration-tests/local/storage-users.toml index 0c50bcb3d8..a270504b28 100644 --- a/tests/oc-integration-tests/local/storage-users.toml +++ b/tests/oc-integration-tests/local/storage-users.toml @@ -27,6 +27,8 @@ root = "/var/tmp/reva/data" treetime_accounting = true treesize_accounting = true permissionssvc = "localhost:10000" +personalspacealias_template = "{{.SpaceType}}/{{.User.Username}}" +generalspacealias_template = "{{.SpaceType}}/{{.SpaceName | replace \" \" \"-\" | lower}}" # we have a locally running dataprovider [http] From 8fcd5a6b3955d889b4d353bb14fcdc14e216c262 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Sun, 13 Mar 2022 22:23:57 +0100 Subject: [PATCH 6/6] add tests with custom alias template --- .../decomposedfs_concurrency_test.go | 2 +- .../utils/decomposedfs/decomposedfs_test.go | 2 +- pkg/storage/utils/decomposedfs/grants_test.go | 2 +- .../utils/decomposedfs/lookup/lookup_test.go | 2 +- .../utils/decomposedfs/node/locks_test.go | 2 +- .../utils/decomposedfs/node/node_test.go | 2 +- .../utils/decomposedfs/recycle_test.go | 2 +- pkg/storage/utils/decomposedfs/spaces_test.go | 41 ++++++++++++++++++- .../utils/decomposedfs/testhelpers/helpers.go | 15 +++++-- .../utils/decomposedfs/tree/tree_test.go | 2 +- 10 files changed, 59 insertions(+), 13 deletions(-) diff --git a/pkg/storage/utils/decomposedfs/decomposedfs_concurrency_test.go b/pkg/storage/utils/decomposedfs/decomposedfs_concurrency_test.go index 14c3499224..7bc6fe1cb8 100644 --- a/pkg/storage/utils/decomposedfs/decomposedfs_concurrency_test.go +++ b/pkg/storage/utils/decomposedfs/decomposedfs_concurrency_test.go @@ -40,7 +40,7 @@ var _ = Describe("Decomposed", func() { BeforeEach(func() { var err error - env, err = testhelpers.NewTestEnv() + env, err = testhelpers.NewTestEnv(nil) Expect(err).ToNot(HaveOccurred()) }) diff --git a/pkg/storage/utils/decomposedfs/decomposedfs_test.go b/pkg/storage/utils/decomposedfs/decomposedfs_test.go index 63dd901be6..d456628b1a 100644 --- a/pkg/storage/utils/decomposedfs/decomposedfs_test.go +++ b/pkg/storage/utils/decomposedfs/decomposedfs_test.go @@ -39,7 +39,7 @@ var _ = Describe("Decomposed", func() { JustBeforeEach(func() { var err error - env, err = helpers.NewTestEnv() + env, err = helpers.NewTestEnv(nil) Expect(err).ToNot(HaveOccurred()) ref = &provider.Reference{ diff --git a/pkg/storage/utils/decomposedfs/grants_test.go b/pkg/storage/utils/decomposedfs/grants_test.go index 980470e449..13f9f9ac2e 100644 --- a/pkg/storage/utils/decomposedfs/grants_test.go +++ b/pkg/storage/utils/decomposedfs/grants_test.go @@ -69,7 +69,7 @@ var _ = Describe("Grants", func() { JustBeforeEach(func() { var err error - env, err = helpers.NewTestEnv() + env, err = helpers.NewTestEnv(nil) Expect(err).ToNot(HaveOccurred()) ref = &provider.Reference{ diff --git a/pkg/storage/utils/decomposedfs/lookup/lookup_test.go b/pkg/storage/utils/decomposedfs/lookup/lookup_test.go index 6598d7c283..aacdcc1789 100644 --- a/pkg/storage/utils/decomposedfs/lookup/lookup_test.go +++ b/pkg/storage/utils/decomposedfs/lookup/lookup_test.go @@ -33,7 +33,7 @@ var _ = Describe("Lookup", func() { JustBeforeEach(func() { var err error - env, err = helpers.NewTestEnv() + env, err = helpers.NewTestEnv(nil) Expect(err).ToNot(HaveOccurred()) }) diff --git a/pkg/storage/utils/decomposedfs/node/locks_test.go b/pkg/storage/utils/decomposedfs/node/locks_test.go index ec6ab2d5b3..f11878953e 100644 --- a/pkg/storage/utils/decomposedfs/node/locks_test.go +++ b/pkg/storage/utils/decomposedfs/node/locks_test.go @@ -55,7 +55,7 @@ var _ = Describe("Node locks", func() { BeforeEach(func() { var err error - env, err = helpers.NewTestEnv() + env, err = helpers.NewTestEnv(nil) Expect(err).ToNot(HaveOccurred()) lock = &provider.Lock{ diff --git a/pkg/storage/utils/decomposedfs/node/node_test.go b/pkg/storage/utils/decomposedfs/node/node_test.go index 0f58a451d3..c653ba6b26 100644 --- a/pkg/storage/utils/decomposedfs/node/node_test.go +++ b/pkg/storage/utils/decomposedfs/node/node_test.go @@ -40,7 +40,7 @@ var _ = Describe("Node", func() { BeforeEach(func() { var err error - env, err = helpers.NewTestEnv() + env, err = helpers.NewTestEnv(nil) Expect(err).ToNot(HaveOccurred()) id = "fooId" diff --git a/pkg/storage/utils/decomposedfs/recycle_test.go b/pkg/storage/utils/decomposedfs/recycle_test.go index 59a916166b..e5e6a3b2d8 100644 --- a/pkg/storage/utils/decomposedfs/recycle_test.go +++ b/pkg/storage/utils/decomposedfs/recycle_test.go @@ -39,7 +39,7 @@ var _ = Describe("Recycle", func() { BeforeEach(func() { var err error - env, err = helpers.NewTestEnv() + env, err = helpers.NewTestEnv(nil) Expect(err).ToNot(HaveOccurred()) }) diff --git a/pkg/storage/utils/decomposedfs/spaces_test.go b/pkg/storage/utils/decomposedfs/spaces_test.go index 1543d647a6..d68bcac767 100644 --- a/pkg/storage/utils/decomposedfs/spaces_test.go +++ b/pkg/storage/utils/decomposedfs/spaces_test.go @@ -35,7 +35,7 @@ var _ = Describe("Create Spaces", func() { BeforeEach(func() { var err error - env, err = helpers.NewTestEnv() + env, err = helpers.NewTestEnv(nil) Expect(err).ToNot(HaveOccurred()) env.PermissionsClient.On("CheckPermission", mock.Anything, mock.Anything, mock.Anything).Return(&permissionsv1beta1.CheckPermissionResponse{Status: &rpcv1beta1.Status{Code: rpcv1beta1.Code_CODE_OK}}, nil) }) @@ -67,4 +67,43 @@ var _ = Describe("Create Spaces", func() { Expect(resp.StorageSpace.SpaceType).To(Equal("project")) }) }) + Describe("Create Spaces with custom alias template", func() { + var ( + env *helpers.TestEnv + ) + + BeforeEach(func() { + var err error + env, err = helpers.NewTestEnv(map[string]interface{}{ + "personalspacealias_template": "{{.SpaceType}}/{{.Email.Local}}@{{.Email.Domain}}", + "generalspacealias_template": "{{.SpaceType}}:{{.SpaceName | replace \" \" \"-\" | upper}}", + }) + Expect(err).ToNot(HaveOccurred()) + env.PermissionsClient.On("CheckPermission", mock.Anything, mock.Anything, mock.Anything).Return(&permissionsv1beta1.CheckPermissionResponse{Status: &rpcv1beta1.Status{Code: rpcv1beta1.Code_CODE_OK}}, nil) + }) + + AfterEach(func() { + if env != nil { + env.Cleanup() + } + }) + Context("during login", func() { + It("personal space is created with custom alias", func() { + resp, err := env.Fs.ListStorageSpaces(env.Ctx, nil) + Expect(err).ToNot(HaveOccurred()) + Expect(len(resp)).To(Equal(1)) + Expect(string(resp[0].Opaque.GetMap()["spaceAlias"].Value)).To(Equal("personal/username@_unknown")) + }) + }) + Context("creating a space", func() { + It("project space is created with custom alias", func() { + resp, err := env.Fs.CreateStorageSpace(env.Ctx, &provider.CreateStorageSpaceRequest{Name: "Mission to Venus", Type: "project"}) + Expect(err).ToNot(HaveOccurred()) + Expect(resp.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK)) + Expect(resp.StorageSpace).ToNot(Equal(nil)) + Expect(string(resp.StorageSpace.Opaque.Map["spaceAlias"].Value)).To(Equal("project:MISSION-TO-VENUS")) + + }) + }) + }) }) diff --git a/pkg/storage/utils/decomposedfs/testhelpers/helpers.go b/pkg/storage/utils/decomposedfs/testhelpers/helpers.go index d441ced685..9581766619 100644 --- a/pkg/storage/utils/decomposedfs/testhelpers/helpers.go +++ b/pkg/storage/utils/decomposedfs/testhelpers/helpers.go @@ -64,20 +64,27 @@ type TestEnv struct { // /dir1/ // /dir1/file1 // /dir1/subdir1/ -func NewTestEnv() (*TestEnv, error) { +// +// The default config can be overridden by providing the strings to override +// via map as a parameter +func NewTestEnv(config map[string]interface{}) (*TestEnv, error) { tmpRoot, err := helpers.TempDir("reva-unit-tests-*-root") if err != nil { return nil, err } - - config := map[string]interface{}{ + defaultConfig := map[string]interface{}{ "root": tmpRoot, "treetime_accounting": true, "treesize_accounting": true, "share_folder": "/Shares", "user_layout": "{{.Id.OpaqueId}}", } - o, err := options.New(config) + // make it possible to override single config values + for k, v := range config { + defaultConfig[k] = v + } + + o, err := options.New(defaultConfig) if err != nil { return nil, err } diff --git a/pkg/storage/utils/decomposedfs/tree/tree_test.go b/pkg/storage/utils/decomposedfs/tree/tree_test.go index 896126cd1c..9486372637 100644 --- a/pkg/storage/utils/decomposedfs/tree/tree_test.go +++ b/pkg/storage/utils/decomposedfs/tree/tree_test.go @@ -45,7 +45,7 @@ var _ = Describe("Tree", func() { JustBeforeEach(func() { var err error - env, err = helpers.NewTestEnv() + env, err = helpers.NewTestEnv(nil) Expect(err).ToNot(HaveOccurred()) t = env.Tree })