diff --git a/changelog/unreleased/space-membership.md b/changelog/unreleased/space-membership.md new file mode 100644 index 0000000000..a07e4481fb --- /dev/null +++ b/changelog/unreleased/space-membership.md @@ -0,0 +1,6 @@ +Enhancement: Implement space membership endpoints + +Implemented endpoints to add and remove members to spaces. + +https://github.com/owncloud/ocis/issues/2740 +https://github.com/cs3org/reva/pull/2250 diff --git a/internal/http/services/owncloud/ocs/conversions/main.go b/internal/http/services/owncloud/ocs/conversions/main.go index 33bd953182..02f1b8566b 100644 --- a/internal/http/services/owncloud/ocs/conversions/main.go +++ b/internal/http/services/owncloud/ocs/conversions/main.go @@ -51,7 +51,9 @@ const ( // ShareTypeFederatedCloudShare represents a federated share ShareTypeFederatedCloudShare ShareType = 6 - ShareTypeSpaceMembership ShareType = 7 + + // ShareTypeSpaceMembership represents an action regarding space members + ShareTypeSpaceMembership ShareType = 7 ) // ResourceType indicates the OCS type of the resource diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go index 5e5115e23e..347e4a8ac4 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go @@ -25,7 +25,6 @@ import ( "strconv" rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" - collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" @@ -206,32 +205,10 @@ func (h *Handler) isPublicShare(r *http.Request, oid string) bool { }) if err != nil { logger.Err(err) - } - - if psRes.GetShare() != nil { - return true - } - - // check if we have a user share - uRes, err := client.GetShare(r.Context(), &collaboration.GetShareRequest{ - Ref: &collaboration.ShareReference{ - Spec: &collaboration.ShareReference_Id{ - Id: &collaboration.ShareId{ - OpaqueId: oid, - }, - }, - }, - }) - if err != nil { - logger.Err(err) - } - - if uRes.GetShare() != nil { return false } - // TODO token is neither a public or a user share. - return false + return psRes.GetShare() != nil } func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shareID string) { diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go index c243e90771..f1937658ca 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go @@ -507,11 +507,15 @@ func (h *Handler) updateShare(w http.ResponseWriter, r *http.Request, shareID st // RemoveShare handles DELETE requests on /apps/files_sharing/api/v1/shares/(shareid) func (h *Handler) RemoveShare(w http.ResponseWriter, r *http.Request) { shareID := chi.URLParam(r, "shareid") - if h.isPublicShare(r, shareID) { + switch { + case h.isPublicShare(r, shareID): h.removePublicShare(w, r, shareID) - return + case h.isUserShare(r, shareID): + h.removeUserShare(w, r, shareID) + default: + // The request is a remove space member request. + h.removeSpaceMember(w, r, shareID) } - h.removeUserShare(w, r, shareID) } // ListShares handles GET requests on /apps/files_sharing/api/v1/shares diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/spaces.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/spaces.go index 182815f402..814dc9ef84 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/spaces.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/spaces.go @@ -20,27 +20,59 @@ package shares import ( "context" + "fmt" "net/http" + groupv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1" userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1" "github.com/cs3org/reva/internal/http/services/owncloud/ocs/conversions" "github.com/cs3org/reva/internal/http/services/owncloud/ocs/response" + "github.com/cs3org/reva/pkg/appctx" "github.com/cs3org/reva/pkg/errtypes" "github.com/cs3org/reva/pkg/rgrpc/status" "github.com/cs3org/reva/pkg/rgrpc/todo/pool" + "github.com/cs3org/reva/pkg/utils" "github.com/pkg/errors" ) -func (h *Handler) addSpaceMember(w http.ResponseWriter, r *http.Request, info *provider.ResourceInfo, role *conversions.Role, roleVal []byte) { - ctx := r.Context() +func (h *Handler) getGrantee(ctx context.Context, name string) (provider.Grantee, error) { + log := appctx.GetLogger(ctx) client, err := pool.GetGatewayServiceClient(h.gatewayAddr) if err != nil { - response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error getting grpc gateway client", err) - return + return provider.Grantee{}, err + } + userRes, err := client.GetUserByClaim(ctx, &userpb.GetUserByClaimRequest{ + Claim: "username", + Value: name, + }) + if err == nil && userRes.Status.Code == rpc.Code_CODE_OK { + return provider.Grantee{ + Type: provider.GranteeType_GRANTEE_TYPE_USER, + Id: &provider.Grantee_UserId{UserId: userRes.User.Id}, + }, nil } + log.Debug().Str("name", name).Msg("no user found") + + groupRes, err := client.GetGroupByClaim(ctx, &groupv1beta1.GetGroupByClaimRequest{ + Claim: "group_name", + Value: name, + }) + if err == nil && groupRes.Status.Code == rpc.Code_CODE_OK { + return provider.Grantee{ + Type: provider.GranteeType_GRANTEE_TYPE_GROUP, + Id: &provider.Grantee_GroupId{GroupId: groupRes.Group.Id}, + }, nil + } + log.Debug().Str("name", name).Msg("no group found") + + return provider.Grantee{}, fmt.Errorf("no grantee found with name %s", name) +} + +func (h *Handler) addSpaceMember(w http.ResponseWriter, r *http.Request, info *provider.ResourceInfo, role *conversions.Role, roleVal []byte) { + ctx := r.Context() shareWith := r.FormValue("shareWith") if shareWith == "" { @@ -48,17 +80,9 @@ func (h *Handler) addSpaceMember(w http.ResponseWriter, r *http.Request, info *p return } - userRes, err := client.GetUserByClaim(ctx, &userpb.GetUserByClaimRequest{ - Claim: "username", - Value: shareWith, - }) + grantee, err := h.getGrantee(ctx, shareWith) if err != nil { - response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error searching recipient", err) - return - } - - if userRes.Status.Code != rpc.Code_CODE_OK { - response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "user not found", err) + response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "error getting grantee", err) return } @@ -79,10 +103,7 @@ func (h *Handler) addSpaceMember(w http.ResponseWriter, r *http.Request, info *p addGrantRes, err := providerClient.AddGrant(ctx, &provider.AddGrantRequest{ Ref: ref, Grant: &provider.Grant{ - Grantee: &provider.Grantee{ - Type: provider.GranteeType_GRANTEE_TYPE_USER, - Id: &provider.Grantee_UserId{UserId: userRes.User.Id}, - }, + Grantee: &grantee, Permissions: role.CS3ResourcePermissions(), }, }) @@ -94,6 +115,57 @@ func (h *Handler) addSpaceMember(w http.ResponseWriter, r *http.Request, info *p response.WriteOCSSuccess(w, r, nil) } +func (h *Handler) removeSpaceMember(w http.ResponseWriter, r *http.Request, spaceID string) { + ctx := r.Context() + + shareWith := r.URL.Query().Get("shareWith") + if shareWith == "" { + response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "missing shareWith", nil) + return + } + + grantee, err := h.getGrantee(ctx, shareWith) + if err != nil { + response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "error getting grantee", err) + return + } + + ref, err := utils.ParseStorageSpaceReference(spaceID) + if err != nil { + response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "could not parse space id", err) + return + } + + providers, err := h.findProviders(ctx, &ref) + if err != nil { + response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "error getting storage provider", err) + return + } + + providerClient, err := h.getStorageProviderClient(providers[0]) + if err != nil { + response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "error getting storage provider", err) + return + } + + removeGrantRes, err := providerClient.RemoveGrant(ctx, &provider.RemoveGrantRequest{ + Ref: &ref, + Grant: &provider.Grant{ + Grantee: &grantee, + }, + }) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error removing grant", err) + return + } + if removeGrantRes.Status.Code != rpc.Code_CODE_OK { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error removing grant", err) + return + } + + response.WriteOCSSuccess(w, r, nil) +} + func (h *Handler) getStorageProviderClient(p *registry.ProviderInfo) (provider.ProviderAPIClient, error) { c, err := pool.GetStorageProviderServiceClient(p.Address) if err != nil { diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go index 22cc7ef477..76204897d7 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go @@ -85,6 +85,30 @@ func (h *Handler) createUserShare(w http.ResponseWriter, r *http.Request, statIn h.createCs3Share(ctx, w, r, c, createShareReq, statInfo) } +func (h *Handler) isUserShare(r *http.Request, oid string) bool { + logger := appctx.GetLogger(r.Context()) + client, err := pool.GetGatewayServiceClient(h.gatewayAddr) + if err != nil { + logger.Err(err) + } + + getShareRes, err := client.GetShare(r.Context(), &collaboration.GetShareRequest{ + Ref: &collaboration.ShareReference{ + Spec: &collaboration.ShareReference_Id{ + Id: &collaboration.ShareId{ + OpaqueId: oid, + }, + }, + }, + }) + if err != nil { + logger.Err(err) + return false + } + + return getShareRes.GetShare() != nil +} + func (h *Handler) removeUserShare(w http.ResponseWriter, r *http.Request, shareID string) { ctx := r.Context()