diff --git a/internal/grpc/services/appprovider/appprovider.go b/internal/grpc/services/appprovider/appprovider.go index c12acfca78c..8dd446d704c 100644 --- a/internal/grpc/services/appprovider/appprovider.go +++ b/internal/grpc/services/appprovider/appprovider.go @@ -142,24 +142,6 @@ func getProvider(c *config) (app.Provider, error) { return nil, errtypes.NotFound("driver not found: " + c.Driver) } -func (s *service) CreateFileForApp(ctx context.Context, req *providerpb.CreateFileForAppRequest) (*providerpb.CreateFileForAppResponse, error) { - fileInfo, err := s.provider.CreateFile(ctx, req.Ref, req.Filename, req.Template) - if err != nil { - err := errors.Wrap(err, "appprovider: error calling CreateFile") - res := &providerpb.CreateFileForAppResponse{ - Status: status.NewInternal(ctx, err, "error creating file"), - } - return res, nil - } - - res := &providerpb.CreateFileForAppResponse{ - Status: status.NewOK(ctx), - ResourceInfo: fileInfo, - } - return res, nil - -} - func (s *service) OpenInApp(ctx context.Context, req *providerpb.OpenInAppRequest) (*providerpb.OpenInAppResponse, error) { appURL, err := s.provider.GetAppURL(ctx, req.ResourceInfo, req.ViewMode, req.AccessToken) if err != nil { diff --git a/internal/grpc/services/gateway/appprovider.go b/internal/grpc/services/gateway/appprovider.go index bd577f72ad8..b834968ced5 100644 --- a/internal/grpc/services/gateway/appprovider.go +++ b/internal/grpc/services/gateway/appprovider.go @@ -42,51 +42,6 @@ import ( "google.golang.org/grpc/metadata" ) -func (s *svc) CreateFileForApp(ctx context.Context, req *providerpb.CreateFileForAppRequest) (*providerpb.CreateFileForAppResponse, error) { - _, st := s.getPath(ctx, req.Ref) - if st.Code != rpc.Code_CODE_OK { - if st.Code == rpc.Code_CODE_NOT_FOUND { - return &providerpb.CreateFileForAppResponse{ - Status: status.NewNotFound(ctx, "gateway: container resource not found:"+req.Ref.String()), - }, nil - } - return &providerpb.CreateFileForAppResponse{ - Status: st, - }, nil - } - - // TODO identify app provider: take the GetDefaultProviderForMimeType for the given file extension - // provider, err := s.getDefaultAppProvider(ctx, req.Ref.path) - // if err != nil { - // err = errors.Wrap(err, "gateway: error calling findAppProvider") - // var st *rpc.Status - // if _, ok := err.(errtypes.IsNotFound); ok { - // st = status.NewNotFound(ctx, "app provider not found") - // } else { - // st = status.NewInternal(ctx, err, "error searching for app provider") - // } - // return &providerpb.CreateFileForAppResponse{ - // Status: st, - // }, nil - // } - - // appProviderClient, err := pool.GetAppProviderClient(provider.Address) - // if err != nil { - // err = errors.Wrap(err, "gateway: error calling GetAppProviderClient") - // return &providerpb.CreateFileForAppResponse{ - // Status: status.NewInternal(ctx, err, "error getting appprovider client"), - // }, nil - // } - - // res, err := appProviderClient.CreateFileForApp(ctx, req) - // if err != nil { - // return nil, errors.Wrap(err, "gateway: error calling CreateFileForApp") - // } - res := &providerpb.CreateFileForAppResponse{} - - return res, nil -} - func (s *svc) OpenInApp(ctx context.Context, req *gateway.OpenInAppRequest) (*providerpb.OpenInAppResponse, error) { p, st := s.getPath(ctx, req.Ref) if st.Code != rpc.Code_CODE_OK { diff --git a/internal/http/services/appprovider/appprovider.go b/internal/http/services/appprovider/appprovider.go index 71d55217e51..4a28c48c756 100644 --- a/internal/http/services/appprovider/appprovider.go +++ b/internal/http/services/appprovider/appprovider.go @@ -23,21 +23,25 @@ import ( "encoding/base64" "encoding/json" "net/http" + "path" + "strconv" "strings" "unicode/utf8" - appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1" appregistry "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1" gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + "github.com/cs3org/reva/internal/http/services/datagateway" "github.com/cs3org/reva/internal/http/services/ocmd" + "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/rhttp/global" "github.com/cs3org/reva/pkg/rhttp/router" "github.com/cs3org/reva/pkg/sharedconf" "github.com/cs3org/reva/pkg/utils" + "github.com/google/uuid" ua "github.com/mileusna/useragent" "github.com/mitchellh/mapstructure" "github.com/pkg/errors" @@ -124,13 +128,29 @@ func (s *svc) handleNew(w http.ResponseWriter, r *http.Request) { return } - createReq := appprovider.CreateFileForAppRequest{ - Ref: &provider.Reference{ResourceId: info.Id}, - Filename: r.URL.Query().Get("filename"), + if r.URL.Query().Get("template") != "" { + // TODO in the future we want to create a file out of the given template + ocmd.WriteError(w, r, ocmd.APIErrorServerError, "Template not implemented", + status.NewUnimplemented(ctx, errtypes.NotSupported("Templates are not yet supported")) + return + } + } + + // Create empty file via storageprovider: obtain the HTTP URL for a PUT + createReq := &storageprovider.InitiateFileUploadRequest{ + Ref: path.Join(info.path, r.URL.Query().Get("filename")), + Opaque: &typespb.Opaque{ + Map: map[string]*typespb.OpaqueEntry{ + "Upload-Length": { + Decoder: "plain", + Value: []byte(strconv.FormatInt(0, 10)), + }, + }, + }, } - createRes, err := client.CreateFileForApp(ctx, &createReq) + createRes, err := client.InitiateFileUpload(ctx, createReq) if err != nil { - ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error creating resource", err) + ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error calling InitiateFileUpload", err) return } if createRes.Status.Code != rpc.Code_CODE_OK { @@ -138,7 +158,35 @@ func (s *svc) handleNew(w http.ResponseWriter, r *http.Request) { return } - js, err := json.Marshal(createRes.ResourceInfo) + // Do a HTTP PUT with an empty body + var ep, token string + for _, p := range createRes.Protocols { + if p.Protocol == "simple" { + ep, token = p.UploadEndpoint, p.Token + } + } + httpReq, err := rhttp.NewRequest(ctx, http.MethodPut, ep, nil) + if err != nil { + ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error executing PUT", err) + return + } + + httpReq.Header.Set(datagateway.TokenTransportHeader, token) + httpRes, err := s.client.Do(httpReq) + if err != nil { + log.Error().Err(err).Msg("error doing PUT request to data service") + ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error executing PUT", err) + return + } + defer httpRes.Body.Close() + if httpRes.StatusCode != http.StatusOK { + log.Error().Err(err).Msg("PUT request to data server failed") + ocmd.WriteError(w, r, httpRes.StatusCode, "error executing PUT", err) + return + } + + // Return file id + js, err := json.Marshal(map[string]interface{}{"file_id": httpRes.ref.id}) if err != nil { ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error marshalling JSON response", err) return diff --git a/pkg/app/app.go b/pkg/app/app.go index e811379ca8f..8267f1d0489 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -40,7 +40,6 @@ type Registry interface { // Provider is the interface that application providers implement // for interacting with external apps that serve the requested resource. type Provider interface { - CreateFile(ctx context.Context, ref *provider.Reference, filename string, template string) (*provider.ResourceInfo, error) GetAppURL(ctx context.Context, resource *provider.ResourceInfo, viewMode appprovider.OpenInAppRequest_ViewMode, token string) (*appprovider.OpenInAppURL, error) GetAppProviderInfo(ctx context.Context) (*registry.ProviderInfo, error) } diff --git a/pkg/app/provider/demo/demo.go b/pkg/app/provider/demo/demo.go index 02ab40c1211..896893fa658 100644 --- a/pkg/app/provider/demo/demo.go +++ b/pkg/app/provider/demo/demo.go @@ -21,14 +21,12 @@ package demo import ( "context" "fmt" - "path" appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1" appregistry "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" "github.com/cs3org/reva/pkg/app" "github.com/cs3org/reva/pkg/app/provider/registry" - uuid "github.com/google/uuid" "github.com/mitchellh/mapstructure" ) @@ -40,17 +38,6 @@ type demoProvider struct { iframeUIProvider string } -func (p *demoProvider) CreateFile(ctx context.Context, ref *provider.Reference, filename string, template string) (*provider.ResourceInfo, error) { - return &provider.ResourceInfo{ - Id: &provider.ResourceId{ - StorageId: "/", - OpaqueId: uuid.New().String(), - }, - Type: provider.ResourceType_RESOURCE_TYPE_FILE, - Path: path.Join(ref.GetPath(), filename), - }, nil -} - func (p *demoProvider) GetAppURL(ctx context.Context, resource *provider.ResourceInfo, viewMode appprovider.OpenInAppRequest_ViewMode, token string) (*appprovider.OpenInAppURL, error) { url := fmt.Sprintf("