From 0cfaedc808fb2a0529660412b5f1ede1e4a15458 Mon Sep 17 00:00:00 2001 From: Ishank Arora Date: Tue, 3 Aug 2021 16:02:37 +0200 Subject: [PATCH 1/9] Use a URL object in OpenInAppResponse --- .../unreleased/appprovider-url-object.md | 3 + cmd/reva/open-in-app.go | 2 +- examples/ocmd/ocmd-server-1.toml | 2 + examples/storage-references/gateway.toml | 1 + go.mod | 2 + go.sum | 6 +- .../grpc/services/appregistry/appregistry.go | 2 +- .../http/services/appprovider/appprovider.go | 79 ++++++++++++++++--- internal/http/services/loader/loader.go | 1 + pkg/app/app.go | 4 +- pkg/app/provider/demo/demo.go | 9 ++- pkg/app/provider/wopi/wopi.go | 23 ++++-- pkg/app/registry/static/static.go | 8 +- 13 files changed, 112 insertions(+), 30 deletions(-) create mode 100644 changelog/unreleased/appprovider-url-object.md diff --git a/changelog/unreleased/appprovider-url-object.md b/changelog/unreleased/appprovider-url-object.md new file mode 100644 index 0000000000..aac3d82f3c --- /dev/null +++ b/changelog/unreleased/appprovider-url-object.md @@ -0,0 +1,3 @@ +Enhancement: Use a URL object in OpenInAppResponse + +https://github.com/cs3org/reva/pull/1968 diff --git a/cmd/reva/open-in-app.go b/cmd/reva/open-in-app.go index 7a6712dd39..70c1887767 100644 --- a/cmd/reva/open-in-app.go +++ b/cmd/reva/open-in-app.go @@ -86,7 +86,7 @@ func openInAppCommand() *command { return formatError(openRes.Status) } - fmt.Println("App URL: " + openRes.AppUrl) + fmt.Printf("App URL: %+v\n", openRes.AppUrl) return nil } diff --git a/examples/ocmd/ocmd-server-1.toml b/examples/ocmd/ocmd-server-1.toml index 9d69b7ccc7..4902f18fbe 100644 --- a/examples/ocmd/ocmd-server-1.toml +++ b/examples/ocmd/ocmd-server-1.toml @@ -143,4 +143,6 @@ prefix = "ocs" [http.services.ocdav] +[http.services.appprovider] + [http.middlewares.cors] diff --git a/examples/storage-references/gateway.toml b/examples/storage-references/gateway.toml index a477512a5b..10e58e90bd 100644 --- a/examples/storage-references/gateway.toml +++ b/examples/storage-references/gateway.toml @@ -35,3 +35,4 @@ appauth = "localhost:15000" [http.services.ocmd] [http.services.ocdav] [http.services.ocs] +[http.services.appprovider] diff --git a/go.mod b/go.mod index aeefd821df..bf7356f29c 100644 --- a/go.mod +++ b/go.mod @@ -39,6 +39,7 @@ require ( github.com/imdario/mergo v0.3.8 // indirect github.com/jedib0t/go-pretty v4.3.0+incompatible github.com/mattn/go-sqlite3 v1.14.8 + github.com/mileusna/useragent v1.0.2 github.com/minio/minio-go/v7 v7.0.12 github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/mapstructure v1.4.1 @@ -73,6 +74,7 @@ require ( go 1.16 replace ( + github.com/cs3org/go-cs3apis => github.com/ishank011/go-cs3apis v0.0.0-20210806135412-33c0570675bf github.com/eventials/go-tus => github.com/andrewmostello/go-tus v0.0.0-20200314041820-904a9904af9a github.com/oleiade/reflections => github.com/oleiade/reflections v1.0.1 google.golang.org/grpc => google.golang.org/grpc v1.26.0 // temporary downgrade diff --git a/go.sum b/go.sum index 2a46e292ff..c730a09aa0 100644 --- a/go.sum +++ b/go.sum @@ -108,8 +108,6 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e h1:tqSPWQeueWTKnJVMJffz4pz0o1WuQxJ28+5x5JgaHD8= github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4= -github.com/cs3org/go-cs3apis v0.0.0-20210802070913-970eec344e59 h1:cj9HxIbmbGn+HPpFP8nZ8oaNUsoFa0+cheCO8FUNoMc= -github.com/cs3org/go-cs3apis v0.0.0-20210802070913-970eec344e59/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -309,6 +307,8 @@ github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/ishank011/go-cs3apis v0.0.0-20210806135412-33c0570675bf h1:wn+wPv/i6zy20sf9PqOhLjfaRyj987uObXSRqeJfdDI= +github.com/ishank011/go-cs3apis v0.0.0-20210806135412-33c0570675bf/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo= github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= @@ -380,6 +380,8 @@ github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvr github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mileusna/useragent v1.0.2 h1:DgVKtiPnjxlb73z9bCwgdUvU2nQNQ97uhgfO8l9uz/w= +github.com/mileusna/useragent v1.0.2/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc= github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4= github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= github.com/minio/minio-go/v7 v7.0.12 h1:/4pxUdwn9w0QEryNkrrWaodIESPRX+NxpO0Q6hVdaAA= diff --git a/internal/grpc/services/appregistry/appregistry.go b/internal/grpc/services/appregistry/appregistry.go index abbfdc1fac..035f240029 100644 --- a/internal/grpc/services/appregistry/appregistry.go +++ b/internal/grpc/services/appregistry/appregistry.go @@ -45,7 +45,7 @@ func (s *svc) Close() error { } func (s *svc) UnprotectedEndpoints() []string { - return []string{"/cs3.app.registry.v1beta1.RegistryAPI/AddAppProvider"} + return []string{"/cs3.app.registry.v1beta1.RegistryAPI/AddAppProvider", "/cs3.app.registry.v1beta1.RegistryAPI/ListSupportedMimeTypes"} } func (s *svc) Register(ss *grpc.Server) { diff --git a/internal/http/services/appprovider/appprovider.go b/internal/http/services/appprovider/appprovider.go index bae42ca2c1..072338eede 100644 --- a/internal/http/services/appprovider/appprovider.go +++ b/internal/http/services/appprovider/appprovider.go @@ -28,14 +28,18 @@ import ( "time" "unicode/utf8" + 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/ocmd" + "github.com/cs3org/reva/pkg/appctx" "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" + ua "github.com/mileusna/useragent" "github.com/mitchellh/mapstructure" "github.com/pkg/errors" "github.com/rs/zerolog" @@ -54,7 +58,7 @@ type Config struct { func (c *Config) init() { if c.Prefix == "" { - c.Prefix = "api/v0/wopi/open" + c.Prefix = "app" } if c.AccessTokenTTL == 0 { c.AccessTokenTTL = 86400 @@ -91,17 +95,20 @@ func (s *svc) Prefix() string { } func (s *svc) Unprotected() []string { - return []string{} + return []string{"/list"} } func (s *svc) Handler() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodGet { - ocmd.WriteError(w, r, ocmd.APIErrorUnimplemented, "only GET requests are supported", errors.New("only GET requests are supported")) - return + var head string + head, r.URL.Path = router.ShiftPath(r.URL.Path) + + switch head { + case "list": + s.handleList(w, r) + case "open": + s.handleOpen(w, r) } - - s.handleWopiOpen(w, r) }) } @@ -112,7 +119,61 @@ type WopiResponse struct { AccessTokenTTL int64 `json:"accesstokenttl"` } -func (s *svc) handleWopiOpen(w http.ResponseWriter, r *http.Request) { +func filterAppsByUserAgent(mimeTypes map[string]*appregistry.AppProviderList, userAgent string) { + ua := ua.Parse(userAgent) + if ua.Desktop { + return + } + + for m, providers := range mimeTypes { + apps := []*appregistry.ProviderInfo{} + for _, p := range providers.AppProviders { + if !p.DesktopOnly { + apps = append(apps, p) + } + } + mimeTypes[m] = &appregistry.AppProviderList{AppProviders: apps} + } +} + +func (s *svc) handleList(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + log := appctx.GetLogger(ctx) + log.Info().Msgf("user agent %+v", r.UserAgent()) + + client, err := pool.GetGatewayServiceClient(s.conf.GatewaySvc) + if err != nil { + ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error getting grpc gateway client", err) + return + } + + listRes, err := client.ListSupportedMimeTypes(ctx, &appregistry.ListSupportedMimeTypesRequest{}) + if err != nil { + ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error listing supported mime types", err) + return + } + if listRes.Status.Code != rpc.Code_CODE_OK { + ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error listing supported mime types", status.NewErrorFromCode(listRes.Status.Code, "appprovider")) + return + } + + mimeTypes := listRes.MimeTypes + filterAppsByUserAgent(mimeTypes, r.UserAgent()) + + js, err := json.Marshal(map[string]interface{}{"mime-types": mimeTypes}) + if err != nil { + ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error marshalling JSON response", err) + return + } + + w.Header().Set("Content-Type", "application/json") + if _, err = w.Write(js); err != nil { + ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error writing JSON response", err) + return + } +} + +func (s *svc) handleOpen(w http.ResponseWriter, r *http.Request) { ctx := r.Context() client, err := pool.GetGatewayServiceClient(s.conf.GatewaySvc) @@ -141,7 +202,7 @@ func (s *svc) handleWopiOpen(w http.ResponseWriter, r *http.Request) { return } - u, err := url.Parse(openRes.AppUrl) + u, err := url.Parse(openRes.AppUrl.AppUrl) if err != nil { ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error parsing app URL", err) return diff --git a/internal/http/services/loader/loader.go b/internal/http/services/loader/loader.go index 92e535d876..73ac5e2719 100644 --- a/internal/http/services/loader/loader.go +++ b/internal/http/services/loader/loader.go @@ -20,6 +20,7 @@ package loader import ( // Load core HTTP services + _ "github.com/cs3org/reva/internal/http/services/appprovider" _ "github.com/cs3org/reva/internal/http/services/datagateway" _ "github.com/cs3org/reva/internal/http/services/dataprovider" _ "github.com/cs3org/reva/internal/http/services/helloworld" diff --git a/pkg/app/app.go b/pkg/app/app.go index 0e6c1f65a0..bb1319dc52 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -31,7 +31,7 @@ import ( type Registry interface { FindProviders(ctx context.Context, mimeType string) ([]*registry.ProviderInfo, error) ListProviders(ctx context.Context) ([]*registry.ProviderInfo, error) - ListSupportedMimeTypes(ctx context.Context) (map[string]*registry.AppProviderNameList, error) + ListSupportedMimeTypes(ctx context.Context) (map[string]*registry.AppProviderList, error) AddProvider(ctx context.Context, p *registry.ProviderInfo) error GetDefaultProviderForMimeType(ctx context.Context, mimeType string) (*registry.ProviderInfo, error) SetDefaultProviderForMimeType(ctx context.Context, mimeType string, p *registry.ProviderInfo) error @@ -40,6 +40,6 @@ type Registry interface { // Provider is the interface that application providers implement // for providing the URL of the app which will serve the requested resource. type Provider interface { - GetAppURL(ctx context.Context, resource *provider.ResourceInfo, viewMode appprovider.OpenInAppRequest_ViewMode, token string) (string, 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 4805f2b1b9..254dd868ae 100644 --- a/pkg/app/provider/demo/demo.go +++ b/pkg/app/provider/demo/demo.go @@ -39,9 +39,12 @@ type demoProvider struct { iframeUIProvider string } -func (p *demoProvider) GetAppURL(ctx context.Context, resource *provider.ResourceInfo, viewMode appprovider.OpenInAppRequest_ViewMode, token string) (string, error) { - msg := fmt.Sprintf("