feat(graph): add GET /drive/<id>/root/permissions suppport

Partial Fix: #8351
This commit is contained in:
Ralf Haferkamp
2024-03-26 18:16:24 +01:00
committed by Ralf Haferkamp
parent 2a5b406963
commit 57b70a08ee
4 changed files with 156 additions and 5 deletions

View File

@@ -139,6 +139,63 @@ func (_c *DriveItemPermissionsProvider_ListPermissions_Call) RunAndReturn(run fu
return _c
}
// ListSpaceRootPermissions provides a mock function with given fields: ctx, driveID
func (_m *DriveItemPermissionsProvider) ListSpaceRootPermissions(ctx context.Context, driveID providerv1beta1.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error) {
ret := _m.Called(ctx, driveID)
if len(ret) == 0 {
panic("no return value specified for ListSpaceRootPermissions")
}
var r0 libregraph.CollectionOfPermissionsWithAllowedValues
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, providerv1beta1.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error)); ok {
return rf(ctx, driveID)
}
if rf, ok := ret.Get(0).(func(context.Context, providerv1beta1.ResourceId) libregraph.CollectionOfPermissionsWithAllowedValues); ok {
r0 = rf(ctx, driveID)
} else {
r0 = ret.Get(0).(libregraph.CollectionOfPermissionsWithAllowedValues)
}
if rf, ok := ret.Get(1).(func(context.Context, providerv1beta1.ResourceId) error); ok {
r1 = rf(ctx, driveID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// DriveItemPermissionsProvider_ListSpaceRootPermissions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListSpaceRootPermissions'
type DriveItemPermissionsProvider_ListSpaceRootPermissions_Call struct {
*mock.Call
}
// ListSpaceRootPermissions is a helper method to define mock.On call
// - ctx context.Context
// - driveID providerv1beta1.ResourceId
func (_e *DriveItemPermissionsProvider_Expecter) ListSpaceRootPermissions(ctx interface{}, driveID interface{}) *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call {
return &DriveItemPermissionsProvider_ListSpaceRootPermissions_Call{Call: _e.mock.On("ListSpaceRootPermissions", ctx, driveID)}
}
func (_c *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call) Run(run func(ctx context.Context, driveID providerv1beta1.ResourceId)) *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(providerv1beta1.ResourceId))
})
return _c
}
func (_c *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call) Return(_a0 libregraph.CollectionOfPermissionsWithAllowedValues, _a1 error) *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call) RunAndReturn(run func(context.Context, providerv1beta1.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error)) *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call {
_c.Call.Return(run)
return _c
}
// SpaceRootInvite provides a mock function with given fields: ctx, driveID, invite
func (_m *DriveItemPermissionsProvider) SpaceRootInvite(ctx context.Context, driveID providerv1beta1.ResourceId, invite libregraph.DriveItemInvite) (libregraph.Permission, error) {
ret := _m.Called(ctx, driveID, invite)

View File

@@ -26,10 +26,13 @@ import (
"github.com/owncloud/ocis/v2/services/graph/pkg/validate"
)
const invalidIdMsg = "invalid driveID or itemID"
type DriveItemPermissionsProvider interface {
Invite(ctx context.Context, resourceId storageprovider.ResourceId, invite libregraph.DriveItemInvite) (libregraph.Permission, error)
SpaceRootInvite(ctx context.Context, driveID storageprovider.ResourceId, invite libregraph.DriveItemInvite) (libregraph.Permission, error)
ListPermissions(ctx context.Context, itemID storageprovider.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error)
ListSpaceRootPermissions(ctx context.Context, driveID storageprovider.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error)
}
// DriveItemPermissionsService contains the production business logic for everything that relates to permissions on drive items.
@@ -263,6 +266,27 @@ func (s DriveItemPermissionsService) ListPermissions(ctx context.Context, itemID
return collectionOfPermissions, nil
}
// ListSpaceRootPermissions handles ListPermissions request on project spaces
func (s DriveItemPermissionsService) ListSpaceRootPermissions(ctx context.Context, driveID storageprovider.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error) {
collectionOfPermissions := libregraph.CollectionOfPermissionsWithAllowedValues{}
gatewayClient, err := s.gatewaySelector.Next()
if err != nil {
return collectionOfPermissions, err
}
space, err := utils.GetSpace(ctx, storagespace.FormatResourceID(driveID), gatewayClient)
if err != nil {
return collectionOfPermissions, err
}
if space.SpaceType != "project" {
return collectionOfPermissions, errorcode.New(errorcode.InvalidRequest, "unsupported space type")
}
rootResourceID := space.GetRoot()
return s.ListPermissions(ctx, *rootResourceID)
}
// DriveItemPermissionsService is the api that registers the http endpoints which expose needed operation to the graph api.
// the business logic is delegated to the permissions service and further down to the cs3 client.
type DriveItemPermissionsApi struct {
@@ -281,9 +305,8 @@ func NewDriveItemPermissionsApi(driveItemPermissionService DriveItemPermissionsP
func (api DriveItemPermissionsApi) Invite(w http.ResponseWriter, r *http.Request) {
_, itemID, err := GetDriveAndItemIDParam(r, &api.logger)
if err != nil {
msg := "invalid driveID or itemID"
api.logger.Debug().Err(err).Msg(msg)
errorcode.InvalidRequest.Render(w, r, http.StatusUnprocessableEntity, msg)
api.logger.Debug().Err(err).Msg(invalidIdMsg)
errorcode.InvalidRequest.Render(w, r, http.StatusUnprocessableEntity, invalidIdMsg)
return
}
@@ -348,8 +371,7 @@ func (api DriveItemPermissionsApi) SpaceRootInvite(w http.ResponseWriter, r *htt
func (api DriveItemPermissionsApi) ListPermissions(w http.ResponseWriter, r *http.Request) {
_, itemID, err := GetDriveAndItemIDParam(r, &api.logger)
if err != nil {
msg := "invalid driveID or itemID"
api.logger.Debug().Err(err).Msg(msg)
api.logger.Debug().Err(err).Msg(invalidIdMsg)
errorcode.RenderError(w, r, err)
return
}
@@ -365,3 +387,24 @@ func (api DriveItemPermissionsApi) ListPermissions(w http.ResponseWriter, r *htt
render.Status(r, http.StatusOK)
render.JSON(w, r, permissions)
}
func (api DriveItemPermissionsApi) ListSpaceRootPermissions(w http.ResponseWriter, r *http.Request) {
driveID, err := parseIDParam(r, "driveID")
if err != nil {
msg := "could not parse driveID"
api.logger.Debug().Err(err).Msg(msg)
errorcode.InvalidRequest.Render(w, r, http.StatusUnprocessableEntity, msg)
return
}
ctx := r.Context()
permissions, err := api.driveItemPermissionsService.ListSpaceRootPermissions(ctx, driveID)
if err != nil {
errorcode.RenderError(w, r, err)
return
}
render.Status(r, http.StatusOK)
render.JSON(w, r, permissions)
}

View File

@@ -369,6 +369,54 @@ var _ = Describe("DriveItemPermissionsService", func() {
Expect(len(permissions.LibreGraphPermissionsRolesAllowedValues)).ToNot(BeZero())
Expect(len(permissions.Value)).To(Equal(2))
})
})
Describe("ListSpaceRootPermissions", func() {
var (
listSpacesResponse *provider.ListStorageSpacesResponse
driveId provider.ResourceId
listPublicSharesResponse *link.ListPublicSharesResponse
)
BeforeEach(func() {
driveId = provider.ResourceId{
StorageId: "1",
SpaceId: "2",
}
listSpacesResponse = &provider.ListStorageSpacesResponse{
Status: status.NewOK(ctx),
StorageSpaces: []*provider.StorageSpace{
{
Id: &provider.StorageSpaceId{
OpaqueId: "2",
},
},
},
}
listPublicSharesResponse = &link.ListPublicSharesResponse{
Status: status.NewOK(ctx),
}
})
It("adds a user to a space as expected (happy path)", func() {
listSpacesResponse.StorageSpaces[0].SpaceType = "project"
listSpacesResponse.StorageSpaces[0].Root = &provider.ResourceId{
StorageId: "1",
SpaceId: "2",
OpaqueId: "2",
}
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(listSpacesResponse, nil)
gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(listPublicSharesResponse, nil)
statResponse.Info = &provider.ResourceInfo{
Id: listSpacesResponse.StorageSpaces[0].Root,
PermissionSet: roleconversions.NewViewerRole(false).CS3ResourcePermissions(),
}
gatewayClient.On("Stat", mock.Anything, mock.Anything).Return(statResponse, nil)
permissions, err := driveItemPermissionsService.ListSpaceRootPermissions(context.Background(), driveId)
Expect(err).ToNot(HaveOccurred())
Expect(len(permissions.LibreGraphPermissionsActionsAllowedValues)).ToNot(BeZero())
})
})
})

View File

@@ -241,6 +241,9 @@ func NewService(opts ...Option) (Graph, error) {
r.Route("/root", func(r chi.Router) {
r.Post("/children", drivesDriveItemApi.CreateDriveItem)
r.Post("/invite", driveItemPermissionsApi.SpaceRootInvite)
r.Route("/permissions", func(r chi.Router) {
r.Get("/", driveItemPermissionsApi.ListSpaceRootPermissions)
})
})
r.Route("/items/{itemID}", func(r chi.Router) {
r.Delete("/", drivesDriveItemApi.DeleteDriveItem)