Skip to content

Commit

Permalink
Create OCM share from sciencemesh service (cs3org#3695)
Browse files Browse the repository at this point in the history
* create share from sciencemesh service

* make /create-share unprotected

* add changelog

* fix linter!

* Update internal/http/services/sciencemesh/share.go

Co-authored-by: Giuseppe Lo Presti <giuseppe.lopresti@cern.ch>

* Update internal/http/services/sciencemesh/share.go

Co-authored-by: Giuseppe Lo Presti <giuseppe.lopresti@cern.ch>

* Update internal/http/services/sciencemesh/sciencemesh.go

Co-authored-by: Giuseppe Lo Presti <giuseppe.lopresti@cern.ch>

* removed old code

* fix import names

---------

Co-authored-by: Giuseppe Lo Presti <giuseppe.lopresti@cern.ch>
  • Loading branch information
gmgigi96 and glpatcern committed Jun 5, 2023
1 parent 7212ab2 commit 29787c9
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 1 deletion.
4 changes: 4 additions & 0 deletions changelog/unreleased/ocm-share-create-sm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Enhancement: Create OCM share from sciencemesh service

https://github.com/cs3org/reva/pull/3695
https://github.com/pondersource/sciencemesh-php/issues/166
6 changes: 5 additions & 1 deletion internal/http/services/sciencemesh/sciencemesh.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ func (s *svc) routerInit() error {
if err := providersHandler.init(s.conf); err != nil {
return err
}
sharesHandler := new(sharesHandler)
if err := sharesHandler.init(s.conf); err != nil {
return err
}

appsHandler := new(appsHandler)
if err := appsHandler.init(s.conf); err != nil {
Expand All @@ -106,8 +110,8 @@ func (s *svc) routerInit() error {
s.router.Post("/accept-invite", tokenHandler.AcceptInvite)
s.router.Get("/find-accepted-users", tokenHandler.FindAccepted)
s.router.Get("/list-providers", providersHandler.ListProviders)
s.router.Post("/create-share", sharesHandler.CreateShare)
s.router.Post("/open-in-app", appsHandler.OpenInApp)

return nil
}

Expand Down
176 changes: 176 additions & 0 deletions internal/http/services/sciencemesh/share.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

package sciencemesh

import (
"encoding/json"
"errors"
"mime"
"net/http"

appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
providerpb "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/internal/http/services/owncloud/ocs/conversions"
"github.com/cs3org/reva/internal/http/services/reqres"
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/ocm/share"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/go-playground/validator/v10"
)

var validate = validator.New()

type sharesHandler struct {
gatewayClient gateway.GatewayAPIClient
}

func (h *sharesHandler) init(c *config) error {
var err error
h.gatewayClient, err = pool.GetGatewayServiceClient(pool.Endpoint(c.GatewaySvc))
return err
}

type createShareRequest struct {
SourcePath string `json:"sourcePath" validate:"required"`
TargetPath string `json:"targetPath" validate:"required"`
Type string `json:"type"`
Role string `json:"role" validate:"oneof=viewer editor"`
RecipientUsername string `json:"recipientUsername" validate:"required"`
RecipientHost string `json:"recipientHost" validate:"required"`
}

// CreateShare creates an OCM share.
func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
log := appctx.GetLogger(r.Context())

req, err := getCreateShareRequest(r)
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "invalid parameters", err)
return
}

ctx := r.Context()

statRes, err := h.gatewayClient.Stat(ctx, &providerpb.StatRequest{
Ref: &providerpb.Reference{
Path: req.SourcePath,
},
})
switch {
case err != nil:
reqres.WriteError(w, r, reqres.APIErrorServerError, "unexpected error", err)
return
case statRes.Status.Code == rpc.Code_CODE_NOT_FOUND:
reqres.WriteError(w, r, reqres.APIErrorNotFound, statRes.Status.Message, nil)
return
case statRes.Status.Code != rpc.Code_CODE_OK:
reqres.WriteError(w, r, reqres.APIErrorServerError, statRes.Status.Message, errors.New(statRes.Status.Message))
return
}

recipientProviderInfo, err := h.gatewayClient.GetInfoByDomain(ctx, &ocmprovider.GetInfoByDomainRequest{
Domain: req.RecipientHost,
})
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc get invite by domain info request", err)
return
}
if recipientProviderInfo.Status.Code != rpc.Code_CODE_OK {
reqres.WriteError(w, r, reqres.APIErrorNotFound, recipientProviderInfo.Status.Message, errors.New(recipientProviderInfo.Status.Message))
return
}

perm, viewMode := getPermissionsByRole(req.Role)

shareRes, err := h.gatewayClient.CreateOCMShare(ctx, &ocm.CreateOCMShareRequest{
ResourceId: statRes.Info.Id,
Grantee: &providerpb.Grantee{
Type: providerpb.GranteeType_GRANTEE_TYPE_USER,
Id: &providerpb.Grantee_UserId{
UserId: &userpb.UserId{
Idp: req.RecipientHost,
OpaqueId: req.RecipientUsername,
},
},
},
RecipientMeshProvider: recipientProviderInfo.ProviderInfo,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(perm),
share.NewWebappAccessMethod(viewMode),
},
})
switch {
case err != nil:
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc CreateOCMShare", err)
return
case shareRes.Status.Code == rpc.Code_CODE_NOT_FOUND:
reqres.WriteError(w, r, reqres.APIErrorNotFound, shareRes.Status.Message, nil)
return
case shareRes.Status.Code == rpc.Code_CODE_ALREADY_EXISTS:
reqres.WriteError(w, r, reqres.APIErrorAlreadyExist, shareRes.Status.Message, nil)
return
case shareRes.Status.Code != rpc.Code_CODE_OK:
reqres.WriteError(w, r, reqres.APIErrorAlreadyExist, shareRes.Status.Message, errors.New(shareRes.Status.Message))
return
}

if err := json.NewEncoder(w).Encode(shareRes); err != nil {
log.Error().Err(err).Msg("error encoding response")
w.WriteHeader(http.StatusInternalServerError)
return
}

w.WriteHeader(http.StatusOK)
}

func getPermissionsByRole(role string) (*providerpb.ResourcePermissions, appprovider.ViewMode) {
switch role {
case "viewer":
return conversions.NewViewerRole().CS3ResourcePermissions(), appprovider.ViewMode_VIEW_MODE_READ_ONLY
case "editor":
return conversions.NewEditorRole().CS3ResourcePermissions(), appprovider.ViewMode_VIEW_MODE_READ_WRITE
}
return nil, 0
}

func getCreateShareRequest(r *http.Request) (*createShareRequest, error) {
var req createShareRequest
contentType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err == nil && contentType == "application/json" {
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, err
}
} else {
return nil, errors.New("body request not recognised")
}
// set defaults
if req.Type == "" {
req.Type = "viewer"
}
// validate the request
if err := validate.Struct(req); err != nil {
return nil, err
}
return &req, nil
}

0 comments on commit 29787c9

Please sign in to comment.