From 5ddd51ea84df403efb4da99b97dd151375e33ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Wed, 14 Aug 2024 18:21:15 +0200 Subject: [PATCH 1/3] refactor: simplify openInApp code and remove hostViewUrl (and edit) --- .../pkg/connector/fileconnector.go | 6 +- .../pkg/middleware/wopicontext.go | 2 - .../pkg/service/grpc/v0/service.go | 221 +++++++++--------- 3 files changed, 107 insertions(+), 122 deletions(-) diff --git a/services/collaboration/pkg/connector/fileconnector.go b/services/collaboration/pkg/connector/fileconnector.go index 0f9d42f67d2..d23e93c7358 100644 --- a/services/collaboration/pkg/connector/fileconnector.go +++ b/services/collaboration/pkg/connector/fileconnector.go @@ -1050,8 +1050,9 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse, // to get the folder we actually need to do a GetPath() request //BreadcrumbFolderName: path.Dir(statRes.Info.Path), - fileinfo.KeyHostViewURL: wopiContext.ViewAppUrl, - fileinfo.KeyHostEditURL: wopiContext.EditAppUrl, + // TODO: these URLs must point to ocis, which is hosting the editor's iframe + //fileinfo.KeyHostViewURL: wopiContext.ViewAppUrl, + //fileinfo.KeyHostEditURL: wopiContext.EditAppUrl, fileinfo.KeyEnableOwnerTermination: true, // only for collabora fileinfo.KeySupportsExtendedLockLength: true, @@ -1061,7 +1062,6 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse, fileinfo.KeySupportsDeleteFile: true, fileinfo.KeySupportsRename: true, - //fileinfo.KeyUserCanNotWriteRelative: true, fileinfo.KeyIsAnonymousUser: isAnonymousUser, fileinfo.KeyUserFriendlyName: userFriendlyName, fileinfo.KeyUserID: userId, diff --git a/services/collaboration/pkg/middleware/wopicontext.go b/services/collaboration/pkg/middleware/wopicontext.go index 1232da0317b..e6b9dff0afe 100644 --- a/services/collaboration/pkg/middleware/wopicontext.go +++ b/services/collaboration/pkg/middleware/wopicontext.go @@ -31,8 +31,6 @@ type WopiContext struct { FileReference *providerv1beta1.Reference User *userv1beta1.User ViewMode appproviderv1beta1.ViewMode - EditAppUrl string - ViewAppUrl string } // WopiContextAuthMiddleware will prepare an HTTP handler to be used as diff --git a/services/collaboration/pkg/service/grpc/v0/service.go b/services/collaboration/pkg/service/grpc/v0/service.go index 1568efe0ad2..41a50df81a2 100644 --- a/services/collaboration/pkg/service/grpc/v0/service.go +++ b/services/collaboration/pkg/service/grpc/v0/service.go @@ -2,10 +2,11 @@ package service import ( "context" - "fmt" + "errors" "net/url" "path" "strconv" + "strings" appproviderv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1" gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" @@ -80,147 +81,47 @@ func (s *Service) OpenInApp( Path: ".", } - // build a urlsafe and stable file reference that can be used for proxy routing, - // so that all sessions on one file end on the same office server - fileRef := helpers.HashResourceId(req.GetResourceInfo().GetId()) + logger := s.logger.With(). + Str("FileReference", providerFileRef.String()). + Str("ViewMode", req.GetViewMode().String()). + Str("Requester", user.GetId().String()). + Logger() // get the file extension to use the right wopi app url fileExt := path.Ext(req.GetResourceInfo().GetPath()) - var viewCommentAppURL string - var viewAppURL string - var editAppURL string - if viewCommentAppURLs, ok := s.appURLs["view_comment"]; ok { - if u, ok := viewCommentAppURLs[fileExt]; ok { - viewCommentAppURL = u - } - } - if viewAppURLs, ok := s.appURLs["view"]; ok { - if u, ok := viewAppURLs[fileExt]; ok { - viewAppURL = u - } - } - if editAppURLs, ok := s.appURLs["edit"]; ok { - if u, ok := editAppURLs[fileExt]; ok { - editAppURL = u - } - } - if editAppURL == "" && viewAppURL == "" && viewCommentAppURL == "" { - err := fmt.Errorf("OpenInApp: neither edit nor view app url found") - s.logger.Error(). - Err(err). - Str("FileReference", providerFileRef.String()). - Str("ViewMode", req.GetViewMode().String()). - Str("Requester", user.GetId().String()).Send() - return nil, err - } - - if editAppURL == "" { - // assuming that an view action is always available in the /hosting/discovery manifest - // eg. Collabora does support viewing jpgs but no editing - // eg. OnlyOffice does support viewing pdfs but no editing - // there is no known case of supporting edit only without view - editAppURL = viewAppURL - } - if viewAppURL == "" { - // the URL of the end-user application in view mode when different (defaults to edit mod URL) - viewAppURL = editAppURL - } - // TODO: check if collabora will support an "edit" url in the future - if viewAppURL == "" && editAppURL == "" && viewCommentAppURL != "" { - // there are rare cases where neither view nor edit is supported but view_comment is - viewAppURL = viewCommentAppURL - // that can be the case for editable and viewable files - if req.GetViewMode() == appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE { - editAppURL = viewCommentAppURL - } - } - wopiSrcURL, err := url.Parse(s.config.Wopi.WopiSrc) - if err != nil { - return nil, err - } - wopiSrcURL.Path = path.Join("wopi", "files", fileRef) - - addWopiSrcQueryParam := func(baseURL string) (string, error) { - u, err := url.Parse(baseURL) - if err != nil { - return "", err - } - - q := u.Query() - q.Add("WOPISrc", wopiSrcURL.String()) - - if s.config.Wopi.DisableChat { - q.Add("dchat", "1") - } - - lang := utils.ReadPlainFromOpaque(req.GetOpaque(), "lang") - - if lang != "" { - q.Add("ui", lang) // OnlyOffice - q.Add("lang", lang) // Collabora, Impact on the default document language of OnlyOffice - q.Add("UI_LLCC", lang) // Office365 - } - qs := q.Encode() - u.RawQuery = qs - - return u.String(), nil + // get the appURL we need to use + appURL := s.getAppUrl(fileExt, req.GetViewMode()) + if appURL == "" { + logger.Error().Msg("OpenInApp: neither edit nor view app URL found") + return nil, errors.New("neither edit nor view app URL found") } - viewAppURL, err = addWopiSrcQueryParam(viewAppURL) + // append the parameters we need + appURL, err = s.addQueryToURL(appURL, req) if err != nil { - s.logger.Error(). - Err(err). - Str("FileReference", providerFileRef.String()). - Str("ViewMode", req.GetViewMode().String()). - Str("Requester", user.GetId().String()). - Msg("OpenInApp: error parsing viewAppUrl") - return nil, err - } - editAppURL, err = addWopiSrcQueryParam(editAppURL) - if err != nil { - s.logger.Error(). - Err(err). - Str("FileReference", providerFileRef.String()). - Str("ViewMode", req.GetViewMode().String()). - Str("Requester", user.GetId().String()). - Msg("OpenInApp: error parsing editAppUrl") + logger.Error().Err(err).Msg("OpenInApp: error parsing appUrl") return nil, err } - appURL := viewAppURL - if req.GetViewMode() == appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE { - appURL = editAppURL - } - + // create the wopiContext and generate the token wopiContext := middleware.WopiContext{ AccessToken: req.GetAccessToken(), // it will be encrypted ViewOnlyToken: utils.ReadPlainFromOpaque(req.GetOpaque(), "viewOnlyToken"), FileReference: &providerFileRef, User: user, ViewMode: req.GetViewMode(), - EditAppUrl: editAppURL, - ViewAppUrl: viewAppURL, } accessToken, accessExpiration, err := middleware.GenerateWopiToken(wopiContext, s.config) if err != nil { - s.logger.Error(). - Err(err). - Str("FileReference", providerFileRef.String()). - Str("ViewMode", req.GetViewMode().String()). - Str("Requester", user.GetId().String()). - Msg("OpenInApp: error generating the token") + logger.Error().Err(err).Msg("OpenInApp: error generating the token") return &appproviderv1beta1.OpenInAppResponse{ Status: &rpcv1beta1.Status{Code: rpcv1beta1.Code_CODE_INTERNAL}, }, err } - s.logger.Debug(). - Str("FileReference", providerFileRef.String()). - Str("ViewMode", req.GetViewMode().String()). - Str("Requester", user.GetId().String()). - Msg("OpenInApp: success") + logger.Debug().Msg("OpenInApp: success") return &appproviderv1beta1.OpenInAppResponse{ Status: &rpcv1beta1.Status{Code: rpcv1beta1.Code_CODE_OK}, @@ -237,3 +138,89 @@ func (s *Service) OpenInApp( }, }, nil } + +// getAppUrlFor gets the appURL from the list of appURLs based on the +// action and file extension provided. If there is no match, an empty +// string will be returned. +func (s *Service) getAppUrlFor(action, fileExt string) string { + if actionURL, ok := s.appURLs[action]; ok { + if actionExtensionURL, ok := actionURL[fileExt]; ok { + return actionExtensionURL + } + } + return "" +} + +// getAppUrl will get the appURL that should be used based on the extension +// and the provided view mode. +// "view" urls will be chosen first, then if the view mode is "read/write", +// "edit" urls will be prioritized. Note that "view" url might be returned for +// "read/write" view mode if no "edit" url is found. +func (s *Service) getAppUrl(fileExt string, viewMode appproviderv1beta1.ViewMode) string { + // check view_comment action first (for collabora) + appURL := s.getAppUrlFor("view_comment", fileExt) + + // prioritize view action if possible + if viewAppURL := s.getAppUrlFor("view", fileExt); viewAppURL != "" { + appURL = viewAppURL + } + + // If read/write mode has been requested, prioritize edit action. + // Special case for collabora because it only provides one action per + // extension, + if viewMode == appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE || strings.ToLower(s.config.App.Name) == "collabora" { + if editAppURL := s.getAppUrlFor("edit", fileExt); editAppURL != "" { + appURL = editAppURL + } + } + + return appURL +} + +// addQueryToURL will add specific query parameters to the baseURL. These +// parameters are: +// * "WOPISrc" pointing to the requested resource in the OpenInAppRequest +// * "dchat" to disable the chat, based on configuration +// * "lang" (WOPI app dependent) with the language in the request. "lang" +// for collabora, "ui" for onlyoffice and "UI_LLCC" for the rest +func (s *Service) addQueryToURL(baseURL string, req *appproviderv1beta1.OpenInAppRequest) (string, error) { + u, err := url.Parse(baseURL) + if err != nil { + return "", err + } + + // build a urlsafe and stable file reference that can be used for proxy routing, + // so that all sessions on one file end on the same office server + fileRef := helpers.HashResourceId(req.GetResourceInfo().GetId()) + + wopiSrcURL, err := url.Parse(s.config.Wopi.WopiSrc) + if err != nil { + return "", err + } + wopiSrcURL.Path = path.Join("wopi", "files", fileRef) + + q := u.Query() + q.Add("WOPISrc", wopiSrcURL.String()) + + if s.config.Wopi.DisableChat { + q.Add("dchat", "1") + } + + lang := utils.ReadPlainFromOpaque(req.GetOpaque(), "lang") + + if lang != "" { + switch strings.ToLower(s.config.App.Name) { + case "collabora": + q.Add("lang", lang) + case "onlyoffice": + q.Add("ui", lang) + default: + q.Add("UI_LLCC", lang) + } + } + + qs := q.Encode() + u.RawQuery = qs + + return u.String(), nil +} From 3d287da5cea12e043bcf83f8b8610a97896770a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Fri, 16 Aug 2024 11:01:51 +0200 Subject: [PATCH 2/3] refactor: simplify getting the app url for collabora --- .../pkg/service/grpc/v0/service.go | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/services/collaboration/pkg/service/grpc/v0/service.go b/services/collaboration/pkg/service/grpc/v0/service.go index 41a50df81a2..1458a4e27e7 100644 --- a/services/collaboration/pkg/service/grpc/v0/service.go +++ b/services/collaboration/pkg/service/grpc/v0/service.go @@ -157,20 +157,28 @@ func (s *Service) getAppUrlFor(action, fileExt string) string { // "edit" urls will be prioritized. Note that "view" url might be returned for // "read/write" view mode if no "edit" url is found. func (s *Service) getAppUrl(fileExt string, viewMode appproviderv1beta1.ViewMode) string { - // check view_comment action first (for collabora) - appURL := s.getAppUrlFor("view_comment", fileExt) - // prioritize view action if possible - if viewAppURL := s.getAppUrlFor("view", fileExt); viewAppURL != "" { - appURL = viewAppURL - } - - // If read/write mode has been requested, prioritize edit action. - // Special case for collabora because it only provides one action per - // extension, - if viewMode == appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE || strings.ToLower(s.config.App.Name) == "collabora" { - if editAppURL := s.getAppUrlFor("edit", fileExt); editAppURL != "" { - appURL = editAppURL + appURL := s.getAppUrlFor("view", fileExt) + + if strings.ToLower(s.config.App.Name) == "collabora" { + // collabora provides only one action per extension. usual options + // are "view" (checked above), "edit" or "view_comment" (this last one + // is exclusive of collabora) + if appURL == "" { + if editURL := s.getAppUrlFor("edit", fileExt); editURL != "" { + return editURL + } + if commentURL := s.getAppUrlFor("view_comment", fileExt); commentURL != "" { + return commentURL + } + } + } else { + // If not collabora, there might be an edit action for the extension. + // If read/write mode has been requested, prioritize edit action. + if viewMode == appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE { + if editAppURL := s.getAppUrlFor("edit", fileExt); editAppURL != "" { + appURL = editAppURL + } } } From fe1712ebcae9df5444df12061a2bf5e0c3929d10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Fri, 16 Aug 2024 14:08:09 +0200 Subject: [PATCH 3/3] fix: adjust unit tests --- .../pkg/connector/contentconnector_test.go | 12 +- .../pkg/connector/fileconnector_test.go | 6 +- .../pkg/service/grpc/v0/service_test.go | 185 ++++++------------ 3 files changed, 64 insertions(+), 139 deletions(-) diff --git a/services/collaboration/pkg/connector/contentconnector_test.go b/services/collaboration/pkg/connector/contentconnector_test.go index 38f308afcf3..82ba9e9c42f 100644 --- a/services/collaboration/pkg/connector/contentconnector_test.go +++ b/services/collaboration/pkg/connector/contentconnector_test.go @@ -52,10 +52,8 @@ var _ = Describe("ContentConnector", func() { }, Path: ".", }, - User: &userv1beta1.User{}, // Not used for now - ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE, - EditAppUrl: "http://test.ex.prv/edit", - ViewAppUrl: "http://test.ex.prv/view", + User: &userv1beta1.User{}, // Not used for now + ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE, } randomContent = "This is the content of the test.txt file" @@ -186,10 +184,8 @@ var _ = Describe("ContentConnector", func() { }, Path: ".", }, - User: &userv1beta1.User{}, // Not used for now - ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY, - EditAppUrl: "http://test.ex.prv/edit", - ViewAppUrl: "http://test.ex.prv/view", + User: &userv1beta1.User{}, // Not used for now + ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY, } ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx) diff --git a/services/collaboration/pkg/connector/fileconnector_test.go b/services/collaboration/pkg/connector/fileconnector_test.go index 2f74ebb1419..eb1ec5462c2 100644 --- a/services/collaboration/pkg/connector/fileconnector_test.go +++ b/services/collaboration/pkg/connector/fileconnector_test.go @@ -82,9 +82,7 @@ var _ = Describe("FileConnector", func() { // }, //}, }, - ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE, - EditAppUrl: "http://test.ex.prv/edit", - ViewAppUrl: "http://test.ex.prv/view", + ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE, } }) @@ -1546,8 +1544,6 @@ var _ = Describe("FileConnector", func() { BaseFileName: "test.txt", BreadcrumbDocName: "test.txt", UserCanNotWriteRelative: false, - HostViewURL: "http://test.ex.prv/view", - HostEditURL: "http://test.ex.prv/edit", SupportsExtendedLockLength: true, SupportsGetLock: true, SupportsLocks: true, diff --git a/services/collaboration/pkg/service/grpc/v0/service_test.go b/services/collaboration/pkg/service/grpc/v0/service_test.go index e2361c090c5..68f5aa1416b 100644 --- a/services/collaboration/pkg/service/grpc/v0/service_test.go +++ b/services/collaboration/pkg/service/grpc/v0/service_test.go @@ -136,133 +136,66 @@ var _ = Describe("Discovery", func() { Expect(resp).To(BeNil()) }) - It("Success", func() { - ctx := context.Background() - nowTime := time.Now() - - cfg.Wopi.WopiSrc = "https://wopiserver.test.prv" - cfg.Wopi.Secret = "my_supa_secret" - - myself := &userv1beta1.User{ - Id: &userv1beta1.UserId{ - Idp: "myIdp", - OpaqueId: "opaque001", - Type: userv1beta1.UserType_USER_TYPE_PRIMARY, - }, - Username: "username", - } - - req := &appproviderv1beta1.OpenInAppRequest{ - ResourceInfo: &providerv1beta1.ResourceInfo{ - Id: &providerv1beta1.ResourceId{ - StorageId: "myStorage", - OpaqueId: "storageOpaque001", - SpaceId: "SpaceA", - }, - Path: "/path/to/file.docx", - }, - ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE, - AccessToken: MintToken(myself, cfg.Wopi.Secret, nowTime), - } - req.Opaque = utils.AppendPlainToOpaque(req.Opaque, "lang", "de") - - gatewayClient.On("WhoAmI", mock.Anything, mock.Anything).Times(1).Return(&gatewayv1beta1.WhoAmIResponse{ - Status: status.NewOK(ctx), - User: myself, - }, nil) - - resp, err := srv.OpenInApp(ctx, req) - Expect(err).To(Succeed()) - Expect(resp.GetStatus().GetCode()).To(Equal(rpcv1beta1.Code_CODE_OK)) - Expect(resp.GetAppUrl().GetMethod()).To(Equal("POST")) - Expect(resp.GetAppUrl().GetAppUrl()).To(Equal("https://test.server.prv/hosting/wopi/word/edit?UI_LLCC=de&WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&lang=de&ui=de")) - Expect(resp.GetAppUrl().GetFormParameters()["access_token_ttl"]).To(Equal(strconv.FormatInt(nowTime.Add(5*time.Hour).Unix()*1000, 10))) - }) - - It("Success", func() { - ctx := context.Background() - nowTime := time.Now() - - cfg.Wopi.WopiSrc = "https://wopiserver.test.prv" - cfg.Wopi.Secret = "my_supa_secret" - cfg.Wopi.DisableChat = true - - myself := &userv1beta1.User{ - Id: &userv1beta1.UserId{ - Idp: "myIdp", - OpaqueId: "opaque001", - Type: userv1beta1.UserType_USER_TYPE_PRIMARY, - }, - Username: "username", - } - - req := &appproviderv1beta1.OpenInAppRequest{ - ResourceInfo: &providerv1beta1.ResourceInfo{ - Id: &providerv1beta1.ResourceId{ - StorageId: "myStorage", - OpaqueId: "storageOpaque001", - SpaceId: "SpaceA", + DescribeTable( + "Success", + func(appName, lang string, disableChat bool, expectedAppUrl string) { + ctx := context.Background() + nowTime := time.Now() + + cfg.Wopi.WopiSrc = "https://wopiserver.test.prv" + cfg.Wopi.Secret = "my_supa_secret" + cfg.Wopi.DisableChat = disableChat + cfg.App.Name = appName + + myself := &userv1beta1.User{ + Id: &userv1beta1.UserId{ + Idp: "myIdp", + OpaqueId: "opaque001", + Type: userv1beta1.UserType_USER_TYPE_PRIMARY, }, - Path: "/path/to/file.docx", - }, - ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE, - AccessToken: MintToken(myself, cfg.Wopi.Secret, nowTime), - } - - gatewayClient.On("WhoAmI", mock.Anything, mock.Anything).Times(1).Return(&gatewayv1beta1.WhoAmIResponse{ - Status: status.NewOK(ctx), - User: myself, - }, nil) - - resp, err := srv.OpenInApp(ctx, req) - Expect(err).To(Succeed()) - Expect(resp.GetStatus().GetCode()).To(Equal(rpcv1beta1.Code_CODE_OK)) - Expect(resp.GetAppUrl().GetMethod()).To(Equal("POST")) - Expect(resp.GetAppUrl().GetAppUrl()).To(Equal("https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1")) - Expect(resp.GetAppUrl().GetFormParameters()["access_token_ttl"]).To(Equal(strconv.FormatInt(nowTime.Add(5*time.Hour).Unix()*1000, 10))) - }) - - It("Success", func() { - ctx := context.Background() - nowTime := time.Now() - - cfg.Wopi.WopiSrc = "https://wopiserver.test.prv" - cfg.Wopi.Secret = "my_supa_secret" - cfg.Wopi.DisableChat = true - - myself := &userv1beta1.User{ - Id: &userv1beta1.UserId{ - Idp: "myIdp", - OpaqueId: "opaque001", - Type: userv1beta1.UserType_USER_TYPE_PRIMARY, - }, - Username: "username", - } - - req := &appproviderv1beta1.OpenInAppRequest{ - ResourceInfo: &providerv1beta1.ResourceInfo{ - Id: &providerv1beta1.ResourceId{ - StorageId: "myStorage", - OpaqueId: "storageOpaque001", - SpaceId: "SpaceA", + Username: "username", + } + + req := &appproviderv1beta1.OpenInAppRequest{ + ResourceInfo: &providerv1beta1.ResourceInfo{ + Id: &providerv1beta1.ResourceId{ + StorageId: "myStorage", + OpaqueId: "storageOpaque001", + SpaceId: "SpaceA", + }, + Path: "/path/to/file.docx", }, - Path: "/path/to/file.docx", - }, - ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE, - AccessToken: MintToken(myself, cfg.Wopi.Secret, nowTime), - } - - gatewayClient.On("WhoAmI", mock.Anything, mock.Anything).Times(1).Return(&gatewayv1beta1.WhoAmIResponse{ - Status: status.NewOK(ctx), - User: myself, - }, nil) - - resp, err := srv.OpenInApp(ctx, req) - Expect(err).To(Succeed()) - Expect(resp.GetStatus().GetCode()).To(Equal(rpcv1beta1.Code_CODE_OK)) - Expect(resp.GetAppUrl().GetMethod()).To(Equal("POST")) - Expect(resp.GetAppUrl().GetAppUrl()).To(Equal("https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1")) - Expect(resp.GetAppUrl().GetFormParameters()["access_token_ttl"]).To(Equal(strconv.FormatInt(nowTime.Add(5*time.Hour).Unix()*1000, 10))) - }) + ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE, + AccessToken: MintToken(myself, cfg.Wopi.Secret, nowTime), + } + if lang != "" { + req.Opaque = utils.AppendPlainToOpaque(req.Opaque, "lang", lang) + } + + gatewayClient.On("WhoAmI", mock.Anything, mock.Anything).Times(1).Return(&gatewayv1beta1.WhoAmIResponse{ + Status: status.NewOK(ctx), + User: myself, + }, nil) + + resp, err := srv.OpenInApp(ctx, req) + Expect(err).To(Succeed()) + Expect(resp.GetStatus().GetCode()).To(Equal(rpcv1beta1.Code_CODE_OK)) + Expect(resp.GetAppUrl().GetMethod()).To(Equal("POST")) + Expect(resp.GetAppUrl().GetAppUrl()).To(Equal(expectedAppUrl)) + Expect(resp.GetAppUrl().GetFormParameters()["access_token_ttl"]).To(Equal(strconv.FormatInt(nowTime.Add(5*time.Hour).Unix()*1000, 10))) + }, + Entry("Microsoft chat no lang", "Microsoft", "", false, "https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e"), + Entry("Collabora chat no lang", "Collabora", "", false, "https://test.server.prv/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e"), + Entry("OnlyOffice chat no lang", "OnlyOffice", "", false, "https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e"), + Entry("Microsoft chat lang", "Microsoft", "de", false, "https://test.server.prv/hosting/wopi/word/edit?UI_LLCC=de&WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e"), + Entry("Collabora chat lang", "Collabora", "de", false, "https://test.server.prv/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&lang=de"), + Entry("OnlyOffice chat lang", "OnlyOffice", "de", false, "https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&ui=de"), + Entry("Microsoft no chat no lang", "Microsoft", "", true, "https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1"), + Entry("Collabora no chat no lang", "Collabora", "", true, "https://test.server.prv/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1"), + Entry("OnlyOffice no chat no lang", "OnlyOffice", "", true, "https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1"), + Entry("Microsoft no chat lang", "Microsoft", "de", true, "https://test.server.prv/hosting/wopi/word/edit?UI_LLCC=de&WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1"), + Entry("Collabora no chat lang", "Collabora", "de", true, "https://test.server.prv/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1&lang=de"), + Entry("OnlyOffice no chat lang", "OnlyOffice", "de", true, "https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1&ui=de"), + ) }) })