Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhancement: add graph beta sharedWithMe API #7633

Merged
merged 1 commit into from Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 18 additions & 0 deletions changelog/unreleased/enhancement-sharing-ng.md
@@ -0,0 +1,18 @@
Enhancement: Add Sharing NG endpoints

We've added new sharing ng endpoints to the graph beta api.
The following endpoints are added:

* /v1beta1/me/drive/sharedByMe
* /v1beta1/me/drive/sharedWithMe
* /v1beta1/roleManagement/permissions/roleDefinitions
* /v1beta1/roleManagement/permissions/roleDefinitions/{roleID}

https://github.com/owncloud/ocis/pull/7633
https://github.com/owncloud/ocis/pull/7686
https://github.com/owncloud/ocis/pull/7684
https://github.com/owncloud/ocis/pull/7683
https://github.com/owncloud/ocis/pull/7239
https://github.com/owncloud/libre-graph-api/pull/112
https://github.com/owncloud/ocis/issues/7436
https://github.com/owncloud/ocis/issues/6993
5 changes: 4 additions & 1 deletion go.mod
Expand Up @@ -67,7 +67,7 @@ require (
github.com/onsi/gomega v1.29.0
github.com/open-policy-agent/opa v0.51.0
github.com/orcaman/concurrent-map v1.0.0
github.com/owncloud/libre-graph-api-go v1.0.5-0.20231019070917-17ae03ef40e4
github.com/owncloud/libre-graph-api-go v1.0.5-0.20231107135330-011e9d4c45e3
github.com/pkg/errors v0.9.1
github.com/pkg/xattr v0.4.9
github.com/prometheus/client_golang v1.17.0
Expand All @@ -80,6 +80,7 @@ require (
github.com/spf13/cobra v1.8.0
github.com/stretchr/testify v1.8.4
github.com/thejerf/suture/v4 v4.0.2
github.com/tidwall/gjson v1.17.0
github.com/tus/tusd v1.13.0
github.com/urfave/cli/v2 v2.25.7
github.com/xhit/go-simple-mail/v2 v2.16.0
Expand Down Expand Up @@ -305,6 +306,8 @@ require (
github.com/stretchr/objx v0.5.0 // indirect
github.com/studio-b12/gowebdav v0.0.0-20221015232716-17255f2e7423 // indirect
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect
github.com/trustelem/zxcvbn v1.0.1 // indirect
github.com/wk8/go-ordered-map v1.0.0 // indirect
Expand Down
11 changes: 9 additions & 2 deletions go.sum
Expand Up @@ -1774,8 +1774,8 @@ github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35uk
github.com/orcaman/concurrent-map v1.0.0 h1:I/2A2XPCb4IuQWcQhBhSwGfiuybl/J0ev9HDbW65HOY=
github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
github.com/owncloud/libre-graph-api-go v1.0.5-0.20231019070917-17ae03ef40e4 h1:W2X4DGGEuNUeGCKOUK8c2NAC4kva8jq9knuv5ePLUiE=
github.com/owncloud/libre-graph-api-go v1.0.5-0.20231019070917-17ae03ef40e4/go.mod h1:v2aAl5IwEI8t+GmcWvBd+bvJMYp9Vf1hekLuRf0UnEs=
github.com/owncloud/libre-graph-api-go v1.0.5-0.20231107135330-011e9d4c45e3 h1:eUE3kNgr8PwcXeUKFkuEuz1+4hfCCmq+rKYQzk0OxtY=
github.com/owncloud/libre-graph-api-go v1.0.5-0.20231107135330-011e9d4c45e3/go.mod h1:v2aAl5IwEI8t+GmcWvBd+bvJMYp9Vf1hekLuRf0UnEs=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
Expand Down Expand Up @@ -1990,6 +1990,13 @@ github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE
github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo=
github.com/thejerf/suture/v4 v4.0.2 h1:VxIH/J8uYvqJY1+9fxi5GBfGRkRZ/jlSOP6x9HijFQc=
github.com/thejerf/suture/v4 v4.0.2/go.mod h1:g0e8vwskm9tI0jRjxrnA6lSr0q6OfPdWJVX7G5bVWRs=
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 h1:PM5hJF7HVfNWmCjMdEfbuOBNXSVF2cMFGgQTPdKCbwM=
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns=
Expand Down
9 changes: 5 additions & 4 deletions services/graph/pkg/service/v0/graph.go
Expand Up @@ -15,6 +15,11 @@ import (
"github.com/cs3org/reva/v2/pkg/storagespace"
"github.com/go-chi/chi/v5"
"github.com/jellydator/ttlcache/v3"
"go-micro.dev/v4/client"
mevents "go-micro.dev/v4/events"
"go.opentelemetry.io/otel/trace"
"google.golang.org/protobuf/types/known/emptypb"

"github.com/owncloud/ocis/v2/ocis-pkg/keycloak"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
ehsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/eventhistory/v0"
Expand All @@ -23,10 +28,6 @@ import (
"github.com/owncloud/ocis/v2/services/graph/pkg/config"
"github.com/owncloud/ocis/v2/services/graph/pkg/identity"
"github.com/owncloud/ocis/v2/services/graph/pkg/service/v0/errorcode"
"go-micro.dev/v4/client"
mevents "go-micro.dev/v4/events"
"go.opentelemetry.io/otel/trace"
"google.golang.org/protobuf/types/known/emptypb"
)

//go:generate make -C ../../.. generate
Expand Down
12 changes: 7 additions & 5 deletions services/graph/pkg/service/v0/service.go
Expand Up @@ -16,6 +16,8 @@ import (
"github.com/go-chi/chi/v5/middleware"
ldapv3 "github.com/go-ldap/ldap/v3"
"github.com/jellydator/ttlcache/v3"
microstore "go-micro.dev/v4/store"

ocisldap "github.com/owncloud/ocis/v2/ocis-pkg/ldap"
"github.com/owncloud/ocis/v2/ocis-pkg/registry"
"github.com/owncloud/ocis/v2/ocis-pkg/roles"
Expand All @@ -24,7 +26,6 @@ import (
"github.com/owncloud/ocis/v2/services/graph/pkg/identity"
"github.com/owncloud/ocis/v2/services/graph/pkg/identity/ldap"
graphm "github.com/owncloud/ocis/v2/services/graph/pkg/middleware"
microstore "go-micro.dev/v4/store"
)

const (
Expand Down Expand Up @@ -95,11 +96,13 @@ type Service interface {
GetDrives(w http.ResponseWriter, r *http.Request)
GetSingleDrive(w http.ResponseWriter, r *http.Request)
GetAllDrives(w http.ResponseWriter, r *http.Request)
GetSharedByMe(w http.ResponseWriter, r *http.Request)
CreateDrive(w http.ResponseWriter, r *http.Request)
UpdateDrive(w http.ResponseWriter, r *http.Request)
DeleteDrive(w http.ResponseWriter, r *http.Request)

GetSharedByMe(w http.ResponseWriter, r *http.Request)
ListSharedWithMe(w http.ResponseWriter, r *http.Request)

GetRootDriveChildren(w http.ResponseWriter, r *http.Request)
GetDriveItem(w http.ResponseWriter, r *http.Request)
GetDriveItemChildren(w http.ResponseWriter, r *http.Request)
Expand Down Expand Up @@ -190,6 +193,7 @@ func NewService(opts ...Option) (Graph, error) {
r.Use(middleware.StripSlashes)
r.Route("/v1beta1", func(r chi.Router) {
r.Get("/me/drive/sharedByMe", svc.GetSharedByMe)
r.Get("/me/drive/sharedWithMe", svc.ListSharedWithMe)
fschade marked this conversation as resolved.
Show resolved Hide resolved
r.Route("/roleManagement/permissions/roleDefinitions", func(r chi.Router) {
r.Get("/", svc.GetRoleDefinitions)
r.Get("/{roleID}", svc.GetRoleDefinition)
Expand All @@ -208,9 +212,7 @@ func NewService(opts ...Option) (Graph, error) {
r.Route("/me", func(r chi.Router) {
r.Get("/", svc.GetMe)
r.Get("/drive", svc.GetUserDrive)
r.Route("/drives", func(r chi.Router) {
r.Get("/", svc.GetDrives)
})
r.Get("/drives", svc.GetDrives)
r.Get("/drive/root/children", svc.GetRootDriveChildren)
r.Post("/changePassword", svc.ChangeOwnPassword)
})
Expand Down
226 changes: 226 additions & 0 deletions services/graph/pkg/service/v0/sharedwithme.go
@@ -0,0 +1,226 @@
package svc

import (
"context"
"net/http"
"strings"

rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/v2/pkg/storagespace"
"github.com/go-chi/render"
libregraph "github.com/owncloud/libre-graph-api-go"

"github.com/owncloud/ocis/v2/services/graph/pkg/identity"
"github.com/owncloud/ocis/v2/services/graph/pkg/service/v0/errorcode"
)

// ListSharedWithMe lists the files shared with the current user.
func (g Graph) ListSharedWithMe(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
driveItems, err := g.listSharedWithMe(ctx)
if err != nil {
g.logger.Error().Err(err).Msg("listSharedWithMe failed")
errorcode.RenderError(w, r, err)
return
}

render.Status(r, http.StatusOK)
render.JSON(w, r, &ListResponse{Value: driveItems})
}

func (g Graph) listSharedWithMe(ctx context.Context) ([]libregraph.DriveItem, error) {
fschade marked this conversation as resolved.
Show resolved Hide resolved
gatewayClient, err := g.gatewaySelector.Next()
if err != nil {
g.logger.Error().Err(err).Msg("could not select next gateway client")
return nil, err
}

listReceivedSharesResponse, err := gatewayClient.ListReceivedShares(ctx, &collaboration.ListReceivedSharesRequest{})
if err != nil {
g.logger.Error().Err(err).Msg("listing shares failed")
return nil, errorcode.New(errorcode.GeneralException, err.Error())
}

switch listReceivedSharesResponse.Status.Code {
case rpc.Code_CODE_NOT_FOUND:
return nil, identity.ErrNotFound
}

var driveItems []libregraph.DriveItem
for _, receivedShare := range listReceivedSharesResponse.GetShares() {
share := receivedShare.GetShare()
if share == nil {
fschade marked this conversation as resolved.
Show resolved Hide resolved
g.logger.Error().Interface("ListReceivedShares", listReceivedSharesResponse).Msg("unexpected empty ReceivedShare.Share")
continue
}

driveItem := &libregraph.DriveItem{}

statResponse, err := gatewayClient.Stat(ctx, &storageprovider.StatRequest{Ref: &storageprovider.Reference{ResourceId: share.GetResourceId()}})
if err != nil {
g.logger.Error().Err(err).Msg("could not stat")
continue
}
if statResponse.GetStatus().GetCode() != rpc.Code_CODE_OK {
g.logger.Error().Err(err).Msg("invalid stat response")
continue
}
resourceInfo := statResponse.GetInfo()

var driveOwner *libregraph.Identity
if userID := statResponse.GetInfo().GetOwner(); userID != nil {
if user, err := g.identityCache.GetUser(ctx, userID.GetOpaqueId()); err != nil {
g.logger.Error().Err(err).Msg("could not get user")
continue
} else {
driveOwner = &libregraph.Identity{
DisplayName: user.GetDisplayName(),
Id: libregraph.PtrString(user.GetId()),
}
}
}

var shareCreator *libregraph.Identity
if userID := share.GetCreator(); userID != nil {
if user, err := g.identityCache.GetUser(ctx, userID.GetOpaqueId()); err != nil {
g.logger.Error().Err(err).Msg("could not get user")
continue
} else {
shareCreator = &libregraph.Identity{
DisplayName: user.GetDisplayName(),
Id: libregraph.PtrString(user.GetId()),
}
}
}

if cTime := share.GetCtime(); cTime != nil {
driveItem.CreatedDateTime = libregraph.PtrTime(cs3TimestampToTime(cTime))
}

driveItem.ETag = libregraph.PtrString(strings.Trim(statResponse.GetInfo().GetEtag(), "\""))

if id := share.GetId().GetOpaqueId(); id != "" {
driveItem.Id = libregraph.PtrString(id)
}

if mTime := share.GetMtime(); mTime != nil {
driveItem.LastModifiedDateTime = libregraph.PtrTime(cs3TimestampToTime(mTime))
}

if name := resourceInfo.GetName(); name != "" {
driveItem.Name = libregraph.PtrString(name)
}

{
addParentReference := false
parentReference := &libregraph.ItemReference{}

if id := share.GetId().GetOpaqueId(); id != "" {
parentReference.DriveId = libregraph.PtrString(id)
addParentReference = true
}

if addParentReference {
driveItem.ParentReference = parentReference
}
}

{
remoteItem := &libregraph.RemoteItem{}

if id := resourceInfo.GetId(); id != nil {
remoteItem.Id = libregraph.PtrString(storagespace.FormatResourceID(*id))
}

if mTime := resourceInfo.GetMtime(); mTime != nil {
remoteItem.LastModifiedDateTime = libregraph.PtrTime(cs3TimestampToTime(mTime))
}

if name := resourceInfo.GetName(); name != "" {
remoteItem.Name = libregraph.PtrString(name)
}

// fixMe:
// - negative permission could distort the size, am i right?
remoteItem.Size = libregraph.PtrInt64(int64(resourceInfo.GetSize()))

remoteItem.CreatedBy = &libregraph.IdentitySet{
User: driveOwner,
}

{

addFileSystemInfo := false
fileSystemInfo := &libregraph.FileSystemInfo{}

if cTime := share.GetCtime(); cTime != nil {
// fixMe:
// - ms uses the root resource ctime for that,
// the stat response does not contain any information about this, use share instead?
fileSystemInfo.CreatedDateTime = libregraph.PtrTime(cs3TimestampToTime(cTime))
addFileSystemInfo = true
}

if mTime := resourceInfo.GetMtime(); mTime != nil {
fileSystemInfo.LastModifiedDateTime = libregraph.PtrTime(cs3TimestampToTime(mTime))
addFileSystemInfo = true
}

if addFileSystemInfo {
remoteItem.FileSystemInfo = fileSystemInfo
}
}

switch resourceInfo.GetType() {
case storageprovider.ResourceType_RESOURCE_TYPE_CONTAINER:
remoteItem.Folder = &libregraph.Folder{}
case storageprovider.ResourceType_RESOURCE_TYPE_FILE:
openGraphFile := &libregraph.OpenGraphFile{}

if mimeType := resourceInfo.GetMimeType(); mimeType != "" {
openGraphFile.MimeType = libregraph.PtrString(mimeType)
}

remoteItem.File = openGraphFile
case storageprovider.ResourceType_RESOURCE_TYPE_INVALID:
g.logger.Error().Msg("invalid resource type")
continue
}

{
addShared := false
shared := &libregraph.Shared{
Owner: &libregraph.IdentitySet{
User: shareCreator,
},
SharedBy: &libregraph.IdentitySet{
User: shareCreator,
},
}

if cTime := share.GetCtime(); cTime != nil {
shared.SharedDateTime = libregraph.PtrTime(cs3TimestampToTime(cTime))
addShared = true
}

if shareCreator != nil {
shared.Owner.User = shareCreator
shared.SharedBy.User = shareCreator
addShared = true
}

if addShared {
remoteItem.Shared = shared
}
}

driveItem.RemoteItem = remoteItem
}

driveItems = append(driveItems, *driveItem)
}

return driveItems, nil
}