Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions services/graph/pkg/service/v0/driveitems.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,29 @@ import (

revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
"github.com/opencloud-eu/reva/v2/pkg/tags"
"github.com/opencloud-eu/reva/v2/pkg/utils"

"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
"github.com/opencloud-eu/opencloud/services/graph/pkg/unifiedrole"
)

// opt-in driveItem instance annotations, returned only when requested via $select
const _selectAllowedValues = "@libre.graph.permissions.actions.allowedValues"

// driveItemPropertySelected reports whether the given opt-in property was requested via $select
func driveItemPropertySelected(r *http.Request, property string) bool {
for _, values := range r.URL.Query()["$select"] {
for _, v := range strings.Split(values, ",") {
if v == property {
return true
}
}
}
return false
}

// CreateUploadSession create an upload session to allow your app to upload files up to the maximum file size.
// An upload session allows your app to upload ranges of the file in sequential API requests, which allows the
// transfer to be resumed if a connection is dropped while the upload is in progress.
Expand Down Expand Up @@ -211,6 +228,12 @@ func (g Graph) GetRootDriveChildren(w http.ResponseWriter, r *http.Request) {
return
}

if driveItemPropertySelected(r, _selectAllowedValues) {
for i, info := range lRes.GetInfos() {
files[i].LibreGraphPermissionsActionsAllowedValues = unifiedrole.CS3ResourcePermissionsToLibregraphActions(info.GetPermissionSet())
}
}

render.Status(r, http.StatusOK)
render.JSON(w, r, &ListResponse{Value: files})
}
Expand Down Expand Up @@ -275,6 +298,10 @@ func (g Graph) GetDriveItem(w http.ResponseWriter, r *http.Request) {
return
}

if driveItemPropertySelected(r, _selectAllowedValues) {
driveItem.LibreGraphPermissionsActionsAllowedValues = unifiedrole.CS3ResourcePermissionsToLibregraphActions(res.GetInfo().GetPermissionSet())
}

render.Status(r, http.StatusOK)
render.JSON(w, r, &driveItem)
}
Expand Down Expand Up @@ -457,6 +484,12 @@ func cs3ResourceToDriveItem(logger *log.Logger, publicBaseURL *url.URL, res *sto
driveItem.Image = cs3ResourceToDriveItemImageFacet(logger, res)
driveItem.Location = cs3ResourceToDriveItemLocationFacet(logger, res)
driveItem.Photo = cs3ResourceToDriveItemPhotoFacet(logger, res)

m := res.GetArbitraryMetadata().GetMetadata()
driveItem.LibreGraphMeFollowing = libregraph.PtrBool(m[_favoriteMetadataKey] == "1")
if t := m["tags"]; t != "" {
driveItem.LibreGraphTags = tags.New(t).AsSlice()
}
}

return driveItem, nil
Expand Down
103 changes: 103 additions & 0 deletions services/graph/pkg/service/v0/driveitems_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/opencloud-eu/opencloud/services/graph/pkg/config/defaults"
identitymocks "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/mocks"
service "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0"
"github.com/opencloud-eu/opencloud/services/graph/pkg/unifiedrole"
)

type itemsList struct {
Expand Down Expand Up @@ -196,6 +197,43 @@ var _ = Describe("Driveitems", func() {
Expect(res.Value[0].GetLastModifiedDateTime().Equal(mtime)).To(BeTrue())
Expect(res.Value[0].GetETag()).To(Equal("etag"))
Expect(res.Value[0].GetId()).To(Equal("storageid$spaceid!opaqueid"))
Expect(res.Value[0].LibreGraphPermissionsActionsAllowedValues).To(BeNil())
})

It("returns the allowed actions when requested via $select", func() {
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(&provider.ListStorageSpacesResponse{
Status: status.NewOK(ctx),
StorageSpaces: []*provider.StorageSpace{{Owner: currentUser, Root: &provider.ResourceId{}}},
}, nil)
gatewayClient.On("ListContainer", mock.Anything, mock.Anything).Return(&provider.ListContainerResponse{
Status: status.NewOK(ctx),
Infos: []*provider.ResourceInfo{
{
Type: provider.ResourceType_RESOURCE_TYPE_FILE,
Id: &provider.ResourceId{StorageId: "storageid", SpaceId: "spaceid", OpaqueId: "opaqueid"},
Etag: "etag",
Mtime: utils.TimeToTS(time.Now()),
PermissionSet: &provider.ResourcePermissions{
GetPath: true,
InitiateFileDownload: true,
},
},
},
}, nil)
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drive/root/children?$select=@libre.graph.permissions.actions.allowedValues", nil)
r = r.WithContext(revactx.ContextSetUser(ctx, currentUser))
svc.GetRootDriveChildren(rr, r)
Expect(rr.Code).To(Equal(http.StatusOK))
data, err := io.ReadAll(rr.Body)
Expect(err).ToNot(HaveOccurred())

res := itemsList{}
Expect(json.Unmarshal(data, &res)).To(Succeed())
Expect(len(res.Value)).To(Equal(1))
Expect(res.Value[0].GetLibreGraphPermissionsActionsAllowedValues()).To(ConsistOf(
unifiedrole.DriveItemPathRead,
unifiedrole.DriveItemContentRead,
))
})
})

Expand Down Expand Up @@ -293,6 +331,71 @@ var _ = Describe("Driveitems", func() {
res := assertItemsList(1)
Expect(res.Value[0].Audio).To(BeNil())
Expect(res.Value[0].Location).To(BeNil())
Expect(res.Value[0].LibreGraphMeFollowing).To(BeNil())
Expect(res.Value[0].LibreGraphTags).To(BeNil())
})

It("returns tags if metadata is available", func() {
gatewayClient.On("ListContainer", mock.Anything, mock.Anything).Return(&provider.ListContainerResponse{
Status: status.NewOK(ctx),
Infos: []*provider.ResourceInfo{
{
Type: provider.ResourceType_RESOURCE_TYPE_FILE,
Id: &provider.ResourceId{StorageId: "storageid", SpaceId: "spaceid", OpaqueId: "opaqueid"},
Etag: "etag",
Mtime: utils.TimeToTS(mtime),
ArbitraryMetadata: &provider.ArbitraryMetadata{
Metadata: map[string]string{
"tags": "marketing,important",
},
},
},
},
}, nil)

res := assertItemsList(1)
Expect(res.Value[0].GetLibreGraphTags()).To(ConsistOf("marketing", "important"))
})

It("returns the following state if metadata is available", func() {
gatewayClient.On("ListContainer", mock.Anything, mock.Anything).Return(&provider.ListContainerResponse{
Status: status.NewOK(ctx),
Infos: []*provider.ResourceInfo{
{
Type: provider.ResourceType_RESOURCE_TYPE_FILE,
Id: &provider.ResourceId{StorageId: "storageid", SpaceId: "spaceid", OpaqueId: "opaqueid"},
Etag: "etag",
Mtime: utils.TimeToTS(mtime),
ArbitraryMetadata: &provider.ArbitraryMetadata{
Metadata: map[string]string{
"http://owncloud.org/ns/favorite": "1",
},
},
},
},
}, nil)

res := assertItemsList(1)
Expect(res.Value[0].GetLibreGraphMeFollowing()).To(BeTrue())
})

It("reports not following if the favorite flag is absent", func() {
gatewayClient.On("ListContainer", mock.Anything, mock.Anything).Return(&provider.ListContainerResponse{
Status: status.NewOK(ctx),
Infos: []*provider.ResourceInfo{
{
Type: provider.ResourceType_RESOURCE_TYPE_FILE,
Id: &provider.ResourceId{StorageId: "storageid", SpaceId: "spaceid", OpaqueId: "opaqueid"},
Etag: "etag",
Mtime: utils.TimeToTS(mtime),
ArbitraryMetadata: &provider.ArbitraryMetadata{Metadata: map[string]string{}},
},
},
}, nil)

res := assertItemsList(1)
Expect(res.Value[0].LibreGraphMeFollowing).ToNot(BeNil())
Expect(res.Value[0].GetLibreGraphMeFollowing()).To(BeFalse())
})

It("returns the audio facet if metadata is available", func() {
Expand Down
7 changes: 6 additions & 1 deletion services/graph/pkg/service/v0/follow.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import (
"github.com/opencloud-eu/reva/v2/pkg/events"
)

const _favoriteLabel = "favorite"
const (
_favoriteLabel = "favorite"
// deliberately not using the existing node.FavoriteKey constant to avoid importing a specific storage driver package
_favoriteMetadataKey = "http://owncloud.org/ns/favorite"
)

// FollowDriveItem marks a drive item as favorite.
func (g Graph) FollowDriveItem(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -99,6 +103,7 @@ func (g Graph) FollowDriveItem(w http.ResponseWriter, r *http.Request) {
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
driveItem.SetLibreGraphMeFollowing(true)

render.Status(r, http.StatusCreated)
render.JSON(w, r, &driveItem)
Expand Down