diff --git a/services/graph/pkg/service/v0/service.go b/services/graph/pkg/service/v0/service.go index fb5e490851..3396a2d1da 100644 --- a/services/graph/pkg/service/v0/service.go +++ b/services/graph/pkg/service/v0/service.go @@ -106,6 +106,7 @@ type Service interface { //nolint:interfacebloat GetDrivesV1(w http.ResponseWriter, r *http.Request) GetDrivesV1Beta1(w http.ResponseWriter, r *http.Request) GetSingleDrive(w http.ResponseWriter, r *http.Request) + GetUserDrive(w http.ResponseWriter, r *http.Request) GetAllDrivesV1(w http.ResponseWriter, r *http.Request) GetAllDrivesV1Beta1(w http.ResponseWriter, r *http.Request) CreateDrive(w http.ResponseWriter, r *http.Request) diff --git a/services/graph/pkg/service/v0/users.go b/services/graph/pkg/service/v0/users.go index 18b154546b..f9c29b17eb 100644 --- a/services/graph/pkg/service/v0/users.go +++ b/services/graph/pkg/service/v0/users.go @@ -147,13 +147,15 @@ func (g Graph) GetUserDrive(w http.ResponseWriter, r *http.Request) { log = log.With().Str("userID", userID).Logger() - _, expandPermissions, err := parseDriveRequest(r) + odataReq, expandPermissions, err := parseDriveRequest(r) if err != nil { log.Debug().Err(err).Msg("could not get drives: error parsing odata request") errorcode.RenderError(w, r, err) return } + // Empty {user-id} is the current user (/me/drive); a non-empty one may be + // an id or a name, so resolve it to the opaque id the filter expects. if userID == "" { u, ok := revactx.ContextGetUser(ctx) if !ok { @@ -162,6 +164,14 @@ func (g Graph) GetUserDrive(w http.ResponseWriter, r *http.Request) { return } userID = u.GetId().GetOpaqueId() + } else { + user, err := g.identityBackend.GetUser(ctx, userID, odataReq) + if err != nil { + log.Debug().Err(err).Str("userID", userID).Msg("could not get user drive: failed to resolve user") + errorcode.RenderError(w, r, err) + return + } + userID = user.GetId() } log.Debug().Msg("calling list storage spaces with user and personal filter") diff --git a/services/graph/pkg/service/v0/users_test.go b/services/graph/pkg/service/v0/users_test.go index 5db85f90f8..3f6eafce20 100644 --- a/services/graph/pkg/service/v0/users_test.go +++ b/services/graph/pkg/service/v0/users_test.go @@ -115,6 +115,43 @@ var _ = Describe("Users", func() { Expect(err).ToNot(HaveOccurred()) }) + Describe("GetUserDrive", func() { + It("resolves the user by name before looking up the personal space", func() { + user := &libregraph.User{} + user.SetId("user1") + + // A name in the path must be resolved to the user id via the + // identity backend before the storage space filter runs. + permissionService.On("GetPermissionByID", mock.Anything, mock.Anything).Return(&settings.GetPermissionByIDResponse{}, nil) + identityBackend.On("GetUser", mock.Anything, "alice", mock.Anything).Return(user, nil) + gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything, mock.Anything).Return(&provider.ListStorageSpacesResponse{ + Status: status.NewOK(ctx), + StorageSpaces: []*provider.StorageSpace{ + { + Id: &provider.StorageSpaceId{OpaqueId: "drive1"}, + Root: &provider.ResourceId{StorageId: "storage", SpaceId: "space", OpaqueId: "space"}, + SpaceType: "personal", + }, + }, + }, nil) + gatewayClient.On("GetQuota", mock.Anything, mock.Anything, mock.Anything).Return(&provider.GetQuotaResponse{ + Status: status.NewOK(ctx), + TotalBytes: 10, + }, nil) + valueService.On("GetValueByUniqueIdentifiers", mock.Anything, mock.Anything, mock.Anything). + Return(&settings.GetValueResponse{}, nil) + + r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/users/alice/drive", nil) + rctx := chi.NewRouteContext() + rctx.URLParams.Add("userID", "alice") + r = r.WithContext(context.WithValue(revactx.ContextSetUser(ctx, currentUser), chi.RouteCtxKey, rctx)) + svc.GetUserDrive(rr, r) + + Expect(rr.Code).To(Equal(http.StatusOK)) + identityBackend.AssertCalled(GinkgoT(), "GetUser", mock.Anything, "alice", mock.Anything) + }) + }) + Describe("GetMe", func() { It("handles missing user", func() { r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me", nil)