From 00c9302d8263ff74707a99589df1dcc6e6d53be5 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Thu, 26 Sep 2024 15:28:15 +0200 Subject: [PATCH] feat: add wopi host and sharing urls --- changelog/unreleased/wopi-host-urls.md | 5 ++ .../pkg/connector/fileconnector.go | 62 ++++++++++++++++--- .../pkg/connector/fileconnector_test.go | 23 ++++--- .../apiCollaboration/checkFileInfo.feature | 28 ++++++++- 4 files changed, 96 insertions(+), 22 deletions(-) create mode 100644 changelog/unreleased/wopi-host-urls.md diff --git a/changelog/unreleased/wopi-host-urls.md b/changelog/unreleased/wopi-host-urls.md new file mode 100644 index 000000000..a730f95b2 --- /dev/null +++ b/changelog/unreleased/wopi-host-urls.md @@ -0,0 +1,5 @@ +Enhancement: Add WOPI host URLs to the collaboration service + +We added the WOPI host urls to create a better integration with WOPI clients. This allows the WOPI apps to display links to our sharing and versions panel in the UI. + +https://github.com/owncloud/ocis/pull/10174 diff --git a/services/collaboration/pkg/connector/fileconnector.go b/services/collaboration/pkg/connector/fileconnector.go index 12ba12bc7..289d5329d 100644 --- a/services/collaboration/pkg/connector/fileconnector.go +++ b/services/collaboration/pkg/connector/fileconnector.go @@ -1118,9 +1118,14 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse, if err != nil { return nil, err } + + fileRef := wopiContext.FileReference + // set path to empty string to get the full path from the stat + fileRef.Path = "" statRes, err := gwc.Stat(ctx, &providerv1beta1.StatRequest{ - Ref: wopiContext.FileReference, + Ref: fileRef, }) + if err != nil { logger.Error().Err(err).Msg("CheckFileInfo: stat failed") return nil, err @@ -1175,18 +1180,17 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse, } breadcrumbFolderName := path.Dir(statRes.Info.Path) - if breadcrumbFolderName == "." || breadcrumbFolderName == "" { + if breadcrumbFolderName == "." || breadcrumbFolderName == "" || breadcrumbFolderName == "/" { breadcrumbFolderName = statRes.GetInfo().GetSpace().GetName() } - ocisUrl, err := url.Parse(f.cfg.Commons.OcisURL) + ocisURL, err := url.Parse(f.cfg.Commons.OcisURL) if err != nil { return nil, err } - breadcrumbFolderURL, viewAppUrl, editAppUrl := *ocisUrl, *ocisUrl, *ocisUrl - breadcrumbFolderURL.Path = path.Join(breadcrumbFolderURL.Path, "f", storagespace.FormatResourceID(statRes.GetInfo().GetId())) - viewAppUrl.Path = path.Join(viewAppUrl.Path, "external"+strings.ToLower(f.cfg.App.Name)) - editAppUrl.Path = path.Join(editAppUrl.Path, "external"+strings.ToLower(f.cfg.App.Name)) + privateLinkURL := &url.URL{} + *privateLinkURL = *ocisURL + privateLinkURL.Path = path.Join(ocisURL.Path, "f", storagespace.FormatResourceID(statRes.GetInfo().GetId())) // fileinfo map infoMap := map[string]interface{}{ fileinfo.KeyOwnerID: hexEncodedOwnerId, @@ -1196,10 +1200,12 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse, fileinfo.KeyBreadcrumbDocName: path.Base(statRes.GetInfo().GetPath()), // to get the folder we actually need to do a GetPath() request fileinfo.KeyBreadcrumbFolderName: breadcrumbFolderName, - fileinfo.KeyBreadcrumbFolderURL: breadcrumbFolderURL.String(), + fileinfo.KeyBreadcrumbFolderURL: privateLinkURL.String(), - //fileinfo.KeyHostViewURL: viewAppUrl.String(), - //fileinfo.KeyHostEditURL: editAppUrl.String(), + fileinfo.KeyHostViewURL: createHostUrl("view", ocisURL, f.cfg.App.Name, statRes.GetInfo()), + fileinfo.KeyHostEditURL: createHostUrl("write", ocisURL, f.cfg.App.Name, statRes.GetInfo()), + fileinfo.KeyFileSharingURL: createShareUrl(privateLinkURL), + fileinfo.KeyFileVersionURL: createVersionsUrl(privateLinkURL), fileinfo.KeyEnableOwnerTermination: true, // only for collabora fileinfo.KeySupportsExtendedLockLength: true, @@ -1240,6 +1246,42 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse, return NewResponseSuccessBody(info), nil } +func createHostUrl(mode string, ocisUrl *url.URL, appName string, info *providerv1beta1.ResourceInfo) string { + webUrl := createAppExternalURL(ocisUrl, appName, info) + addURLParams(webUrl, map[string]string{"view_mode": mode}) + return webUrl.String() +} + +func createShareUrl(ocisURL *url.URL) string { + shareURL := *ocisURL + addURLParams(&shareURL, map[string]string{"details": "sharing"}) + return shareURL.String() +} + +func createVersionsUrl(ocisURL *url.URL) string { + versionsURL := *ocisURL + addURLParams(&versionsURL, map[string]string{"details": "versions"}) + return versionsURL.String() +} + +func addURLParams(u *url.URL, params map[string]string) { + q := u.Query() + for k, v := range params { + q.Add(k, v) + } + u.RawQuery = q.Encode() +} + +func createAppExternalURL(ocisURL *url.URL, appName string, info *providerv1beta1.ResourceInfo) *url.URL { + spaceAlias := utils.ReadPlainFromOpaque(info.GetSpace().GetOpaque(), "spaceAlias") + appExternalURL := *ocisURL + appExternalURL.Path = path.Join(ocisURL.Path, "external-"+strings.ToLower(appName), spaceAlias, info.GetPath()) + q := ocisURL.Query() + q.Add("fileId", storagespace.FormatResourceID(info.GetId())) + appExternalURL.RawQuery = q.Encode() + return &appExternalURL +} + func (f *FileConnector) watermarkText(user *userv1beta1.User) string { if user != nil { return strings.TrimSpace(user.GetDisplayName() + " " + user.GetMail()) diff --git a/services/collaboration/pkg/connector/fileconnector_test.go b/services/collaboration/pkg/connector/fileconnector_test.go index 1401b91f6..3ec57e30e 100644 --- a/services/collaboration/pkg/connector/fileconnector_test.go +++ b/services/collaboration/pkg/connector/fileconnector_test.go @@ -45,6 +45,7 @@ var _ = Describe("FileConnector", func() { }, App: config.App{ LockName: "testName_for_unittests", // Only the LockName is used + Name: "test", }, Wopi: config.Wopi{ WopiSrc: "https://ocis.server.prv", @@ -1694,16 +1695,14 @@ var _ = Describe("FileConnector", func() { }, nil) expectedFileInfo := &fileinfo.Microsoft{ - OwnerID: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp - Size: int64(998877), - Version: "v162738490", - BaseFileName: "test.txt", - BreadcrumbDocName: "test.txt", - BreadcrumbFolderName: "/path/to", - BreadcrumbFolderURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid", - UserCanNotWriteRelative: false, - //HostViewURL: "http://test.ex.prv/view", - //HostEditURL: "http://test.ex.prv/edit", + OwnerID: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp + Size: int64(998877), + Version: "v162738490", + BaseFileName: "test.txt", + BreadcrumbDocName: "test.txt", + BreadcrumbFolderName: "/path/to", + BreadcrumbFolderURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid", + UserCanNotWriteRelative: false, SupportsExtendedLockLength: true, SupportsGetLock: true, SupportsLocks: true, @@ -1714,6 +1713,10 @@ var _ = Describe("FileConnector", func() { UserCanRename: true, UserID: "61646d696e40637573746f6d496470", // hex of admin@customIdp UserFriendlyName: "Pet Shaft", + FileSharingURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid?details=sharing", + FileVersionURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid?details=versions", + HostEditURL: "https://ocis.example.prv/external-test/path/to/test.txt?fileId=storageid%24spaceid%21opaqueid&view_mode=write", + HostViewURL: "https://ocis.example.prv/external-test/path/to/test.txt?fileId=storageid%24spaceid%21opaqueid&view_mode=view", } response, err := fc.CheckFileInfo(ctx) diff --git a/tests/acceptance/features/apiCollaboration/checkFileInfo.feature b/tests/acceptance/features/apiCollaboration/checkFileInfo.feature index f881aa34e..8f3d23725 100644 --- a/tests/acceptance/features/apiCollaboration/checkFileInfo.feature +++ b/tests/acceptance/features/apiCollaboration/checkFileInfo.feature @@ -235,7 +235,10 @@ Feature: check file info with different wopi apps "UserCanWrite", "SupportsLocks", "SupportsRename", - "SupportsUpdate" + "SupportsUpdate", + "HostEditUrl", + "FileSharingUrl", + "FileVersionUrl" ], "properties": { "BaseFileName": { @@ -285,6 +288,15 @@ Feature: check file info with different wopi apps }, "PostMessageOrigin": { "type": "string" + }, + "FileSharingUrl": { + "type": "string" + }, + "HostEditUrl": { + "type": "string" + }, + "FileVersionUrl": { + "type": "string" } } } @@ -315,7 +327,10 @@ Feature: check file info with different wopi apps "UserCanWrite", "SupportsLocks", "SupportsRename", - "SupportsUpdate" + "SupportsUpdate", + "HostEditUrl", + "FileSharingUrl", + "FileVersionUrl" ], "properties": { "BaseFileName": { @@ -365,6 +380,15 @@ Feature: check file info with different wopi apps }, "PostMessageOrigin": { "type": "string" + }, + "FileSharingUrl": { + "type": "string" + }, + "HostEditUrl": { + "type": "string" + }, + "FileVersionUrl": { + "type": "string" } } }