Skip to content

Commit

Permalink
graph/sharedbyme: populate the permissions property
Browse files Browse the repository at this point in the history
Set the exipration date, grantedToV2 and link attributes on the
permissions.

The displayName for users and groups isn't expanded yet (only the "id" is set)
Also, the "roles" attribute cannot be populated yet.
  • Loading branch information
rhafer committed Oct 24, 2023
1 parent e8bf18a commit edc885f
Show file tree
Hide file tree
Showing 2 changed files with 201 additions and 23 deletions.
49 changes: 48 additions & 1 deletion services/graph/pkg/service/v0/sharedbyme.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package svc
import (
"context"
"net/http"
"net/url"
"path"

rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
Expand All @@ -29,7 +31,7 @@ func (g Graph) GetSharedByMe(w http.ResponseWriter, r *http.Request) {
return
}

_, err = g.listPublicShares(ctx, driveItems)
driveItems, err = g.listPublicShares(ctx, driveItems)
if err != nil {
errorcode.RenderError(w, r, err)
return
Expand Down Expand Up @@ -115,6 +117,29 @@ func (g Graph) cs3UserSharesToDriveItems(ctx context.Context, shares []*collabor
}
item = *itemptr
}
perm := libregraph.Permission{}
perm.SetRoles([]string{"TODO:insert-role-here"})
perm.SetId(s.Id.OpaqueId)
grantedTo := libregraph.SharePointIdentitySet{}
switch s.Grantee.Type {
case storageprovider.GranteeType_GRANTEE_TYPE_USER:
user := libregraph.NewIdentityWithDefaults()
user.SetId(s.Grantee.GetUserId().GetOpaqueId())
grantedTo.SetUser(*user)
case storageprovider.GranteeType_GRANTEE_TYPE_GROUP:
grp := libregraph.NewIdentityWithDefaults()
grp.SetId(s.Grantee.GetGroupId().GetOpaqueId())
grantedTo.SetGroup(*grp)

}

// set expiration date
if s.GetExpiration() != nil {
perm.SetExpirationDateTime(cs3TimestampToTime(s.GetExpiration()))
}

perm.SetGrantedToV2(grantedTo)
item.Permissions = append(item.Permissions, perm)
driveItems[resIDStr] = item
}
return driveItems, nil
Expand All @@ -133,6 +158,28 @@ func (g Graph) cs3PublicSharesToDriveItems(ctx context.Context, shares []*link.P
}
item = *itemptr
}
perm := libregraph.Permission{}
perm.SetId(s.Id.OpaqueId)
perm.SetRoles([]string{"TODO:insert-role-here"})
link := libregraph.SharingLink{}
webURL, err := url.Parse(g.config.Spaces.WebDavBase)
if err != nil {
g.logger.Error().
Err(err).
Str("url", g.config.Spaces.WebDavBase).
Msg("failed to parse webURL base url")
return driveItems, err
}

webURL.Path = path.Join(webURL.Path, "s", s.GetToken())
link.SetWebUrl(webURL.String())
perm.SetLink(link)
// set expiration date
if s.GetExpiration() != nil {
perm.SetExpirationDateTime(cs3TimestampToTime(s.GetExpiration()))
}

item.Permissions = append(item.Permissions, perm)
driveItems[resIDStr] = item
}

Expand Down
175 changes: 153 additions & 22 deletions services/graph/pkg/service/v0/sharedbyme_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
cs3mocks "github.com/cs3org/reva/v2/tests/cs3mocks/mocks"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
libregraph "github.com/owncloud/libre-graph-api-go"
"github.com/owncloud/ocis/v2/ocis-pkg/shared"
"github.com/owncloud/ocis/v2/services/graph/mocks"
"github.com/owncloud/ocis/v2/services/graph/pkg/config"
Expand All @@ -44,9 +43,8 @@ var _ = Describe("sharedbyme", func() {
identityBackend *identitymocks.Backend

rr *httptest.ResponseRecorder

newGroup *libregraph.Group
)
expiration := time.Now()
userShare := collaboration.Share{
Id: &collaboration.ShareId{
OpaqueId: "share-id",
Expand Down Expand Up @@ -100,7 +98,19 @@ var _ = Describe("sharedbyme", func() {
},
},
},
Expiration: utils.TimeToTS(time.Now()),
Expiration: utils.TimeToTS(expiration),
}

publicShare := link.PublicShare{
Id: &link.PublicShareId{
OpaqueId: "public-share-id",
},
Token: "public-share-token",
ResourceId: &provider.ResourceId{
StorageId: "storageid",
SpaceId: "spaceid",
OpaqueId: "public-share-opaqueid",
},
}

BeforeEach(func() {
Expand All @@ -110,14 +120,6 @@ var _ = Describe("sharedbyme", func() {

pool.RemoveSelector("GatewaySelector" + "com.owncloud.api.gateway")
gatewayClient = &cs3mocks.GatewayAPIClient{}
gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(
&link.ListPublicSharesResponse{
Status: status.NewOK(ctx),
Share: []*link.PublicShare{},
},
nil,
)
// no stat for the image
gatewayClient.On("Stat",
mock.Anything,
mock.MatchedBy(
Expand All @@ -130,6 +132,18 @@ var _ = Describe("sharedbyme", func() {
Id: userShareWithExpiration.ResourceId,
},
}, nil)
gatewayClient.On("Stat",
mock.Anything,
mock.MatchedBy(
func(req *provider.StatRequest) bool {
return req.Ref.ResourceId.OpaqueId == publicShare.ResourceId.OpaqueId
})).
Return(&provider.StatResponse{
Status: status.NewOK(ctx),
Info: &provider.ResourceInfo{
Id: publicShare.ResourceId,
},
}, nil)
gatewayClient.On("Stat",
mock.Anything,
mock.Anything).
Expand All @@ -148,9 +162,6 @@ var _ = Describe("sharedbyme", func() {
)

identityBackend = &identitymocks.Backend{}
newGroup = libregraph.NewGroup()
newGroup.SetMembersodataBind([]string{"/users/user1"})
newGroup.SetId("group1")

rr = httptest.NewRecorder()
ctx = context.Background()
Expand All @@ -169,15 +180,35 @@ var _ = Describe("sharedbyme", func() {
)
})

emptyListPublicSharesMock := func() {
gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(
&link.ListPublicSharesResponse{
Status: status.NewOK(ctx),
Share: []*link.PublicShare{},
},
nil,
)
}
emptyListSharesMock := func() {
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(
&collaboration.ListSharesResponse{
Status: status.NewOK(ctx),
Shares: []*collaboration.Share{},
},
nil,
)
}
Describe("GetSharedByMe", func() {
It("handles a failing ListShares", func() {
emptyListPublicSharesMock()
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(nil, errors.New("some error"))
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives/sharedByMe", nil)
svc.GetSharedByMe(rr, r)
Expect(rr.Code).To(Equal(http.StatusInternalServerError))
})

It("handles ListShares returning an error status", func() {
emptyListPublicSharesMock()
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(
&collaboration.ListSharesResponse{Status: status.NewInternal(ctx, "error listing shares")},
nil,
Expand All @@ -189,13 +220,8 @@ var _ = Describe("sharedbyme", func() {
})

It("succeeds, when no shares are returned", func() {
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(
&collaboration.ListSharesResponse{
Status: status.NewOK(ctx),
Shares: []*collaboration.Share{},
},
nil,
)
emptyListPublicSharesMock()
emptyListSharesMock()

r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives/sharedByMe", nil)
svc.GetSharedByMe(rr, r)
Expand All @@ -212,6 +238,7 @@ var _ = Describe("sharedbyme", func() {
})

It("returns a proper driveItem, when a single user share is returned", func() {
emptyListPublicSharesMock()
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(
&collaboration.ListSharesResponse{
Status: status.NewOK(ctx),
Expand All @@ -237,9 +264,22 @@ var _ = Describe("sharedbyme", func() {

di := res.Value[0]
Expect(di.GetId()).To(Equal(storagespace.FormatResourceID(*userShare.GetResourceId())))

perm := di.GetPermissions()
Expect(perm[0].GetId()).To(Equal(userShare.GetId().GetOpaqueId()))
_, ok := perm[0].GetExpirationDateTimeOk()
Expect(ok).To(BeFalse())
_, ok = perm[0].GrantedToV2.GetGroupOk()
Expect(ok).To(BeFalse())
user, ok := perm[0].GrantedToV2.GetUserOk()
Expect(ok).To(BeTrue())
Expect(user.GetId()).To(Equal(userShare.GetGrantee().GetUserId().GetOpaqueId()))
_, ok = perm[0].GetLinkOk()
Expect(ok).To(BeFalse())
})

It("returns a proper driveItem, when a single group share is returned", func() {
emptyListPublicSharesMock()
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(
&collaboration.ListSharesResponse{
Status: status.NewOK(ctx),
Expand All @@ -264,9 +304,22 @@ var _ = Describe("sharedbyme", func() {

di := res.Value[0]
Expect(di.GetId()).To(Equal(storagespace.FormatResourceID(*groupShare.GetResourceId())))

perm := di.GetPermissions()
Expect(perm[0].GetId()).To(Equal(userShare.GetId().GetOpaqueId()))
_, ok := perm[0].GetExpirationDateTimeOk()
Expect(ok).To(BeFalse())
_, ok = perm[0].GrantedToV2.GetUserOk()
Expect(ok).To(BeFalse())
group, ok := perm[0].GrantedToV2.GetGroupOk()
Expect(ok).To(BeTrue())
Expect(group.GetId()).To(Equal(groupShare.GetGrantee().GetGroupId().GetOpaqueId()))
_, ok = perm[0].GetLinkOk()
Expect(ok).To(BeFalse())
})

It("returns a single driveItem, when a mulitple shares for the same resource are returned", func() {
emptyListPublicSharesMock()
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(
&collaboration.ListSharesResponse{
Status: status.NewOK(ctx),
Expand All @@ -292,9 +345,13 @@ var _ = Describe("sharedbyme", func() {

di := res.Value[0]
Expect(di.GetId()).To(Equal(storagespace.FormatResourceID(*groupShare.GetResourceId())))

// one permission per share
Expect(len(di.GetPermissions())).To(Equal(2))
})

It("return a driveItem with the expiration date set, for expiring shares", func() {
emptyListPublicSharesMock()
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(
&collaboration.ListSharesResponse{
Status: status.NewOK(ctx),
Expand All @@ -319,6 +376,80 @@ var _ = Describe("sharedbyme", func() {

di := res.Value[0]
Expect(di.GetId()).To(Equal(storagespace.FormatResourceID(*userShareWithExpiration.GetResourceId())))

perm := di.GetPermissions()
Expect(perm[0].GetId()).To(Equal(userShareWithExpiration.GetId().GetOpaqueId()))
exp, ok := perm[0].GetExpirationDateTimeOk()
Expect(ok).To(BeTrue())
Expect(exp.Equal(expiration)).To(BeTrue())
_, ok = perm[0].GrantedToV2.GetGroupOk()
Expect(ok).To(BeFalse())
user, ok := perm[0].GrantedToV2.GetUserOk()
Expect(ok).To(BeTrue())
Expect(user.GetId()).To(Equal(userShareWithExpiration.GetGrantee().GetUserId().GetOpaqueId()))
_, ok = perm[0].GetLinkOk()
Expect(ok).To(BeFalse())
})

// Public Shares / "links" in graph terms
It("handles a failing ListPublicShares", func() {
gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(nil, errors.New("some error"))
emptyListSharesMock()
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives/sharedByMe", nil)
svc.GetSharedByMe(rr, r)
Expect(rr.Code).To(Equal(http.StatusInternalServerError))
})

It("handles ListPublicShares returning an error status", func() {
emptyListSharesMock()
gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(
&link.ListPublicSharesResponse{Status: status.NewInternal(ctx, "error listing shares")},
nil,
)

r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives/sharedByMe", nil)
svc.GetSharedByMe(rr, r)
Expect(rr.Code).To(Equal(http.StatusInternalServerError))
})

It("returns a proper driveItem, when a single public share is returned", func() {
emptyListSharesMock()
gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(
&link.ListPublicSharesResponse{
Status: status.NewOK(ctx),
Share: []*link.PublicShare{
&publicShare,
},
},
nil,
)

r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives/sharedByMe", nil)
svc.GetSharedByMe(rr, r)
Expect(rr.Code).To(Equal(http.StatusOK))

data, err := io.ReadAll(rr.Body)
Expect(err).ToNot(HaveOccurred())

res := itemsList{}
err = json.Unmarshal(data, &res)
Expect(err).ToNot(HaveOccurred())

Expect(len(res.Value)).To(Equal(1))

di := res.Value[0]
Expect(di.GetId()).To(Equal(storagespace.FormatResourceID(*publicShare.GetResourceId())))

perm := di.GetPermissions()
Expect(perm[0].GetId()).To(Equal(publicShare.GetId().GetOpaqueId()))
_, ok := perm[0].GetExpirationDateTimeOk()
Expect(ok).To(BeFalse())
_, ok = perm[0].GetGrantedToV2Ok()
Expect(ok).To(BeFalse())
link, ok := perm[0].GetLinkOk()
Expect(ok).To(BeTrue())
Expect(link.GetWebUrl()).To(Equal("https://localhost:9200/s/" + publicShare.GetToken()))
})

})
})

0 comments on commit edc885f

Please sign in to comment.