From 116bd2c4148a60d131f84fbc4621fe63f3ea929d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Fri, 24 May 2024 14:14:01 +0200 Subject: [PATCH 01/10] feat: explicit provider for WOPI apps to handle fileinfo --- .../pkg/connector/fileconnector.go | 118 ++++---- .../pkg/connector/fileinfo/collabora.go | 108 ++++++++ .../pkg/connector/fileinfo/fileinfo.go | 103 +++++++ .../{fileinfo.go => fileinfo/microsoft.go} | 261 ++++++------------ .../pkg/connector/fileinfo/onlyoffice.go | 188 +++++++++++++ 5 files changed, 551 insertions(+), 227 deletions(-) create mode 100644 services/collaboration/pkg/connector/fileinfo/collabora.go create mode 100644 services/collaboration/pkg/connector/fileinfo/fileinfo.go rename services/collaboration/pkg/connector/{fileinfo.go => fileinfo/microsoft.go} (60%) create mode 100644 services/collaboration/pkg/connector/fileinfo/onlyoffice.go diff --git a/services/collaboration/pkg/connector/fileconnector.go b/services/collaboration/pkg/connector/fileconnector.go index a498bc3e2..18a8093b3 100644 --- a/services/collaboration/pkg/connector/fileconnector.go +++ b/services/collaboration/pkg/connector/fileconnector.go @@ -17,6 +17,7 @@ import ( "github.com/cs3org/reva/v2/pkg/utils" "github.com/google/uuid" "github.com/owncloud/ocis/v2/services/collaboration/pkg/config" + "github.com/owncloud/ocis/v2/services/collaboration/pkg/connector/fileinfo" "github.com/owncloud/ocis/v2/services/collaboration/pkg/middleware" "github.com/rs/zerolog" ) @@ -50,7 +51,7 @@ type FileConnectorService interface { // The current lockID will be returned if a conflict happens UnLock(ctx context.Context, lockID string) (string, error) // CheckFileInfo will return the file information of the target file - CheckFileInfo(ctx context.Context) (FileInfo, error) + CheckFileInfo(ctx context.Context) (fileinfo.FileInfo, error) } // FileConnector implements the "File" endpoint. @@ -475,10 +476,10 @@ func (f *FileConnector) UnLock(ctx context.Context, lockID string) (string, erro // // If the operation is successful, a "FileInfo" instance will be returned, // otherwise the "FileInfo" will be empty and an error will be returned. -func (f *FileConnector) CheckFileInfo(ctx context.Context) (FileInfo, error) { +func (f *FileConnector) CheckFileInfo(ctx context.Context) (fileinfo.FileInfo, error) { wopiContext, err := middleware.WopiContextFromCtx(ctx) if err != nil { - return FileInfo{}, err + return nil, err } logger := zerolog.Ctx(ctx) @@ -488,7 +489,7 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (FileInfo, error) { }) if err != nil { logger.Error().Err(err).Msg("CheckFileInfo: stat failed") - return FileInfo{}, err + return nil, err } if statRes.GetStatus().GetCode() != rpcv1beta1.Code_CODE_OK { @@ -496,76 +497,87 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (FileInfo, error) { Str("StatusCode", statRes.GetStatus().GetCode().String()). Str("StatusMsg", statRes.GetStatus().GetMessage()). Msg("CheckFileInfo: stat failed with unexpected status") - return FileInfo{}, NewConnectorError(500, statRes.GetStatus().GetCode().String()+" "+statRes.GetStatus().GetMessage()) + return nil, NewConnectorError(500, statRes.GetStatus().GetCode().String()+" "+statRes.GetStatus().GetMessage()) } - fileInfo := FileInfo{ - // OwnerId must use only alphanumeric chars (https://learn.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/checkfileinfo/checkfileinfo-response#requirements-for-user-identity-properties) - OwnerId: hex.EncodeToString([]byte(statRes.GetInfo().GetOwner().GetOpaqueId() + "@" + statRes.GetInfo().GetOwner().GetIdp())), - Size: int64(statRes.GetInfo().GetSize()), - Version: strconv.FormatUint(statRes.GetInfo().GetMtime().GetSeconds(), 10) + "." + strconv.FormatUint(uint64(statRes.GetInfo().GetMtime().GetNanos()), 10), - BaseFileName: path.Base(statRes.GetInfo().GetPath()), - BreadcrumbDocName: path.Base(statRes.GetInfo().GetPath()), + var info fileinfo.FileInfo + switch strings.ToLower(f.cfg.WopiApp.Provider) { + case "collabora": + info = &fileinfo.Collabora{} + case "onlyoffice": + info = &fileinfo.OnlyOffice{} + default: + info = &fileinfo.Microsoft{} + } + + hexEncodedOwnerId := hex.EncodeToString([]byte(statRes.GetInfo().GetOwner().GetOpaqueId() + "@" + statRes.GetInfo().GetOwner().GetIdp())) + version := strconv.FormatUint(statRes.GetInfo().GetMtime().GetSeconds(), 10) + "." + strconv.FormatUint(uint64(statRes.GetInfo().GetMtime().GetNanos()), 10) + + // UserId must use only alphanumeric chars (https://learn.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/checkfileinfo/checkfileinfo-response#requirements-for-user-identity-properties) + // assign userId, userFriendlyName and isAnonymousUser + // assume we don't have a wopiContext.User + randomID, _ := uuid.NewUUID() + userId := hex.EncodeToString([]byte("guest-" + randomID.String())) + userFriendlyName := "Guest " + randomID.String() + isAnonymousUser := true + + isPublicShare := false + if wopiContext.User != nil { + // if we have a wopiContext.User + isPublicShare = utils.ExistsInOpaque(wopiContext.User.GetOpaque(), "public-share-role") + if !isPublicShare { + hexEncodedWopiUserId := hex.EncodeToString([]byte(wopiContext.User.GetId().GetOpaqueId() + "@" + wopiContext.User.GetId().GetIdp())) + isAnonymousUser = false + userFriendlyName = wopiContext.User.GetDisplayName() + userId = hexEncodedWopiUserId + } + } + + // fileinfo map + infoMap := map[string]interface{}{ + "OwnerId": hexEncodedOwnerId, + "Size": int64(statRes.GetInfo().GetSize()), + "Version": version, + "BaseFileName": path.Base(statRes.GetInfo().GetPath()), + "BreadcrumbDocName": path.Base(statRes.GetInfo().GetPath()), // to get the folder we actually need to do a GetPath() request //BreadcrumbFolderName: path.Dir(statRes.Info.Path), - UserCanNotWriteRelative: true, + "HostViewUrl": wopiContext.ViewAppUrl, + "HostEditUrl": wopiContext.EditAppUrl, - HostViewUrl: wopiContext.ViewAppUrl, - HostEditUrl: wopiContext.EditAppUrl, + "EnableOwnerTermination": true, // only for collabora + "SupportsExtendedLockLength": true, + "SupportsGetLock": true, + "SupportsLocks": true, + "SupportsUpdate": true, - //EnableOwnerTermination: true, // enable only for collabora? wopivalidator is complaining - EnableOwnerTermination: false, - - SupportsExtendedLockLength: true, - - SupportsGetLock: true, - SupportsLocks: true, - } - - // user logic from reva wopi driver #TODO: refactor - var isPublicShare bool = false - if wopiContext.User != nil { - // UserId must use only alphanumeric chars (https://learn.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/checkfileinfo/checkfileinfo-response#requirements-for-user-identity-properties) - if wopiContext.User.GetId().GetType() == userv1beta1.UserType_USER_TYPE_LIGHTWEIGHT { - fileInfo.UserId = hex.EncodeToString([]byte(statRes.GetInfo().GetOwner().GetOpaqueId() + "@" + statRes.GetInfo().GetOwner().GetIdp())) - } else { - fileInfo.UserId = hex.EncodeToString([]byte(wopiContext.User.GetId().GetOpaqueId() + "@" + wopiContext.User.GetId().GetIdp())) - } - - isPublicShare = utils.ExistsInOpaque(wopiContext.User.GetOpaque(), "public-share-role") - if !isPublicShare { - fileInfo.UserFriendlyName = wopiContext.User.GetDisplayName() - fileInfo.UserId = hex.EncodeToString([]byte(wopiContext.User.GetId().GetOpaqueId() + "@" + wopiContext.User.GetId().GetIdp())) - } - } - if wopiContext.User == nil || isPublicShare { - randomID, _ := uuid.NewUUID() - fileInfo.UserId = hex.EncodeToString([]byte("guest-" + randomID.String())) - fileInfo.UserFriendlyName = "Guest " + randomID.String() - fileInfo.IsAnonymousUser = true + "UserCanNotWriteRelative": true, + "IsAnonymousUser": isAnonymousUser, + "UserFriendlyName": userFriendlyName, + "UserId": userId, } switch wopiContext.ViewMode { case appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE: - fileInfo.SupportsUpdate = true - fileInfo.UserCanWrite = true + infoMap["UserCanWrite"] = true case appproviderv1beta1.ViewMode_VIEW_MODE_READ_ONLY: // nothing special to do here for now case appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY: - fileInfo.DisableExport = true - fileInfo.DisableCopy = true - fileInfo.DisablePrint = true + infoMap["DisableExport"] = true + infoMap["DisableCopy"] = true + infoMap["DisablePrint"] = true if !isPublicShare { - // the fileInfo.WatermarkText supported by Collabora only - fileInfo.WatermarkText = f.watermarkText(wopiContext.User) + infoMap["WatermarkText"] = f.watermarkText(wopiContext.User) // only for collabora } } + info.SetProperties(infoMap) + logger.Debug().Msg("CheckFileInfo: success") - return fileInfo, nil + return info, nil } func (f *FileConnector) watermarkText(user *userv1beta1.User) string { diff --git a/services/collaboration/pkg/connector/fileinfo/collabora.go b/services/collaboration/pkg/connector/fileinfo/collabora.go new file mode 100644 index 000000000..c53ca305f --- /dev/null +++ b/services/collaboration/pkg/connector/fileinfo/collabora.go @@ -0,0 +1,108 @@ +package fileinfo + +// Collabora fileInfo properties +// +// Collabora WOPI check file info specification: +// https://sdk.collaboraonline.com/docs/advanced_integration.html +type Collabora struct { + // + // Response properties + // + + // Copied from MS WOPI + BaseFileName string `json:"BaseFileName,omitempty"` + // Copied from MS WOPI + DisablePrint bool `json:"DisablePrint"` + // Copied from MS WOPI + OwnerId string `json:"OwnerId,omitempty"` + // A string for the domain the host page sends/receives PostMessages from, we only listen to messages from this domain. + PostMessageOrigin string `json:"PostMessageOrigin,omitempty"` + // copied from MS WOPI + Size int64 `json:"Size"` + // The ID of file (like the wopi/files/ID) can be a non-existing file. In that case, the file will be created from a template when the template (eg. an OTT file) is specified as TemplateSource in the CheckFileInfo response. The TemplateSource is supposed to be an URL like https://somewhere/accessible/file.ott that is accessible by the Online. For the actual saving of the content, normal PutFile mechanism will be used. + TemplateSource string `json:"TemplateSource,omitempty"` + // copied from MS WOPI + UserCanWrite bool `json:"UserCanWrite"` + // copied from MS WOPI + UserCanNotWriteRelative bool `json:"UserCanNotWriteRelative"` + // copied from MS WOPI + UserId string `json:"UserId,omitempty"` + // copied from MS WOPI + UserFriendlyName string `json:"UserFriendlyName,omitempty"` + + // + // Extended response properties + // + + // If set to true, this will enable the insertion of images chosen from the WOPI storage. A UI_InsertGraphic postMessage will be send to the WOPI host to request the UI to select the file. + EnableInsertRemoteImage bool `json:"EnableInsertRemoteImage,omitempty"` + // If set to true, this will disable the insertion of image chosen from the local device. If EnableInsertRemoteImage is not set to true, then inserting images files is not possible. + DisableInsertLocalImage bool `json:"DisableInsertLocalImage,omitempty"` + // If set to true, hides the print option from the file menu bar in the UI. + HidePrintOption bool `json:"HidePrintOption,omitempty"` + // If set to true, hides the save button from the toolbar and file menubar in the UI. + HideSaveOption bool `json:"HideSaveOption,omitempty"` + // Hides Download as option in the file menubar. + HideExportOption bool `json:"HideExportOption,omitempty"` + // Disables export functionality in backend. If set to true, HideExportOption is assumed to be true + DisableExport bool `json:"DisableExport,omitempty"` + // Disables copying from the document in libreoffice online backend. Pasting into the document would still be possible. However, it is still possible to do an “internal” cut/copy/paste. + DisableCopy bool `json:"DisableCopy,omitempty"` + // Disables displaying of the explanation text on the overlay when the document becomes inactive or killed. With this, the JS integration must provide the user with appropriate message when it gets Session_Closed or User_Idle postMessages. + DisableInactiveMessages bool `json:"DisableInactiveMessages,omitempty"` + // Indicate that the integration wants to handle the downloading of pdf for printing or svg for slideshows or exported document, because it cannot rely on browser’s support for downloading. + DownloadAsPostMessage bool `json:"DownloadAsPostMessage,omitempty"` + // Similar to download as, doctype extensions can be provided for save-as. In this case the new file is loaded in the integration instead of downloaded. + SaveAsPostmessage bool `json:"SaveAsPostmessage,omitempty"` + // If set to true, it allows the document owner (the one with OwnerId =UserId) to send a closedocument message (see protocol.txt) + EnableOwnerTermination bool `json:"EnableOwnerTermination,omitempty"` + + // JSON object that contains additional info about the user, namely the avatar image. + //UserExtraInfo -> requires definition, currently not used + // JSON object that contains additional info about the user, but unlike the UserExtraInfo it is not shared among the views in collaborative editing sessions. + //UserPrivateInfo -> requires definition, currently not used + + // If set to a non-empty string, is used for rendering a watermark-like text on each tile of the document. + WatermarkText string `json:"WatermarkText,omitempty"` +} + +func (cinfo *Collabora) SetProperties(props map[string]interface{}) { + setters := map[string]func(value interface{}){ + "BaseFileName": assignStringTo(&cinfo.BaseFileName), + "DisablePrint": assignBoolTo(&cinfo.DisablePrint), + "OwnerId": assignStringTo(&cinfo.OwnerId), + "PostMessageOrigin": assignStringTo(&cinfo.PostMessageOrigin), + "Size": assignInt64To(&cinfo.Size), + "TemplateSource": assignStringTo(&cinfo.TemplateSource), + "UserCanWrite": assignBoolTo(&cinfo.UserCanWrite), + "UserCanNotWriteRelative": assignBoolTo(&cinfo.UserCanNotWriteRelative), + "UserId": assignStringTo(&cinfo.UserId), + "UserFriendlyName": assignStringTo(&cinfo.UserFriendlyName), + + "EnableInsertRemoteImage": assignBoolTo(&cinfo.EnableInsertRemoteImage), + "DisableInsertLocalImage": assignBoolTo(&cinfo.DisableInsertLocalImage), + "HidePrintOption": assignBoolTo(&cinfo.HidePrintOption), + "HideSaveOption": assignBoolTo(&cinfo.HideSaveOption), + "HideExportOption": assignBoolTo(&cinfo.HideExportOption), + "DisableExport": assignBoolTo(&cinfo.DisableExport), + "DisableCopy": assignBoolTo(&cinfo.DisableCopy), + "DisableInactiveMessages": assignBoolTo(&cinfo.DisableInactiveMessages), + "DownloadAsPostMessage": assignBoolTo(&cinfo.DownloadAsPostMessage), + "SaveAsPostmessage": assignBoolTo(&cinfo.SaveAsPostmessage), + "EnableOwnerTermination": assignBoolTo(&cinfo.EnableOwnerTermination), + //UserExtraInfo -> requires definition, currently not used + //UserPrivateInfo -> requires definition, currently not used + "WatermarkText": assignStringTo(&cinfo.WatermarkText), + } + + for key, value := range props { + setterFn := setters[key] + if setterFn != nil { + setterFn(value) + } + } +} + +func (cinfo *Collabora) GetTarget() string { + return "Collabora" +} diff --git a/services/collaboration/pkg/connector/fileinfo/fileinfo.go b/services/collaboration/pkg/connector/fileinfo/fileinfo.go new file mode 100644 index 000000000..63d6c485a --- /dev/null +++ b/services/collaboration/pkg/connector/fileinfo/fileinfo.go @@ -0,0 +1,103 @@ +package fileinfo + +// FileInfo contains the properties of the file. +// Some properties refer to capabilities in the WOPI client, and capabilities +// that the WOPI server has. +// +// Specific implementations must allow json-encoding of their relevant +// properties because the object will be marshalled directly +type FileInfo interface { + // SetProperties will set the properties of this FileInfo. + // Keys should match any valid property that the FileInfo implementation + // has. If a key doesn't match any property, it must be ignored. + // The values must have its matching type for the target property, + // otherwise panics might happen. + // + // This method should help to reduce the friction of using different + // implementations with different properties. You can use the same map + // for all the implementations knowing that the relevant properties for + // each implementation will be set. + SetProperties(props map[string]interface{}) + + // GetTarget will return the target implementation (OnlyOffice, Collabora...). + // This will help to identify the implementation we're using in an easy way. + // Note that the returned value must be unique among all the implementations + GetTarget() string +} + +// assignStringTo will return a function whose parameter will be assigned +// to the provided key. The function will panic if the assignment isn't +// possible. +// +// fn := AssignStringTo(&target) +// fn(value) +// +// Is roughly equivalent to +// +// target = value +// +// The reason for this method is to help the `SetProperties` method in order +// to provide a setter function for each property. +// Expected code for the `SetProperties` should be similar to +// +// setters := map[string]func(value interface{}) { +// "Owner": AssignStringTo(&info.Owner), +// "DisplayName": AssignStringTo(&info.DisplayName), +// ..... +// } +// for key, value := range props { +// fn := setters[key] +// fn(value) +// } +// +// Further `assign*To` functions will be provided to be able to assign +// different data types +func assignStringTo(targetKey *string) func(value interface{}) { + return func(value interface{}) { + *targetKey = value.(string) + } +} + +// assignStringListTo will return a function whose parameter will be assigned +// to the provided key. The function will panic if the assignment isn't +// possible. +// +// See assignStringTo for more information +func assignStringListTo(targetKey *[]string) func(value interface{}) { + return func(value interface{}) { + *targetKey = value.([]string) + } +} + +// assignInt64To will return a function whose parameter will be assigned +// to the provided key. The function will panic if the assignment isn't +// possible. +// +// See assignStringTo for more information +func assignInt64To(targetKey *int64) func(value interface{}) { + return func(value interface{}) { + *targetKey = value.(int64) + } +} + +// assignIntTo will return a function whose parameter will be assigned +// to the provided key. The function will panic if the assignment isn't +// possible. +// +// See assignStringTo for more information +func assignIntTo(targetKey *int) func(value interface{}) { + return func(value interface{}) { + *targetKey = value.(int) + } +} + +// assignBoolTo will return a function whose parameter will be assigned +// to the provided key. The function will panic if the assignment isn't +// possible. +// +// See assignStringTo for more information +func assignBoolTo(targetKey *bool) func(value interface{}) { + return func(value interface{}) { + *targetKey = value.(bool) + } +} diff --git a/services/collaboration/pkg/connector/fileinfo.go b/services/collaboration/pkg/connector/fileinfo/microsoft.go similarity index 60% rename from services/collaboration/pkg/connector/fileinfo.go rename to services/collaboration/pkg/connector/fileinfo/microsoft.go index 946656840..f65b2576c 100644 --- a/services/collaboration/pkg/connector/fileinfo.go +++ b/services/collaboration/pkg/connector/fileinfo/microsoft.go @@ -1,17 +1,10 @@ -package connector +package fileinfo -// FileInfo contains the properties of the file. -// Some properties refer to capabilities in the WOPI client, and capabilities -// that the WOPI server has. +// Microsoft fileInfo properties // -// For now, the FileInfo contains data for Microsoft, Collabora and OnlyOffice. -// Not all the properties are supported by every system. -type FileInfo struct { - // ------------ - // Microsoft WOPI check file info specification: - // https://docs.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/checkfileinfo - // ------------ - +// Microsoft WOPI check file info specification: +// https://docs.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/checkfileinfo +type Microsoft struct { // // Required response properties // @@ -168,166 +161,86 @@ type FileInfo struct { BreadcrumbFolderName string `json:"BreadcrumbFolderName,omitempty"` // A URI to a web page that the WOPI client should navigate to when the user clicks on UI that displays BreadcrumbFolderName. BreadcrumbFolderUrl string `json:"BreadcrumbFolderUrl,omitempty"` - - // ------------ - // Collabora WOPI check file info specification: - // https://sdk.collaboraonline.com/docs/advanced_integration.html - // ------------ - - // - // Response properties - // - - //BaseFileName -> already in MS WOPI - //DisablePrint -> already in MS WOPI - //OwnerID -> already in MS WOPI - - // A string for the domain the host page sends/receives PostMessages from, we only listen to messages from this domain. - PostMessageOrigin string `json:"PostMessageOrigin,omitempty"` - - //Size -> already in MS WOPI - - // The ID of file (like the wopi/files/ID) can be a non-existing file. In that case, the file will be created from a template when the template (eg. an OTT file) is specified as TemplateSource in the CheckFileInfo response. The TemplateSource is supposed to be an URL like https://somewhere/accessible/file.ott that is accessible by the Online. For the actual saving of the content, normal PutFile mechanism will be used. - TemplateSource string `json:"TemplateSource,omitempty"` - - //UserCanWrite -> already in MS WOPI - //UserCanNotWriteRelative -> already in MS WOPI - //UserId -> already in MS WOPI - //UserFriendlyName -> already in MS WOPI - - // - // Extended response properties - // - - // If set to true, this will enable the insertion of images chosen from the WOPI storage. A UI_InsertGraphic postMessage will be send to the WOPI host to request the UI to select the file. - EnableInsertRemoteImage bool `json:"EnableInsertRemoteImage,omitempty"` - // If set to true, this will disable the insertion of image chosen from the local device. If EnableInsertRemoteImage is not set to true, then inserting images files is not possible. - DisableInsertLocalImage bool `json:"DisableInsertLocalImage,omitempty"` - // If set to true, hides the print option from the file menu bar in the UI. - HidePrintOption bool `json:"HidePrintOption,omitempty"` - // If set to true, hides the save button from the toolbar and file menubar in the UI. - HideSaveOption bool `json:"HideSaveOption,omitempty"` - // Hides Download as option in the file menubar. - HideExportOption bool `json:"HideExportOption,omitempty"` - // Disables export functionality in backend. If set to true, HideExportOption is assumed to be true - DisableExport bool `json:"DisableExport,omitempty"` - // Disables copying from the document in libreoffice online backend. Pasting into the document would still be possible. However, it is still possible to do an “internal” cut/copy/paste. - DisableCopy bool `json:"DisableCopy,omitempty"` - // Disables displaying of the explanation text on the overlay when the document becomes inactive or killed. With this, the JS integration must provide the user with appropriate message when it gets Session_Closed or User_Idle postMessages. - DisableInactiveMessages bool `json:"DisableInactiveMessages,omitempty"` - // Indicate that the integration wants to handle the downloading of pdf for printing or svg for slideshows or exported document, because it cannot rely on browser’s support for downloading. - DownloadAsPostMessage bool `json:"DownloadAsPostMessage,omitempty"` - // Similar to download as, doctype extensions can be provided for save-as. In this case the new file is loaded in the integration instead of downloaded. - SaveAsPostmessage bool `json:"SaveAsPostmessage,omitempty"` - // If set to true, it allows the document owner (the one with OwnerId =UserId) to send a closedocument message (see protocol.txt) - EnableOwnerTermination bool `json:"EnableOwnerTermination,omitempty"` - - // JSON object that contains additional info about the user, namely the avatar image. - //UserExtraInfo -> requires definition, currently not used - // JSON object that contains additional info about the user, but unlike the UserExtraInfo it is not shared among the views in collaborative editing sessions. - //UserPrivateInfo -> requires definition, currently not used - - // If set to a non-empty string, is used for rendering a watermark-like text on each tile of the document. - WatermarkText string `json:"WatermarkText,omitempty"` - - // ------------ - // OnlyOffice WOPI check file info specification: - // https://api.onlyoffice.com/editors/wopi/restapi/checkfileinfo - // ------------ - - // - // Required response properties - // - - //BaseFileName -> already in MS WOPI - //Version -> already in MS WOPI - - // - // Breadcrumb properties - // - - //BreadcrumbBrandName -> already in MS WOPI - //BreadcrumbBrandUrl -> already in MS WOPI - //BreadcrumbDocName -> already in MS WOPI - //BreadcrumbFolderName -> already in MS WOPI - //BreadcrumbFolderUrl -> already in MS WOPI - - // - // PostMessage properties - // - - // Specifies if the WOPI client should notify the WOPI server in case the user closes the rendering or editing client currently using this file. The host expects to receive the UI_Close PostMessage when the Close UI in the online office is activated. - ClosePostMessage bool `json:"ClosePostMessage,omitempty"` - // Specifies if the WOPI client should notify the WOPI server in case the user tries to edit a file. The host expects to receive the UI_Edit PostMessage when the Edit UI in the online office is activated. - EditModePostMessage bool `json:"EditModePostMessage,omitempty"` - // Specifies if the WOPI client should notify the WOPI server in case the user tries to edit a file. The host expects to receive the Edit_Notification PostMessage. - EditNotificationPostMessage bool `json:"EditNotificationPostMessage,omitempty"` - // Specifies if the WOPI client should notify the WOPI server in case the user tries to share a file. The host expects to receive the UI_Sharing PostMessage when the Share UI in the online office is activated. - FileSharingPostMessage bool `json:"FileSharingPostMessage,omitempty"` - // Specifies if the WOPI client will notify the WOPI server in case the user tries to navigate to the previous file version. The host expects to receive the UI_FileVersions PostMessage when the Previous Versions UI in the online office is activated. - FileVersionPostMessage bool `json:"FileVersionPostMessage,omitempty"` - // A domain that the WOPI client must use as the targetOrigin parameter when sending messages as described in [W3C-HTML5WEBMSG]. - //PostMessageOrigin -> already in collabora WOPI - - // - // File URL properties - // - - //CloseUrl -> already in MS WOPI - //FileSharingUrl -> already in MS WOPI - //FileVersionUrl -> already in MS WOPI - //HostEditUrl -> already in MS WOPI - - // - // Miscellaneous properties - // - - // Specifies if the WOPI client must disable the Copy and Paste functionality within the application. By default, all Copy and Paste functionality is enabled, i.e. the setting has no effect. Possible property values: - // BlockAll - the Copy and Paste functionality is completely disabled within the application; - // CurrentDocumentOnly - the Copy and Paste functionality is enabled but content can only be copied and pasted within the file currently open in the application. - //CopyPasteRestrictions -> already in MS WOPI - //DisablePrint -> already in MS WOPI - //FileExtension -> already in MS WOPI - //FileNameMaxLength -> already in MS WOPI - //LastModifiedTime -> already in MS WOPI - - // - // User metadata properties - // - - //IsAnonymousUser -> already in MS WOPI - //UserFriendlyName -> already in MS WOPI - //UserId -> already in MS WOPI - - // - // User permissions properties - // - - //ReadOnly -> already in MS WOPI - //UserCanNotWriteRelative -> already in MS WOPI - //UserCanRename -> already in MS WOPI - - // Specifies if the user has permissions to review a file. - UserCanReview bool `json:"UserCanReview,omitempty"` - - //UserCanWrite -> already in MS WOPI - - // - // Host capabilities properties - // - - //SupportsLocks -> already in MS WOPI - //SupportsRename -> already in MS WOPI - - // Specifies if the WOPI server supports the review permission. - SupportsReviewing bool `json:"SupportsReviewing,omitempty"` - - //SupportsUpdate -> already in MS WOPI - - // - // Other properties - // - - //EnableInsertRemoteImage -> already in collabora WOPI - //HidePrintOption -> already in collabora WOPI +} + +func (minfo *Microsoft) SetProperties(props map[string]interface{}) { + setters := map[string]func(value interface{}){ + "BaseFileName": assignStringTo(&minfo.BaseFileName), + "OwnerId": assignStringTo(&minfo.OwnerId), + "Size": assignInt64To(&minfo.Size), + "UserId": assignStringTo(&minfo.UserId), + "Version": assignStringTo(&minfo.Version), + + "SupportedShareUrlTypes": assignStringListTo(&minfo.SupportedShareUrlTypes), + "SupportsCobalt": assignBoolTo(&minfo.SupportsCobalt), + "SupportsContainers": assignBoolTo(&minfo.SupportsContainers), + "SupportsDeleteFile": assignBoolTo(&minfo.SupportsDeleteFile), + "SupportsEcosystem": assignBoolTo(&minfo.SupportsEcosystem), + "SupportsExtendedLockLength": assignBoolTo(&minfo.SupportsExtendedLockLength), + "SupportsFolders": assignBoolTo(&minfo.SupportsFolders), + //SupportsGetFileWopiSrc bool `json:"SupportsGetFileWopiSrc"` // wopivalidator is complaining and the property isn't used for now -> commented + "SupportsGetLock": assignBoolTo(&minfo.SupportsGetLock), + "SupportsLocks": assignBoolTo(&minfo.SupportsLocks), + "SupportsRename": assignBoolTo(&minfo.SupportsRename), + "SupportsUpdate": assignBoolTo(&minfo.SupportsUpdate), + "SupportsUserInfo": assignBoolTo(&minfo.SupportsUserInfo), + + "IsAnonymousUser": assignBoolTo(&minfo.IsAnonymousUser), + "IsEduUser": assignBoolTo(&minfo.IsEduUser), + "LicenseCheckForEditIsEnabled": assignBoolTo(&minfo.LicenseCheckForEditIsEnabled), + "UserFriendlyName": assignStringTo(&minfo.UserFriendlyName), + "UserInfo": assignStringTo(&minfo.UserInfo), + + "ReadOnly": assignBoolTo(&minfo.ReadOnly), + "RestrictedWebViewOnly": assignBoolTo(&minfo.RestrictedWebViewOnly), + "UserCanAttend": assignBoolTo(&minfo.UserCanAttend), + "UserCanNotWriteRelative": assignBoolTo(&minfo.UserCanNotWriteRelative), + "UserCanPresent": assignBoolTo(&minfo.UserCanPresent), + "UserCanRename": assignBoolTo(&minfo.UserCanRename), + "UserCanWrite": assignBoolTo(&minfo.UserCanWrite), + + "CloseUrl": assignStringTo(&minfo.CloseUrl), + "DownloadUrl": assignStringTo(&minfo.DownloadUrl), + "FileEmbedCommandUrl": assignStringTo(&minfo.FileEmbedCommandUrl), + "FileSharingUrl": assignStringTo(&minfo.FileSharingUrl), + "FileUrl": assignStringTo(&minfo.FileUrl), + "FileVersionUrl": assignStringTo(&minfo.FileVersionUrl), + "HostEditUrl": assignStringTo(&minfo.HostEditUrl), + "HostEmbeddedViewUrl": assignStringTo(&minfo.HostEmbeddedViewUrl), + "HostViewUrl": assignStringTo(&minfo.HostViewUrl), + "SignoutUrl": assignStringTo(&minfo.SignoutUrl), + + "AllowAdditionalMicrosoftServices": assignBoolTo(&minfo.AllowAdditionalMicrosoftServices), + "AllowErrorReportPrompt": assignBoolTo(&minfo.AllowErrorReportPrompt), + "AllowExternalMarketplace": assignBoolTo(&minfo.AllowExternalMarketplace), + "ClientThrottlingProtection": assignStringTo(&minfo.ClientThrottlingProtection), + "CloseButtonClosesWindow": assignBoolTo(&minfo.CloseButtonClosesWindow), + "CopyPasteRestrictions": assignStringTo(&minfo.CopyPasteRestrictions), + "DisablePrint": assignBoolTo(&minfo.DisablePrint), + "DisableTranslation": assignBoolTo(&minfo.DisableTranslation), + "FileExtension": assignStringTo(&minfo.FileExtension), + "FileNameMaxLength": assignIntTo(&minfo.FileNameMaxLength), + "LastModifiedTime": assignStringTo(&minfo.LastModifiedTime), + "RequestedCallThrottling": assignStringTo(&minfo.RequestedCallThrottling), + "SHA256": assignStringTo(&minfo.SHA256), + "SharingStatus": assignStringTo(&minfo.SharingStatus), + "TemporarilyNotWritable": assignBoolTo(&minfo.TemporarilyNotWritable), + + "BreadcrumbBrandName": assignStringTo(&minfo.BreadcrumbBrandName), + "BreadcrumbBrandUrl": assignStringTo(&minfo.BreadcrumbBrandUrl), + "BreadcrumbDocName": assignStringTo(&minfo.BreadcrumbDocName), + "BreadcrumbFolderName": assignStringTo(&minfo.BreadcrumbFolderName), + "BreadcrumbFolderUrl": assignStringTo(&minfo.BreadcrumbFolderUrl), + } + + for key, value := range props { + setterFn := setters[key] + if setterFn != nil { + setterFn(value) + } + } +} + +func (minfo *Microsoft) GetTarget() string { + return "Microsoft" } diff --git a/services/collaboration/pkg/connector/fileinfo/onlyoffice.go b/services/collaboration/pkg/connector/fileinfo/onlyoffice.go new file mode 100644 index 000000000..f10eaeb34 --- /dev/null +++ b/services/collaboration/pkg/connector/fileinfo/onlyoffice.go @@ -0,0 +1,188 @@ +package fileinfo + +// OnlyOffice fileInfo properties +// +// OnlyOffice WOPI check file info specification: +// https://api.onlyoffice.com/editors/wopi/restapi/checkfileinfo +type OnlyOffice struct { + // + // Required response properties + // + + // copied from MS WOPI + BaseFileName string `json:"BaseFileName,omitempty"` + // copied from MS WOPI + Version string `json:"Version,omitempty"` + + // + // Breadcrumb properties + // + + // copied from MS WOPI + BreadcrumbBrandName string `json:"BreadcrumbBrandName,omitempty"` + // copied from MS WOPI + BreadcrumbBrandUrl string `json:"BreadcrumbBrandUrl,omitempty"` + // copied from MS WOPI + BreadcrumbDocName string `json:"BreadcrumbDocName,omitempty"` + // copied from MS WOPI + BreadcrumbFolderName string `json:"BreadcrumbFolderName,omitempty"` + // copied from MS WOPI + BreadcrumbFolderUrl string `json:"BreadcrumbFolderUrl,omitempty"` + + // + // PostMessage properties + // + + // Specifies if the WOPI client should notify the WOPI server in case the user closes the rendering or editing client currently using this file. The host expects to receive the UI_Close PostMessage when the Close UI in the online office is activated. + ClosePostMessage bool `json:"ClosePostMessage,omitempty"` + // Specifies if the WOPI client should notify the WOPI server in case the user tries to edit a file. The host expects to receive the UI_Edit PostMessage when the Edit UI in the online office is activated. + EditModePostMessage bool `json:"EditModePostMessage,omitempty"` + // Specifies if the WOPI client should notify the WOPI server in case the user tries to edit a file. The host expects to receive the Edit_Notification PostMessage. + EditNotificationPostMessage bool `json:"EditNotificationPostMessage,omitempty"` + // Specifies if the WOPI client should notify the WOPI server in case the user tries to share a file. The host expects to receive the UI_Sharing PostMessage when the Share UI in the online office is activated. + FileSharingPostMessage bool `json:"FileSharingPostMessage,omitempty"` + // Specifies if the WOPI client will notify the WOPI server in case the user tries to navigate to the previous file version. The host expects to receive the UI_FileVersions PostMessage when the Previous Versions UI in the online office is activated. + FileVersionPostMessage bool `json:"FileVersionPostMessage,omitempty"` + // A domain that the WOPI client must use as the targetOrigin parameter when sending messages as described in [W3C-HTML5WEBMSG]. + // copied from collabora WOPI + PostMessageOrigin string `json:"PostMessageOrigin,omitempty"` + + // + // File URL properties + // + + // copied from MS WOPI + CloseUrl string `json:"CloseUrl,omitempty"` + // copied from MS WOPI + FileSharingUrl string `json:"FileSharingUrl,omitempty"` + // copied from MS WOPI + FileVersionUrl string `json:"FileVersionUrl,omitempty"` + // copied from MS WOPI + HostEditUrl string `json:"HostEditUrl,omitempty"` + + // + // Miscellaneous properties + // + + // Specifies if the WOPI client must disable the Copy and Paste functionality within the application. By default, all Copy and Paste functionality is enabled, i.e. the setting has no effect. Possible property values: + // BlockAll - the Copy and Paste functionality is completely disabled within the application; + // CurrentDocumentOnly - the Copy and Paste functionality is enabled but content can only be copied and pasted within the file currently open in the application. + // copied from MS WOPI + CopyPasteRestrictions string `json:"CopyPasteRestrictions,omitempty"` + // copied from MS WOPI + DisablePrint bool `json:"DisablePrint"` + // copied from MS WOPI + FileExtension string `json:"FileExtension,omitempty"` + // copied from MS WOPI + FileNameMaxLength int `json:"FileNameMaxLength,omitempty"` + // copied from MS WOPI + LastModifiedTime string `json:"LastModifiedTime,omitempty"` + + // + // User metadata properties + // + + // copied from MS WOPI + IsAnonymousUser bool `json:"IsAnonymousUser,omitempty"` + // copied from MS WOPI + UserFriendlyName string `json:"UserFriendlyName,omitempty"` + // copied from MS WOPI + UserId string `json:"UserId,omitempty"` + + // + // User permissions properties + // + + // copied from MS WOPI + ReadOnly bool `json:"ReadOnly"` + // copied from MS WOPI + UserCanNotWriteRelative bool `json:"UserCanNotWriteRelative"` + // copied from MS WOPI + UserCanRename bool `json:"UserCanRename"` + // Specifies if the user has permissions to review a file. + UserCanReview bool `json:"UserCanReview,omitempty"` + // copied from MS WOPI + UserCanWrite bool `json:"UserCanWrite"` + + // + // Host capabilities properties + // + + // copied from MS WOPI + SupportsLocks bool `json:"SupportsLocks"` + // copied from MS WOPI + SupportsRename bool `json:"SupportsRename"` + // Specifies if the WOPI server supports the review permission. + SupportsReviewing bool `json:"SupportsReviewing,omitempty"` + // copied from MS WOPI + SupportsUpdate bool `json:"SupportsUpdate"` // whether "Putfile" and "PutRelativeFile" work + + // + // Other properties + // + + // copied from collabora WOPI + EnableInsertRemoteImage bool `json:"EnableInsertRemoteImage,omitempty"` + // copied from collabora WOPI + HidePrintOption bool `json:"HidePrintOption,omitempty"` +} + +func (oinfo *OnlyOffice) SetProperties(props map[string]interface{}) { + setters := map[string]func(value interface{}){ + "BaseFileName": assignStringTo(&oinfo.BaseFileName), + "Version": assignStringTo(&oinfo.Version), + + "BreadcrumbBrandName": assignStringTo(&oinfo.BreadcrumbBrandName), + "BreadcrumbBrandUrl": assignStringTo(&oinfo.BreadcrumbBrandUrl), + "BreadcrumbDocName": assignStringTo(&oinfo.BreadcrumbDocName), + "BreadcrumbFolderName": assignStringTo(&oinfo.BreadcrumbFolderName), + "BreadcrumbFolderUrl": assignStringTo(&oinfo.BreadcrumbFolderUrl), + + "ClosePostMessage": assignBoolTo(&oinfo.ClosePostMessage), + "EditModePostMessage": assignBoolTo(&oinfo.EditModePostMessage), + "EditNotificationPostMessage": assignBoolTo(&oinfo.EditNotificationPostMessage), + "FileSharingPostMessage": assignBoolTo(&oinfo.FileSharingPostMessage), + "FileVersionPostMessage": assignBoolTo(&oinfo.FileVersionPostMessage), + "PostMessageOrigin": assignStringTo(&oinfo.PostMessageOrigin), + + "CloseUrl": assignStringTo(&oinfo.CloseUrl), + "FileSharingUrl": assignStringTo(&oinfo.FileSharingUrl), + "FileVersionUrl": assignStringTo(&oinfo.FileVersionUrl), + "HostEditUrl": assignStringTo(&oinfo.HostEditUrl), + + "CopyPasteRestrictions": assignStringTo(&oinfo.CopyPasteRestrictions), + "DisablePrint": assignBoolTo(&oinfo.DisablePrint), + "FileExtension": assignStringTo(&oinfo.FileExtension), + "FileNameMaxLength": assignIntTo(&oinfo.FileNameMaxLength), + "LastModifiedTime": assignStringTo(&oinfo.LastModifiedTime), + + "IsAnonymousUser": assignBoolTo(&oinfo.IsAnonymousUser), + "UserFriendlyName": assignStringTo(&oinfo.UserFriendlyName), + "UserId": assignStringTo(&oinfo.UserId), + + "ReadOnly": assignBoolTo(&oinfo.ReadOnly), + "UserCanNotWriteRelative": assignBoolTo(&oinfo.UserCanNotWriteRelative), + "UserCanRename": assignBoolTo(&oinfo.UserCanRename), + "UserCanReview": assignBoolTo(&oinfo.UserCanReview), + "UserCanWrite": assignBoolTo(&oinfo.UserCanWrite), + + "SupportsLocks": assignBoolTo(&oinfo.SupportsLocks), + "SupportsRename": assignBoolTo(&oinfo.SupportsRename), + "SupportsReviewing": assignBoolTo(&oinfo.SupportsReviewing), + "SupportsUpdate": assignBoolTo(&oinfo.SupportsUpdate), + + "EnableInsertRemoteImage": assignBoolTo(&oinfo.EnableInsertRemoteImage), + "HidePrintOption": assignBoolTo(&oinfo.HidePrintOption), + } + + for key, value := range props { + setterFn := setters[key] + if setterFn != nil { + setterFn(value) + } + } +} + +func (oinfo *OnlyOffice) GetTarget() string { + return "OnlyOffice" +} From 573f3a25bc84f0ec23335bef2dfafa574a0f01bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Mon, 27 May 2024 11:35:44 +0200 Subject: [PATCH 02/10] fix: adjust unit tests --- .../mocks/file_connector_service.go | 19 ++-- .../pkg/connector/fileconnector.go | 4 +- .../pkg/connector/fileconnector_test.go | 92 +++++++++---------- .../pkg/connector/httpadapter_test.go | 13 +-- 4 files changed, 60 insertions(+), 68 deletions(-) diff --git a/services/collaboration/mocks/file_connector_service.go b/services/collaboration/mocks/file_connector_service.go index 7671d8f35..6a156d04f 100644 --- a/services/collaboration/mocks/file_connector_service.go +++ b/services/collaboration/mocks/file_connector_service.go @@ -5,8 +5,7 @@ package mocks import ( context "context" - connector "github.com/owncloud/ocis/v2/services/collaboration/pkg/connector" - + fileinfo "github.com/owncloud/ocis/v2/services/collaboration/pkg/connector/fileinfo" mock "github.com/stretchr/testify/mock" ) @@ -24,22 +23,24 @@ func (_m *FileConnectorService) EXPECT() *FileConnectorService_Expecter { } // CheckFileInfo provides a mock function with given fields: ctx -func (_m *FileConnectorService) CheckFileInfo(ctx context.Context) (connector.FileInfo, error) { +func (_m *FileConnectorService) CheckFileInfo(ctx context.Context) (fileinfo.FileInfo, error) { ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for CheckFileInfo") } - var r0 connector.FileInfo + var r0 fileinfo.FileInfo var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (connector.FileInfo, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context) (fileinfo.FileInfo, error)); ok { return rf(ctx) } - if rf, ok := ret.Get(0).(func(context.Context) connector.FileInfo); ok { + if rf, ok := ret.Get(0).(func(context.Context) fileinfo.FileInfo); ok { r0 = rf(ctx) } else { - r0 = ret.Get(0).(connector.FileInfo) + if ret.Get(0) != nil { + r0 = ret.Get(0).(fileinfo.FileInfo) + } } if rf, ok := ret.Get(1).(func(context.Context) error); ok { @@ -69,12 +70,12 @@ func (_c *FileConnectorService_CheckFileInfo_Call) Run(run func(ctx context.Cont return _c } -func (_c *FileConnectorService_CheckFileInfo_Call) Return(_a0 connector.FileInfo, _a1 error) *FileConnectorService_CheckFileInfo_Call { +func (_c *FileConnectorService_CheckFileInfo_Call) Return(_a0 fileinfo.FileInfo, _a1 error) *FileConnectorService_CheckFileInfo_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *FileConnectorService_CheckFileInfo_Call) RunAndReturn(run func(context.Context) (connector.FileInfo, error)) *FileConnectorService_CheckFileInfo_Call { +func (_c *FileConnectorService_CheckFileInfo_Call) RunAndReturn(run func(context.Context) (fileinfo.FileInfo, error)) *FileConnectorService_CheckFileInfo_Call { _c.Call.Return(run) return _c } diff --git a/services/collaboration/pkg/connector/fileconnector.go b/services/collaboration/pkg/connector/fileconnector.go index 18a8093b3..cb7fcba3e 100644 --- a/services/collaboration/pkg/connector/fileconnector.go +++ b/services/collaboration/pkg/connector/fileconnector.go @@ -566,8 +566,8 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (fileinfo.FileInfo, e // nothing special to do here for now case appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY: - infoMap["DisableExport"] = true - infoMap["DisableCopy"] = true + infoMap["DisableExport"] = true // only for collabora + infoMap["DisableCopy"] = true // only for collabora infoMap["DisablePrint"] = true if !isPublicShare { infoMap["WatermarkText"] = f.watermarkText(wopiContext.User) // only for collabora diff --git a/services/collaboration/pkg/connector/fileconnector_test.go b/services/collaboration/pkg/connector/fileconnector_test.go index bc4253067..a70c9302a 100644 --- a/services/collaboration/pkg/connector/fileconnector_test.go +++ b/services/collaboration/pkg/connector/fileconnector_test.go @@ -15,6 +15,7 @@ import ( . "github.com/onsi/gomega" "github.com/owncloud/ocis/v2/services/collaboration/pkg/config" "github.com/owncloud/ocis/v2/services/collaboration/pkg/connector" + "github.com/owncloud/ocis/v2/services/collaboration/pkg/connector/fileinfo" "github.com/owncloud/ocis/v2/services/collaboration/pkg/middleware" "github.com/stretchr/testify/mock" ) @@ -732,7 +733,7 @@ var _ = Describe("FileConnector", func() { ctx := context.Background() newFileInfo, err := fc.CheckFileInfo(ctx) Expect(err).To(HaveOccurred()) - Expect(newFileInfo).To(Equal(connector.FileInfo{})) + Expect(newFileInfo).To(BeNil()) }) It("Stat fails", func() { @@ -746,7 +747,7 @@ var _ = Describe("FileConnector", func() { newFileInfo, err := fc.CheckFileInfo(ctx) Expect(err).To(HaveOccurred()) Expect(err).To(Equal(targetErr)) - Expect(newFileInfo).To(Equal(connector.FileInfo{})) + Expect(newFileInfo).To(BeNil()) }) It("Stat fails status not ok", func() { @@ -760,7 +761,7 @@ var _ = Describe("FileConnector", func() { Expect(err).To(HaveOccurred()) conErr := err.(*connector.ConnectorError) Expect(conErr.HttpCodeOut).To(Equal(500)) - Expect(newFileInfo).To(Equal(connector.FileInfo{})) + Expect(newFileInfo).To(BeNil()) }) It("Stat success", func() { @@ -783,7 +784,7 @@ var _ = Describe("FileConnector", func() { }, }, nil) - expectedFileInfo := connector.FileInfo{ + expectedFileInfo := &fileinfo.Microsoft{ OwnerId: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp Size: int64(998877), Version: "16273849.0", @@ -792,7 +793,6 @@ var _ = Describe("FileConnector", func() { UserCanNotWriteRelative: true, HostViewUrl: "http://test.ex.prv/view", HostEditUrl: "http://test.ex.prv/edit", - EnableOwnerTermination: false, SupportsExtendedLockLength: true, SupportsGetLock: true, SupportsLocks: true, @@ -804,7 +804,7 @@ var _ = Describe("FileConnector", func() { newFileInfo, err := fc.CheckFileInfo(ctx) Expect(err).To(Succeed()) - Expect(newFileInfo).To(Equal(expectedFileInfo)) + Expect(newFileInfo.(*fileinfo.Microsoft)).To(Equal(expectedFileInfo)) }) It("Stat success guests", func() { @@ -839,39 +839,34 @@ var _ = Describe("FileConnector", func() { }, }, nil) - expectedFileInfo := connector.FileInfo{ - OwnerId: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp - Size: int64(998877), - Version: "16273849.0", - BaseFileName: "test.txt", - BreadcrumbDocName: "test.txt", - UserCanNotWriteRelative: true, - HostViewUrl: "http://test.ex.prv/view", - HostEditUrl: "http://test.ex.prv/edit", - EnableOwnerTermination: false, - SupportsExtendedLockLength: true, - SupportsGetLock: true, - SupportsLocks: true, - DisableExport: true, - DisableCopy: true, - DisablePrint: true, - IsAnonymousUser: true, - UserId: "guest-zzz000", - UserFriendlyName: "guest zzz000", + // change wopi app provider + cfg.WopiApp.Provider = "Collabora" + + expectedFileInfo := &fileinfo.Collabora{ + OwnerId: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp + Size: int64(998877), + BaseFileName: "test.txt", + UserCanNotWriteRelative: true, + DisableExport: true, + DisableCopy: true, + DisablePrint: true, + UserId: "guest-zzz000", + UserFriendlyName: "guest zzz000", + EnableOwnerTermination: true, } newFileInfo, err := fc.CheckFileInfo(ctx) // UserId and UserFriendlyName have random Ids generated which are impossible to guess // Check both separately - Expect(newFileInfo.UserId).To(HavePrefix(hex.EncodeToString([]byte("guest-")))) - Expect(newFileInfo.UserFriendlyName).To(HavePrefix("Guest ")) + Expect(newFileInfo.(*fileinfo.Collabora).UserId).To(HavePrefix(hex.EncodeToString([]byte("guest-")))) + Expect(newFileInfo.(*fileinfo.Collabora).UserFriendlyName).To(HavePrefix("Guest ")) // overwrite UserId and UserFriendlyName here for easier matching - newFileInfo.UserId = "guest-zzz000" - newFileInfo.UserFriendlyName = "guest zzz000" + newFileInfo.(*fileinfo.Collabora).UserId = "guest-zzz000" + newFileInfo.(*fileinfo.Collabora).UserFriendlyName = "guest zzz000" Expect(err).To(Succeed()) - Expect(newFileInfo).To(Equal(expectedFileInfo)) + Expect(newFileInfo.(*fileinfo.Collabora)).To(Equal(expectedFileInfo)) }) It("Stat success authenticated user", func() { @@ -897,32 +892,27 @@ var _ = Describe("FileConnector", func() { }, }, nil) - expectedFileInfo := connector.FileInfo{ - OwnerId: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp - Size: int64(998877), - Version: "16273849.0", - BaseFileName: "test.txt", - BreadcrumbDocName: "test.txt", - UserCanNotWriteRelative: true, - HostViewUrl: "http://test.ex.prv/view", - HostEditUrl: "http://test.ex.prv/edit", - EnableOwnerTermination: false, - SupportsExtendedLockLength: true, - SupportsGetLock: true, - SupportsLocks: true, - DisableExport: true, - DisableCopy: true, - DisablePrint: true, - IsAnonymousUser: false, - UserId: hex.EncodeToString([]byte("opaqueId@inmemory")), - UserFriendlyName: "Pet Shaft", - WatermarkText: "Pet Shaft shaft@example.com", + // change wopi app provider + cfg.WopiApp.Provider = "Collabora" + + expectedFileInfo := &fileinfo.Collabora{ + OwnerId: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp + Size: int64(998877), + BaseFileName: "test.txt", + UserCanNotWriteRelative: true, + DisableExport: true, + DisableCopy: true, + DisablePrint: true, + UserId: hex.EncodeToString([]byte("opaqueId@inmemory")), + UserFriendlyName: "Pet Shaft", + EnableOwnerTermination: true, + WatermarkText: "Pet Shaft shaft@example.com", } newFileInfo, err := fc.CheckFileInfo(ctx) Expect(err).To(Succeed()) - Expect(newFileInfo).To(Equal(expectedFileInfo)) + Expect(newFileInfo.(*fileinfo.Collabora)).To(Equal(expectedFileInfo)) }) }) }) diff --git a/services/collaboration/pkg/connector/httpadapter_test.go b/services/collaboration/pkg/connector/httpadapter_test.go index 3a277f5fc..52623e736 100644 --- a/services/collaboration/pkg/connector/httpadapter_test.go +++ b/services/collaboration/pkg/connector/httpadapter_test.go @@ -11,6 +11,7 @@ import ( . "github.com/onsi/gomega" "github.com/owncloud/ocis/v2/services/collaboration/mocks" "github.com/owncloud/ocis/v2/services/collaboration/pkg/connector" + "github.com/owncloud/ocis/v2/services/collaboration/pkg/connector/fileinfo" "github.com/stretchr/testify/mock" ) @@ -337,7 +338,7 @@ var _ = Describe("HttpAdapter", func() { w := httptest.NewRecorder() - fc.On("CheckFileInfo", mock.Anything).Times(1).Return(connector.FileInfo{}, errors.New("Something happened")) + fc.On("CheckFileInfo", mock.Anything).Times(1).Return(&fileinfo.Microsoft{}, errors.New("Something happened")) httpAdapter.CheckFileInfo(w, req) resp := w.Result() @@ -351,7 +352,7 @@ var _ = Describe("HttpAdapter", func() { w := httptest.NewRecorder() - fc.On("CheckFileInfo", mock.Anything).Times(1).Return(connector.FileInfo{}, connector.NewConnectorError(404, "Not found")) + fc.On("CheckFileInfo", mock.Anything).Times(1).Return(&fileinfo.Microsoft{}, connector.NewConnectorError(404, "Not found")) httpAdapter.CheckFileInfo(w, req) resp := w.Result() @@ -364,11 +365,11 @@ var _ = Describe("HttpAdapter", func() { w := httptest.NewRecorder() // might need more info, but should be enough for the test - fileinfo := connector.FileInfo{ + finfo := &fileinfo.Microsoft{ Size: 123456789, BreadcrumbDocName: "testy.docx", } - fc.On("CheckFileInfo", mock.Anything).Times(1).Return(fileinfo, nil) + fc.On("CheckFileInfo", mock.Anything).Times(1).Return(finfo, nil) httpAdapter.CheckFileInfo(w, req) resp := w.Result() @@ -376,9 +377,9 @@ var _ = Describe("HttpAdapter", func() { jsonInfo, _ := io.ReadAll(resp.Body) - var responseInfo connector.FileInfo + var responseInfo *fileinfo.Microsoft json.Unmarshal(jsonInfo, &responseInfo) - Expect(responseInfo).To(Equal(fileinfo)) + Expect(responseInfo).To(Equal(finfo)) }) }) From 1f1b818056861c48a6716b5b052e84a2eb5e20e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Mon, 27 May 2024 14:30:01 +0200 Subject: [PATCH 03/10] fix: change var naming for CI --- .../pkg/connector/fileconnector.go | 8 +-- .../pkg/connector/fileconnector_test.go | 24 +++---- .../pkg/connector/fileinfo/collabora.go | 10 +-- .../pkg/connector/fileinfo/microsoft.go | 62 ++++++++++--------- .../pkg/connector/fileinfo/onlyoffice.go | 30 ++++----- 5 files changed, 70 insertions(+), 64 deletions(-) diff --git a/services/collaboration/pkg/connector/fileconnector.go b/services/collaboration/pkg/connector/fileconnector.go index cb7fcba3e..b08718bc4 100644 --- a/services/collaboration/pkg/connector/fileconnector.go +++ b/services/collaboration/pkg/connector/fileconnector.go @@ -535,7 +535,7 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (fileinfo.FileInfo, e // fileinfo map infoMap := map[string]interface{}{ - "OwnerId": hexEncodedOwnerId, + "OwnerID": hexEncodedOwnerId, "Size": int64(statRes.GetInfo().GetSize()), "Version": version, "BaseFileName": path.Base(statRes.GetInfo().GetPath()), @@ -543,8 +543,8 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (fileinfo.FileInfo, e // to get the folder we actually need to do a GetPath() request //BreadcrumbFolderName: path.Dir(statRes.Info.Path), - "HostViewUrl": wopiContext.ViewAppUrl, - "HostEditUrl": wopiContext.EditAppUrl, + "HostViewURL": wopiContext.ViewAppUrl, + "HostEditURL": wopiContext.EditAppUrl, "EnableOwnerTermination": true, // only for collabora "SupportsExtendedLockLength": true, @@ -555,7 +555,7 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (fileinfo.FileInfo, e "UserCanNotWriteRelative": true, "IsAnonymousUser": isAnonymousUser, "UserFriendlyName": userFriendlyName, - "UserId": userId, + "UserID": userId, } switch wopiContext.ViewMode { diff --git a/services/collaboration/pkg/connector/fileconnector_test.go b/services/collaboration/pkg/connector/fileconnector_test.go index a70c9302a..538da4972 100644 --- a/services/collaboration/pkg/connector/fileconnector_test.go +++ b/services/collaboration/pkg/connector/fileconnector_test.go @@ -785,20 +785,20 @@ var _ = Describe("FileConnector", func() { }, nil) expectedFileInfo := &fileinfo.Microsoft{ - OwnerId: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp + OwnerID: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp Size: int64(998877), Version: "16273849.0", BaseFileName: "test.txt", BreadcrumbDocName: "test.txt", UserCanNotWriteRelative: true, - HostViewUrl: "http://test.ex.prv/view", - HostEditUrl: "http://test.ex.prv/edit", + HostViewURL: "http://test.ex.prv/view", + HostEditURL: "http://test.ex.prv/edit", SupportsExtendedLockLength: true, SupportsGetLock: true, SupportsLocks: true, SupportsUpdate: true, UserCanWrite: true, - UserId: "6f7061717565496440696e6d656d6f7279", // hex of opaqueId@inmemory + UserID: "6f7061717565496440696e6d656d6f7279", // hex of opaqueId@inmemory UserFriendlyName: "Pet Shaft", } @@ -843,26 +843,26 @@ var _ = Describe("FileConnector", func() { cfg.WopiApp.Provider = "Collabora" expectedFileInfo := &fileinfo.Collabora{ - OwnerId: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp + OwnerID: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp Size: int64(998877), BaseFileName: "test.txt", UserCanNotWriteRelative: true, DisableExport: true, DisableCopy: true, DisablePrint: true, - UserId: "guest-zzz000", + UserID: "guest-zzz000", UserFriendlyName: "guest zzz000", EnableOwnerTermination: true, } newFileInfo, err := fc.CheckFileInfo(ctx) - // UserId and UserFriendlyName have random Ids generated which are impossible to guess + // UserID and UserFriendlyName have random Ids generated which are impossible to guess // Check both separately - Expect(newFileInfo.(*fileinfo.Collabora).UserId).To(HavePrefix(hex.EncodeToString([]byte("guest-")))) + Expect(newFileInfo.(*fileinfo.Collabora).UserID).To(HavePrefix(hex.EncodeToString([]byte("guest-")))) Expect(newFileInfo.(*fileinfo.Collabora).UserFriendlyName).To(HavePrefix("Guest ")) - // overwrite UserId and UserFriendlyName here for easier matching - newFileInfo.(*fileinfo.Collabora).UserId = "guest-zzz000" + // overwrite UserID and UserFriendlyName here for easier matching + newFileInfo.(*fileinfo.Collabora).UserID = "guest-zzz000" newFileInfo.(*fileinfo.Collabora).UserFriendlyName = "guest zzz000" Expect(err).To(Succeed()) @@ -896,14 +896,14 @@ var _ = Describe("FileConnector", func() { cfg.WopiApp.Provider = "Collabora" expectedFileInfo := &fileinfo.Collabora{ - OwnerId: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp + OwnerID: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp Size: int64(998877), BaseFileName: "test.txt", UserCanNotWriteRelative: true, DisableExport: true, DisableCopy: true, DisablePrint: true, - UserId: hex.EncodeToString([]byte("opaqueId@inmemory")), + UserID: hex.EncodeToString([]byte("opaqueId@inmemory")), UserFriendlyName: "Pet Shaft", EnableOwnerTermination: true, WatermarkText: "Pet Shaft shaft@example.com", diff --git a/services/collaboration/pkg/connector/fileinfo/collabora.go b/services/collaboration/pkg/connector/fileinfo/collabora.go index c53ca305f..01c23b4a4 100644 --- a/services/collaboration/pkg/connector/fileinfo/collabora.go +++ b/services/collaboration/pkg/connector/fileinfo/collabora.go @@ -14,7 +14,7 @@ type Collabora struct { // Copied from MS WOPI DisablePrint bool `json:"DisablePrint"` // Copied from MS WOPI - OwnerId string `json:"OwnerId,omitempty"` + OwnerID string `json:"OwnerId,omitempty"` // A string for the domain the host page sends/receives PostMessages from, we only listen to messages from this domain. PostMessageOrigin string `json:"PostMessageOrigin,omitempty"` // copied from MS WOPI @@ -26,7 +26,7 @@ type Collabora struct { // copied from MS WOPI UserCanNotWriteRelative bool `json:"UserCanNotWriteRelative"` // copied from MS WOPI - UserId string `json:"UserId,omitempty"` + UserID string `json:"UserId,omitempty"` // copied from MS WOPI UserFriendlyName string `json:"UserFriendlyName,omitempty"` @@ -66,17 +66,18 @@ type Collabora struct { WatermarkText string `json:"WatermarkText,omitempty"` } +// SetProperties will set the file properties for the Collabora implementation. func (cinfo *Collabora) SetProperties(props map[string]interface{}) { setters := map[string]func(value interface{}){ "BaseFileName": assignStringTo(&cinfo.BaseFileName), "DisablePrint": assignBoolTo(&cinfo.DisablePrint), - "OwnerId": assignStringTo(&cinfo.OwnerId), + "OwnerID": assignStringTo(&cinfo.OwnerID), "PostMessageOrigin": assignStringTo(&cinfo.PostMessageOrigin), "Size": assignInt64To(&cinfo.Size), "TemplateSource": assignStringTo(&cinfo.TemplateSource), "UserCanWrite": assignBoolTo(&cinfo.UserCanWrite), "UserCanNotWriteRelative": assignBoolTo(&cinfo.UserCanNotWriteRelative), - "UserId": assignStringTo(&cinfo.UserId), + "UserID": assignStringTo(&cinfo.UserID), "UserFriendlyName": assignStringTo(&cinfo.UserFriendlyName), "EnableInsertRemoteImage": assignBoolTo(&cinfo.EnableInsertRemoteImage), @@ -103,6 +104,7 @@ func (cinfo *Collabora) SetProperties(props map[string]interface{}) { } } +// GetTarget will always return "Collabora" func (cinfo *Collabora) GetTarget() string { return "Collabora" } diff --git a/services/collaboration/pkg/connector/fileinfo/microsoft.go b/services/collaboration/pkg/connector/fileinfo/microsoft.go index f65b2576c..204e803fb 100644 --- a/services/collaboration/pkg/connector/fileinfo/microsoft.go +++ b/services/collaboration/pkg/connector/fileinfo/microsoft.go @@ -12,11 +12,11 @@ type Microsoft struct { // The string name of the file, including extension, without a path. Used for display in user interface (UI), and determining the extension of the file. BaseFileName string `json:"BaseFileName,omitempty"` //A string that uniquely identifies the owner of the file. In most cases, the user who uploaded or created the file should be considered the owner. - OwnerId string `json:"OwnerId,omitempty"` + OwnerID string `json:"OwnerId,omitempty"` // The size of the file in bytes, expressed as a long, a 64-bit signed integer. Size int64 `json:"Size"` // A string value uniquely identifying the user currently accessing the file. - UserId string `json:"UserId,omitempty"` + UserID string `json:"UserId,omitempty"` // The current version of the file based on the server’s file version schema, as a string. This value must change when the file changes, and version values must never repeat for a given file. Version string `json:"Version,omitempty"` @@ -25,7 +25,7 @@ type Microsoft struct { // // An array of strings containing the Share URL types supported by the host. - SupportedShareUrlTypes []string `json:"SupportedShareUrlTypes,omitempty"` + SupportedShareURLTypes []string `json:"SupportedShareUrlTypes,omitempty"` // A Boolean value that indicates that the host supports the following WOPI operations: ExecuteCellStorageRequest, ExecuteCellStorageRelativeRequest SupportsCobalt bool `json:"SupportsCobalt"` // A Boolean value that indicates that the host supports the following WOPI operations: CheckContainerInfo, CreateChildContainer, CreateChildFile, DeleteContainer, DeleteFile, EnumerateAncestors (containers), EnumerateAncestors (files), EnumerateChildren (containers), GetEcosystem (containers), RenameContainer @@ -90,25 +90,25 @@ type Microsoft struct { // // A URI to a web page that the WOPI client should navigate to when the application closes, or in the event of an unrecoverable error. - CloseUrl string `json:"CloseUrl,omitempty"` + CloseURL string `json:"CloseUrl,omitempty"` // A user-accessible URI to the file intended to allow the user to download a copy of the file. - DownloadUrl string `json:"DownloadUrl,omitempty"` + DownloadURL string `json:"DownloadUrl,omitempty"` // A URI to a location that allows the user to create an embeddable URI to the file. - FileEmbedCommandUrl string `json:"FileEmbedCommandUrl,omitempty"` + FileEmbedCommandURL string `json:"FileEmbedCommandUrl,omitempty"` // A URI to a location that allows the user to share the file. - FileSharingUrl string `json:"FileSharingUrl,omitempty"` + FileSharingURL string `json:"FileSharingUrl,omitempty"` // A URI to the file location that the WOPI client uses to get the file. If this is provided, the WOPI client may use this URI to get the file instead of a GetFile request. A host might set this property if it is easier or provides better performance to serve files from a different domain than the one handling standard WOPI requests. WOPI clients must not add or remove parameters from the URL; no other parameters, including the access token, should be appended to the FileUrl before it is used. - FileUrl string `json:"FileUrl,omitempty"` + FileURL string `json:"FileUrl,omitempty"` // A URI to a location that allows the user to view the version history for the file. - FileVersionUrl string `json:"FileVersionUrl,omitempty"` + FileVersionURL string `json:"FileVersionUrl,omitempty"` // A URI to a host page that loads the edit WOPI action. - HostEditUrl string `json:"HostEditUrl,omitempty"` + HostEditURL string `json:"HostEditUrl,omitempty"` // A URI to a web page that provides access to a viewing experience for the file that can be embedded in another HTML page. This is typically a URI to a host page that loads the embedview WOPI action. - HostEmbeddedViewUrl string `json:"HostEmbeddedViewUrl,omitempty"` + HostEmbeddedViewURL string `json:"HostEmbeddedViewUrl,omitempty"` // A URI to a host page that loads the view WOPI action. This URL is used by Office Online to navigate between view and edit mode. - HostViewUrl string `json:"HostViewUrl,omitempty"` + HostViewURL string `json:"HostViewUrl,omitempty"` // A URI that will sign the current user out of the host’s authentication system. - SignoutUrl string `json:"SignoutUrl,omitempty"` + SignoutURL string `json:"SignoutUrl,omitempty"` // // Miscellaneous properties @@ -154,24 +154,25 @@ type Microsoft struct { // A string that indicates the brand name of the host. BreadcrumbBrandName string `json:"BreadcrumbBrandName,omitempty"` // A URI to a web page that the WOPI client should navigate to when the user clicks on UI that displays BreadcrumbBrandName. - BreadcrumbBrandUrl string `json:"BreadcrumbBrandUrl,omitempty"` + BreadcrumbBrandURL string `json:"BreadcrumbBrandUrl,omitempty"` // A string that indicates the name of the file. If this is not provided, WOPI clients may use the BaseFileName value. BreadcrumbDocName string `json:"BreadcrumbDocName,omitempty"` // A string that indicates the name of the container that contains the file. BreadcrumbFolderName string `json:"BreadcrumbFolderName,omitempty"` // A URI to a web page that the WOPI client should navigate to when the user clicks on UI that displays BreadcrumbFolderName. - BreadcrumbFolderUrl string `json:"BreadcrumbFolderUrl,omitempty"` + BreadcrumbFolderURL string `json:"BreadcrumbFolderUrl,omitempty"` } +// SetProperties will set the file properties for the Microsoft implementation. func (minfo *Microsoft) SetProperties(props map[string]interface{}) { setters := map[string]func(value interface{}){ "BaseFileName": assignStringTo(&minfo.BaseFileName), - "OwnerId": assignStringTo(&minfo.OwnerId), + "OwnerID": assignStringTo(&minfo.OwnerID), "Size": assignInt64To(&minfo.Size), - "UserId": assignStringTo(&minfo.UserId), + "UserID": assignStringTo(&minfo.UserID), "Version": assignStringTo(&minfo.Version), - "SupportedShareUrlTypes": assignStringListTo(&minfo.SupportedShareUrlTypes), + "SupportedShareURLTypes": assignStringListTo(&minfo.SupportedShareURLTypes), "SupportsCobalt": assignBoolTo(&minfo.SupportsCobalt), "SupportsContainers": assignBoolTo(&minfo.SupportsContainers), "SupportsDeleteFile": assignBoolTo(&minfo.SupportsDeleteFile), @@ -199,16 +200,16 @@ func (minfo *Microsoft) SetProperties(props map[string]interface{}) { "UserCanRename": assignBoolTo(&minfo.UserCanRename), "UserCanWrite": assignBoolTo(&minfo.UserCanWrite), - "CloseUrl": assignStringTo(&minfo.CloseUrl), - "DownloadUrl": assignStringTo(&minfo.DownloadUrl), - "FileEmbedCommandUrl": assignStringTo(&minfo.FileEmbedCommandUrl), - "FileSharingUrl": assignStringTo(&minfo.FileSharingUrl), - "FileUrl": assignStringTo(&minfo.FileUrl), - "FileVersionUrl": assignStringTo(&minfo.FileVersionUrl), - "HostEditUrl": assignStringTo(&minfo.HostEditUrl), - "HostEmbeddedViewUrl": assignStringTo(&minfo.HostEmbeddedViewUrl), - "HostViewUrl": assignStringTo(&minfo.HostViewUrl), - "SignoutUrl": assignStringTo(&minfo.SignoutUrl), + "CloseURL": assignStringTo(&minfo.CloseURL), + "DownloadURL": assignStringTo(&minfo.DownloadURL), + "FileEmbedCommandURL": assignStringTo(&minfo.FileEmbedCommandURL), + "FileSharingURL": assignStringTo(&minfo.FileSharingURL), + "FileURL": assignStringTo(&minfo.FileURL), + "FileVersionURL": assignStringTo(&minfo.FileVersionURL), + "HostEditURL": assignStringTo(&minfo.HostEditURL), + "HostEmbeddedViewURL": assignStringTo(&minfo.HostEmbeddedViewURL), + "HostViewURL": assignStringTo(&minfo.HostViewURL), + "SignoutURL": assignStringTo(&minfo.SignoutURL), "AllowAdditionalMicrosoftServices": assignBoolTo(&minfo.AllowAdditionalMicrosoftServices), "AllowErrorReportPrompt": assignBoolTo(&minfo.AllowErrorReportPrompt), @@ -227,10 +228,10 @@ func (minfo *Microsoft) SetProperties(props map[string]interface{}) { "TemporarilyNotWritable": assignBoolTo(&minfo.TemporarilyNotWritable), "BreadcrumbBrandName": assignStringTo(&minfo.BreadcrumbBrandName), - "BreadcrumbBrandUrl": assignStringTo(&minfo.BreadcrumbBrandUrl), + "BreadcrumbBrandURL": assignStringTo(&minfo.BreadcrumbBrandURL), "BreadcrumbDocName": assignStringTo(&minfo.BreadcrumbDocName), "BreadcrumbFolderName": assignStringTo(&minfo.BreadcrumbFolderName), - "BreadcrumbFolderUrl": assignStringTo(&minfo.BreadcrumbFolderUrl), + "BreadcrumbFolderURL": assignStringTo(&minfo.BreadcrumbFolderURL), } for key, value := range props { @@ -241,6 +242,7 @@ func (minfo *Microsoft) SetProperties(props map[string]interface{}) { } } +// GetTarget will always return "Microsoft" func (minfo *Microsoft) GetTarget() string { return "Microsoft" } diff --git a/services/collaboration/pkg/connector/fileinfo/onlyoffice.go b/services/collaboration/pkg/connector/fileinfo/onlyoffice.go index f10eaeb34..d2315e669 100644 --- a/services/collaboration/pkg/connector/fileinfo/onlyoffice.go +++ b/services/collaboration/pkg/connector/fileinfo/onlyoffice.go @@ -21,13 +21,13 @@ type OnlyOffice struct { // copied from MS WOPI BreadcrumbBrandName string `json:"BreadcrumbBrandName,omitempty"` // copied from MS WOPI - BreadcrumbBrandUrl string `json:"BreadcrumbBrandUrl,omitempty"` + BreadcrumbBrandURL string `json:"BreadcrumbBrandUrl,omitempty"` // copied from MS WOPI BreadcrumbDocName string `json:"BreadcrumbDocName,omitempty"` // copied from MS WOPI BreadcrumbFolderName string `json:"BreadcrumbFolderName,omitempty"` // copied from MS WOPI - BreadcrumbFolderUrl string `json:"BreadcrumbFolderUrl,omitempty"` + BreadcrumbFolderURL string `json:"BreadcrumbFolderUrl,omitempty"` // // PostMessage properties @@ -52,13 +52,13 @@ type OnlyOffice struct { // // copied from MS WOPI - CloseUrl string `json:"CloseUrl,omitempty"` + CloseURL string `json:"CloseUrl,omitempty"` // copied from MS WOPI - FileSharingUrl string `json:"FileSharingUrl,omitempty"` + FileSharingURL string `json:"FileSharingUrl,omitempty"` // copied from MS WOPI - FileVersionUrl string `json:"FileVersionUrl,omitempty"` + FileVersionURL string `json:"FileVersionUrl,omitempty"` // copied from MS WOPI - HostEditUrl string `json:"HostEditUrl,omitempty"` + HostEditURL string `json:"HostEditUrl,omitempty"` // // Miscellaneous properties @@ -87,7 +87,7 @@ type OnlyOffice struct { // copied from MS WOPI UserFriendlyName string `json:"UserFriendlyName,omitempty"` // copied from MS WOPI - UserId string `json:"UserId,omitempty"` + UserID string `json:"UserId,omitempty"` // // User permissions properties @@ -127,16 +127,17 @@ type OnlyOffice struct { HidePrintOption bool `json:"HidePrintOption,omitempty"` } +// SetProperties will set the file properties for the OnlyOffice implementation. func (oinfo *OnlyOffice) SetProperties(props map[string]interface{}) { setters := map[string]func(value interface{}){ "BaseFileName": assignStringTo(&oinfo.BaseFileName), "Version": assignStringTo(&oinfo.Version), "BreadcrumbBrandName": assignStringTo(&oinfo.BreadcrumbBrandName), - "BreadcrumbBrandUrl": assignStringTo(&oinfo.BreadcrumbBrandUrl), + "BreadcrumbBrandURL": assignStringTo(&oinfo.BreadcrumbBrandURL), "BreadcrumbDocName": assignStringTo(&oinfo.BreadcrumbDocName), "BreadcrumbFolderName": assignStringTo(&oinfo.BreadcrumbFolderName), - "BreadcrumbFolderUrl": assignStringTo(&oinfo.BreadcrumbFolderUrl), + "BreadcrumbFolderURL": assignStringTo(&oinfo.BreadcrumbFolderURL), "ClosePostMessage": assignBoolTo(&oinfo.ClosePostMessage), "EditModePostMessage": assignBoolTo(&oinfo.EditModePostMessage), @@ -145,10 +146,10 @@ func (oinfo *OnlyOffice) SetProperties(props map[string]interface{}) { "FileVersionPostMessage": assignBoolTo(&oinfo.FileVersionPostMessage), "PostMessageOrigin": assignStringTo(&oinfo.PostMessageOrigin), - "CloseUrl": assignStringTo(&oinfo.CloseUrl), - "FileSharingUrl": assignStringTo(&oinfo.FileSharingUrl), - "FileVersionUrl": assignStringTo(&oinfo.FileVersionUrl), - "HostEditUrl": assignStringTo(&oinfo.HostEditUrl), + "CloseURL": assignStringTo(&oinfo.CloseURL), + "FileSharingURL": assignStringTo(&oinfo.FileSharingURL), + "FileVersionURL": assignStringTo(&oinfo.FileVersionURL), + "HostEditURL": assignStringTo(&oinfo.HostEditURL), "CopyPasteRestrictions": assignStringTo(&oinfo.CopyPasteRestrictions), "DisablePrint": assignBoolTo(&oinfo.DisablePrint), @@ -158,7 +159,7 @@ func (oinfo *OnlyOffice) SetProperties(props map[string]interface{}) { "IsAnonymousUser": assignBoolTo(&oinfo.IsAnonymousUser), "UserFriendlyName": assignStringTo(&oinfo.UserFriendlyName), - "UserId": assignStringTo(&oinfo.UserId), + "UserID": assignStringTo(&oinfo.UserID), "ReadOnly": assignBoolTo(&oinfo.ReadOnly), "UserCanNotWriteRelative": assignBoolTo(&oinfo.UserCanNotWriteRelative), @@ -183,6 +184,7 @@ func (oinfo *OnlyOffice) SetProperties(props map[string]interface{}) { } } +// GetTarget will always return "OnlyOffice" func (oinfo *OnlyOffice) GetTarget() string { return "OnlyOffice" } From 7360cd115ead5d3419f17ca72f55fa14f445c5de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Wed, 5 Jun 2024 11:23:41 +0200 Subject: [PATCH 04/10] fix: use correct name during init and use app name as provider --- ocis/pkg/init/init.go | 2 +- services/collaboration/pkg/config/app.go | 2 +- services/collaboration/pkg/connector/fileconnector.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ocis/pkg/init/init.go b/ocis/pkg/init/init.go index b3c1f0b63..74a9695b1 100644 --- a/ocis/pkg/init/init.go +++ b/ocis/pkg/init/init.go @@ -162,7 +162,7 @@ type WopiApp struct { } type Collaboration struct { - WopiApp WopiApp `yaml:"wopiapp"` + WopiApp WopiApp `yaml:"wopi"` } type Nats struct { diff --git a/services/collaboration/pkg/config/app.go b/services/collaboration/pkg/config/app.go index 36eecc507..f54d058f6 100644 --- a/services/collaboration/pkg/config/app.go +++ b/services/collaboration/pkg/config/app.go @@ -2,7 +2,7 @@ package config // App defines the available app configuration. type App struct { - Name string `yaml:"name" env:"COLLABORATION_APP_NAME" desc:"The name of the app" introductionVersion:"6.0.0"` + Name string `yaml:"name" env:"COLLABORATION_APP_NAME" desc:"The name of the app, either Collabora, OnlyOffice or Microsoft365" introductionVersion:"6.0.0"` Description string `yaml:"description" env:"COLLABORATION_APP_DESCRIPTION" desc:"App description" introductionVersion:"6.0.0"` Icon string `yaml:"icon" env:"COLLABORATION_APP_ICON" desc:"Icon for the app" introductionVersion:"6.0.0"` LockName string `yaml:"lockname" env:"COLLABORATION_APP_LOCKNAME" desc:"Name for the app lock" introductionVersion:"6.0.0"` diff --git a/services/collaboration/pkg/connector/fileconnector.go b/services/collaboration/pkg/connector/fileconnector.go index b08718bc4..bd77eef5e 100644 --- a/services/collaboration/pkg/connector/fileconnector.go +++ b/services/collaboration/pkg/connector/fileconnector.go @@ -501,7 +501,7 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (fileinfo.FileInfo, e } var info fileinfo.FileInfo - switch strings.ToLower(f.cfg.WopiApp.Provider) { + switch strings.ToLower(f.cfg.App.Name) { case "collabora": info = &fileinfo.Collabora{} case "onlyoffice": From d1753172952e489b42e1dfc8612f17ab24fae1b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Wed, 5 Jun 2024 11:48:12 +0200 Subject: [PATCH 05/10] fix: add comment and fix unit tests --- services/collaboration/pkg/connector/fileconnector.go | 3 +++ services/collaboration/pkg/connector/fileconnector_test.go | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/services/collaboration/pkg/connector/fileconnector.go b/services/collaboration/pkg/connector/fileconnector.go index bd77eef5e..8b98851f2 100644 --- a/services/collaboration/pkg/connector/fileconnector.go +++ b/services/collaboration/pkg/connector/fileconnector.go @@ -500,6 +500,9 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (fileinfo.FileInfo, e return nil, NewConnectorError(500, statRes.GetStatus().GetCode().String()+" "+statRes.GetStatus().GetMessage()) } + // If a not known app name is used, consider "Microsoft" as default. + // This will help with the CI because we're using a "FakeOffice" app + // for the wopi validator, which requires a Microsoft fileinfo var info fileinfo.FileInfo switch strings.ToLower(f.cfg.App.Name) { case "collabora": diff --git a/services/collaboration/pkg/connector/fileconnector_test.go b/services/collaboration/pkg/connector/fileconnector_test.go index 538da4972..077715140 100644 --- a/services/collaboration/pkg/connector/fileconnector_test.go +++ b/services/collaboration/pkg/connector/fileconnector_test.go @@ -840,7 +840,7 @@ var _ = Describe("FileConnector", func() { }, nil) // change wopi app provider - cfg.WopiApp.Provider = "Collabora" + cfg.App.Name = "Collabora" expectedFileInfo := &fileinfo.Collabora{ OwnerID: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp @@ -893,7 +893,7 @@ var _ = Describe("FileConnector", func() { }, nil) // change wopi app provider - cfg.WopiApp.Provider = "Collabora" + cfg.App.Name = "Collabora" expectedFileInfo := &fileinfo.Collabora{ OwnerID: "61616262636340637573746f6d496470", // hex of aabbcc@customIdp From 1a7f7131333cac604dbc984ce3ff112d99b959a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Wed, 5 Jun 2024 17:25:27 +0200 Subject: [PATCH 06/10] fix: use (undocumented) collabora properties, such as "supportLocks" SupportLocks property is required for collabora to use locks. The collaboration service requires locks in order to saves files, so without such support collabora wouldn't be able to save files. --- .../pkg/connector/fileinfo/collabora.go | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/services/collaboration/pkg/connector/fileinfo/collabora.go b/services/collaboration/pkg/connector/fileinfo/collabora.go index 01c23b4a4..d45858605 100644 --- a/services/collaboration/pkg/connector/fileinfo/collabora.go +++ b/services/collaboration/pkg/connector/fileinfo/collabora.go @@ -64,6 +64,20 @@ type Collabora struct { // If set to a non-empty string, is used for rendering a watermark-like text on each tile of the document. WatermarkText string `json:"WatermarkText,omitempty"` + + // + // Undocumented (from source code) + // + + EnableShare bool `json:"EnableShare,omitempty"` + // If set to "true", user list on the status bar will be hidden + // If set to "mobile" | "tablet" | "desktop", will be hidden on a specified device + // (may be joint, delimited by commas eg. "mobile,tablet") + HideUserList string `json:"HideUserList,omitempty"` + SupportsLocks bool `json:"SupportsLocks"` + SupportsRename bool `json:"SupportsRename"` + UserCanRename bool `json:"UserCanRename"` + BreadcrumbDocName string `json:"BreadcrumbDocName,omitempty"` } // SetProperties will set the file properties for the Collabora implementation. @@ -94,6 +108,13 @@ func (cinfo *Collabora) SetProperties(props map[string]interface{}) { //UserExtraInfo -> requires definition, currently not used //UserPrivateInfo -> requires definition, currently not used "WatermarkText": assignStringTo(&cinfo.WatermarkText), + + "EnableShare": assignBoolTo(&cinfo.EnableShare), + "HideUserList": assignStringTo(&cinfo.HideUserList), + "SupportsLocks": assignBoolTo(&cinfo.SupportsLocks), + "SupportsRename": assignBoolTo(&cinfo.SupportsRename), + "UserCanRename": assignBoolTo(&cinfo.UserCanRename), + "BreadcrumbDocName": assignStringTo(&cinfo.BreadcrumbDocName), } for key, value := range props { From 668eb5c34ba6c57e072478cb02719dc8d366afcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Wed, 5 Jun 2024 17:28:29 +0200 Subject: [PATCH 07/10] fix: append the app name to the service name for parallel deployment This will allow multiple collaboration services to target 2, 3 or more different WOPI apps. It's expected that each different collaboration service is deployed in a different container or host --- services/collaboration/pkg/command/version.go | 6 +++--- services/collaboration/pkg/connector/fileconnector.go | 8 ++++---- services/collaboration/pkg/helpers/registration.go | 4 ++-- services/collaboration/pkg/server/debug/server.go | 2 +- services/collaboration/pkg/server/http/server.go | 6 +++--- services/collaboration/pkg/service/grpc/v0/service.go | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/services/collaboration/pkg/command/version.go b/services/collaboration/pkg/command/version.go index 57aa0f6ec..ce31ba5c2 100644 --- a/services/collaboration/pkg/command/version.go +++ b/services/collaboration/pkg/command/version.go @@ -24,14 +24,14 @@ func Version(cfg *config.Config) *cli.Command { fmt.Println("") reg := registry.GetRegistry() - services, err := reg.GetService(cfg.HTTP.Namespace + "." + cfg.Service.Name) + services, err := reg.GetService(cfg.HTTP.Namespace + "." + cfg.Service.Name + "." + cfg.App.Name) if err != nil { - fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name, err)) + fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name+"."+cfg.App.Name, err)) return err } if len(services) == 0 { - fmt.Println("No running " + cfg.Service.Name + " service found.") + fmt.Println("No running " + cfg.Service.Name + "." + cfg.App.Name + " service found.") return nil } diff --git a/services/collaboration/pkg/connector/fileconnector.go b/services/collaboration/pkg/connector/fileconnector.go index 8b98851f2..21ab33acd 100644 --- a/services/collaboration/pkg/connector/fileconnector.go +++ b/services/collaboration/pkg/connector/fileconnector.go @@ -161,7 +161,7 @@ func (f *FileConnector) Lock(ctx context.Context, lockID, oldLockID string) (str Ref: &wopiContext.FileReference, Lock: &providerv1beta1.Lock{ LockId: lockID, - AppName: f.cfg.App.LockName, + AppName: f.cfg.App.LockName + "." + f.cfg.App.Name, Type: providerv1beta1.LockType_LOCK_TYPE_WRITE, Expiration: &typesv1beta1.Timestamp{ Seconds: uint64(time.Now().Add(lockDuration).Unix()), @@ -182,7 +182,7 @@ func (f *FileConnector) Lock(ctx context.Context, lockID, oldLockID string) (str Ref: &wopiContext.FileReference, Lock: &providerv1beta1.Lock{ LockId: lockID, - AppName: f.cfg.App.LockName, + AppName: f.cfg.App.LockName + "." + f.cfg.App.Name, Type: providerv1beta1.LockType_LOCK_TYPE_WRITE, Expiration: &typesv1beta1.Timestamp{ Seconds: uint64(time.Now().Add(lockDuration).Unix()), @@ -295,7 +295,7 @@ func (f *FileConnector) RefreshLock(ctx context.Context, lockID string) (string, Ref: &wopiContext.FileReference, Lock: &providerv1beta1.Lock{ LockId: lockID, - AppName: f.cfg.App.LockName, + AppName: f.cfg.App.LockName + "." + f.cfg.App.Name, Type: providerv1beta1.LockType_LOCK_TYPE_WRITE, Expiration: &typesv1beta1.Timestamp{ Seconds: uint64(time.Now().Add(lockDuration).Unix()), @@ -403,7 +403,7 @@ func (f *FileConnector) UnLock(ctx context.Context, lockID string) (string, erro Ref: &wopiContext.FileReference, Lock: &providerv1beta1.Lock{ LockId: lockID, - AppName: f.cfg.App.LockName, + AppName: f.cfg.App.LockName + "." + f.cfg.App.Name, }, } diff --git a/services/collaboration/pkg/helpers/registration.go b/services/collaboration/pkg/helpers/registration.go index a3b83f4d4..c4967dac7 100644 --- a/services/collaboration/pkg/helpers/registration.go +++ b/services/collaboration/pkg/helpers/registration.go @@ -19,7 +19,7 @@ import ( // There are no explicit requirements for the context, and it will be passed // without changes to the underlying RegisterService method. func RegisterOcisService(ctx context.Context, cfg *config.Config, logger log.Logger) error { - svc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, uuid.Must(uuid.NewV4()).String(), cfg.GRPC.Addr, version.GetString()) + svc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name+"."+cfg.App.Name, uuid.Must(uuid.NewV4()).String(), cfg.GRPC.Addr, version.GetString()) return registry.RegisterService(ctx, svc, logger) } @@ -62,7 +62,7 @@ func RegisterAppProvider( Name: cfg.App.Name, Description: cfg.App.Description, Icon: cfg.App.Icon, - Address: cfg.GRPC.Namespace + "." + cfg.Service.Name, + Address: cfg.GRPC.Namespace + "." + cfg.Service.Name + "." + cfg.App.Name, MimeTypes: mimeTypes, }, } diff --git a/services/collaboration/pkg/server/debug/server.go b/services/collaboration/pkg/server/debug/server.go index abcbe9e8a..89de71370 100644 --- a/services/collaboration/pkg/server/debug/server.go +++ b/services/collaboration/pkg/server/debug/server.go @@ -15,7 +15,7 @@ func Server(opts ...Option) (*http.Server, error) { return debug.NewService( debug.Logger(options.Logger), - debug.Name(options.Config.Service.Name), + debug.Name(options.Config.Service.Name+"."+options.Config.App.Name), debug.Version(version.GetString()), debug.Address(options.Config.Debug.Addr), debug.Token(options.Config.Debug.Token), diff --git a/services/collaboration/pkg/server/http/server.go b/services/collaboration/pkg/server/http/server.go index d1f3b7394..ca494549a 100644 --- a/services/collaboration/pkg/server/http/server.go +++ b/services/collaboration/pkg/server/http/server.go @@ -25,7 +25,7 @@ func Server(opts ...Option) (http.Service, error) { http.TLSConfig(options.Config.HTTP.TLS), http.Logger(options.Logger), http.Namespace(options.Config.HTTP.Namespace), - http.Name(options.Config.Service.Name), + http.Name(options.Config.Service.Name+"."+options.Config.App.Name), http.Version(version.GetString()), http.Address(options.Config.HTTP.Addr), http.Context(options.Context), @@ -41,7 +41,7 @@ func Server(opts ...Option) (http.Service, error) { middlewares := []func(stdhttp.Handler) stdhttp.Handler{ chimiddleware.RequestID, middleware.Version( - options.Config.Service.Name, + options.Config.Service.Name+"."+options.Config.App.Name, version.GetString(), ), middleware.Logger( @@ -69,7 +69,7 @@ func Server(opts ...Option) (http.Service, error) { mux.Use( otelchi.Middleware( - options.Config.Service.Name, + options.Config.Service.Name+"."+options.Config.App.Name, otelchi.WithChiRoutes(mux), otelchi.WithTracerProvider(options.TracerProvider), otelchi.WithPropagators(tracing.GetPropagator()), diff --git a/services/collaboration/pkg/service/grpc/v0/service.go b/services/collaboration/pkg/service/grpc/v0/service.go index 67ae47eb0..994a21149 100644 --- a/services/collaboration/pkg/service/grpc/v0/service.go +++ b/services/collaboration/pkg/service/grpc/v0/service.go @@ -38,7 +38,7 @@ func NewHandler(opts ...Option) (*Service, func(), error) { } return &Service{ - id: options.Config.GRPC.Namespace + "." + options.Config.Service.Name, + id: options.Config.GRPC.Namespace + "." + options.Config.Service.Name + "." + options.Config.App.Name, appURLs: options.AppURLs, logger: options.Logger, config: options.Config, From b4e09e34ae27555d26a53b8548dc566acb70deba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Wed, 5 Jun 2024 18:16:13 +0200 Subject: [PATCH 08/10] fix: adjust unit tests --- services/collaboration/pkg/connector/fileconnector_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/collaboration/pkg/connector/fileconnector_test.go b/services/collaboration/pkg/connector/fileconnector_test.go index 077715140..7669e8a57 100644 --- a/services/collaboration/pkg/connector/fileconnector_test.go +++ b/services/collaboration/pkg/connector/fileconnector_test.go @@ -853,6 +853,8 @@ var _ = Describe("FileConnector", func() { UserID: "guest-zzz000", UserFriendlyName: "guest zzz000", EnableOwnerTermination: true, + SupportsLocks: true, + BreadcrumbDocName: "test.txt", } newFileInfo, err := fc.CheckFileInfo(ctx) @@ -907,6 +909,8 @@ var _ = Describe("FileConnector", func() { UserFriendlyName: "Pet Shaft", EnableOwnerTermination: true, WatermarkText: "Pet Shaft shaft@example.com", + SupportsLocks: true, + BreadcrumbDocName: "test.txt", } newFileInfo, err := fc.CheckFileInfo(ctx) From cfc39fac24ecbbe787f93282ab6da80db93ef5d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Fri, 21 Jun 2024 10:47:35 +0200 Subject: [PATCH 09/10] fix: simplify property assignment --- .../pkg/connector/fileinfo/collabora.go | 93 ++++---- .../pkg/connector/fileinfo/fileinfo.go | 77 ------- .../pkg/connector/fileinfo/microsoft.go | 198 +++++++++++------- .../pkg/connector/fileinfo/onlyoffice.go | 131 +++++++----- 4 files changed, 265 insertions(+), 234 deletions(-) diff --git a/services/collaboration/pkg/connector/fileinfo/collabora.go b/services/collaboration/pkg/connector/fileinfo/collabora.go index d45858605..fa200dcbe 100644 --- a/services/collaboration/pkg/connector/fileinfo/collabora.go +++ b/services/collaboration/pkg/connector/fileinfo/collabora.go @@ -82,45 +82,68 @@ type Collabora struct { // SetProperties will set the file properties for the Collabora implementation. func (cinfo *Collabora) SetProperties(props map[string]interface{}) { - setters := map[string]func(value interface{}){ - "BaseFileName": assignStringTo(&cinfo.BaseFileName), - "DisablePrint": assignBoolTo(&cinfo.DisablePrint), - "OwnerID": assignStringTo(&cinfo.OwnerID), - "PostMessageOrigin": assignStringTo(&cinfo.PostMessageOrigin), - "Size": assignInt64To(&cinfo.Size), - "TemplateSource": assignStringTo(&cinfo.TemplateSource), - "UserCanWrite": assignBoolTo(&cinfo.UserCanWrite), - "UserCanNotWriteRelative": assignBoolTo(&cinfo.UserCanNotWriteRelative), - "UserID": assignStringTo(&cinfo.UserID), - "UserFriendlyName": assignStringTo(&cinfo.UserFriendlyName), + for key, value := range props { + switch key { + case "BaseFileName": + cinfo.BaseFileName = value.(string) + case "DisablePrint": + cinfo.DisablePrint = value.(bool) + case "OwnerID": + cinfo.OwnerID = value.(string) + case "PostMessageOrigin": + cinfo.PostMessageOrigin = value.(string) + case "Size": + cinfo.Size = value.(int64) + case "TemplateSource": + cinfo.TemplateSource = value.(string) + case "UserCanWrite": + cinfo.UserCanWrite = value.(bool) + case "UserCanNotWriteRelative": + cinfo.UserCanNotWriteRelative = value.(bool) + case "UserID": + cinfo.UserID = value.(string) + case "UserFriendlyName": + cinfo.UserFriendlyName = value.(string) - "EnableInsertRemoteImage": assignBoolTo(&cinfo.EnableInsertRemoteImage), - "DisableInsertLocalImage": assignBoolTo(&cinfo.DisableInsertLocalImage), - "HidePrintOption": assignBoolTo(&cinfo.HidePrintOption), - "HideSaveOption": assignBoolTo(&cinfo.HideSaveOption), - "HideExportOption": assignBoolTo(&cinfo.HideExportOption), - "DisableExport": assignBoolTo(&cinfo.DisableExport), - "DisableCopy": assignBoolTo(&cinfo.DisableCopy), - "DisableInactiveMessages": assignBoolTo(&cinfo.DisableInactiveMessages), - "DownloadAsPostMessage": assignBoolTo(&cinfo.DownloadAsPostMessage), - "SaveAsPostmessage": assignBoolTo(&cinfo.SaveAsPostmessage), - "EnableOwnerTermination": assignBoolTo(&cinfo.EnableOwnerTermination), + case "EnableInsertRemoteImage": + cinfo.EnableInsertRemoteImage = value.(bool) + case "DisableInsertLocalImage": + cinfo.DisableInsertLocalImage = value.(bool) + case "HidePrintOption": + cinfo.HidePrintOption = value.(bool) + case "HideSaveOption": + cinfo.HideSaveOption = value.(bool) + case "HideExportOption": + cinfo.HideExportOption = value.(bool) + case "DisableExport": + cinfo.DisableExport = value.(bool) + case "DisableCopy": + cinfo.DisableCopy = value.(bool) + case "DisableInactiveMessages": + cinfo.DisableInactiveMessages = value.(bool) + case "DownloadAsPostMessage": + cinfo.DownloadAsPostMessage = value.(bool) + case "SaveAsPostmessage": + cinfo.SaveAsPostmessage = value.(bool) + case "EnableOwnerTermination": + cinfo.EnableOwnerTermination = value.(bool) //UserExtraInfo -> requires definition, currently not used //UserPrivateInfo -> requires definition, currently not used - "WatermarkText": assignStringTo(&cinfo.WatermarkText), + case "WatermarkText": + cinfo.WatermarkText = value.(string) - "EnableShare": assignBoolTo(&cinfo.EnableShare), - "HideUserList": assignStringTo(&cinfo.HideUserList), - "SupportsLocks": assignBoolTo(&cinfo.SupportsLocks), - "SupportsRename": assignBoolTo(&cinfo.SupportsRename), - "UserCanRename": assignBoolTo(&cinfo.UserCanRename), - "BreadcrumbDocName": assignStringTo(&cinfo.BreadcrumbDocName), - } - - for key, value := range props { - setterFn := setters[key] - if setterFn != nil { - setterFn(value) + case "EnableShare": + cinfo.EnableShare = value.(bool) + case "HideUserList": + cinfo.HideUserList = value.(string) + case "SupportsLocks": + cinfo.SupportsLocks = value.(bool) + case "SupportsRename": + cinfo.SupportsRename = value.(bool) + case "UserCanRename": + cinfo.UserCanRename = value.(bool) + case "BreadcrumbDocName": + cinfo.BreadcrumbDocName = value.(string) } } } diff --git a/services/collaboration/pkg/connector/fileinfo/fileinfo.go b/services/collaboration/pkg/connector/fileinfo/fileinfo.go index 63d6c485a..35349b938 100644 --- a/services/collaboration/pkg/connector/fileinfo/fileinfo.go +++ b/services/collaboration/pkg/connector/fileinfo/fileinfo.go @@ -24,80 +24,3 @@ type FileInfo interface { // Note that the returned value must be unique among all the implementations GetTarget() string } - -// assignStringTo will return a function whose parameter will be assigned -// to the provided key. The function will panic if the assignment isn't -// possible. -// -// fn := AssignStringTo(&target) -// fn(value) -// -// Is roughly equivalent to -// -// target = value -// -// The reason for this method is to help the `SetProperties` method in order -// to provide a setter function for each property. -// Expected code for the `SetProperties` should be similar to -// -// setters := map[string]func(value interface{}) { -// "Owner": AssignStringTo(&info.Owner), -// "DisplayName": AssignStringTo(&info.DisplayName), -// ..... -// } -// for key, value := range props { -// fn := setters[key] -// fn(value) -// } -// -// Further `assign*To` functions will be provided to be able to assign -// different data types -func assignStringTo(targetKey *string) func(value interface{}) { - return func(value interface{}) { - *targetKey = value.(string) - } -} - -// assignStringListTo will return a function whose parameter will be assigned -// to the provided key. The function will panic if the assignment isn't -// possible. -// -// See assignStringTo for more information -func assignStringListTo(targetKey *[]string) func(value interface{}) { - return func(value interface{}) { - *targetKey = value.([]string) - } -} - -// assignInt64To will return a function whose parameter will be assigned -// to the provided key. The function will panic if the assignment isn't -// possible. -// -// See assignStringTo for more information -func assignInt64To(targetKey *int64) func(value interface{}) { - return func(value interface{}) { - *targetKey = value.(int64) - } -} - -// assignIntTo will return a function whose parameter will be assigned -// to the provided key. The function will panic if the assignment isn't -// possible. -// -// See assignStringTo for more information -func assignIntTo(targetKey *int) func(value interface{}) { - return func(value interface{}) { - *targetKey = value.(int) - } -} - -// assignBoolTo will return a function whose parameter will be assigned -// to the provided key. The function will panic if the assignment isn't -// possible. -// -// See assignStringTo for more information -func assignBoolTo(targetKey *bool) func(value interface{}) { - return func(value interface{}) { - *targetKey = value.(bool) - } -} diff --git a/services/collaboration/pkg/connector/fileinfo/microsoft.go b/services/collaboration/pkg/connector/fileinfo/microsoft.go index 204e803fb..72cbcc3bc 100644 --- a/services/collaboration/pkg/connector/fileinfo/microsoft.go +++ b/services/collaboration/pkg/connector/fileinfo/microsoft.go @@ -165,79 +165,133 @@ type Microsoft struct { // SetProperties will set the file properties for the Microsoft implementation. func (minfo *Microsoft) SetProperties(props map[string]interface{}) { - setters := map[string]func(value interface{}){ - "BaseFileName": assignStringTo(&minfo.BaseFileName), - "OwnerID": assignStringTo(&minfo.OwnerID), - "Size": assignInt64To(&minfo.Size), - "UserID": assignStringTo(&minfo.UserID), - "Version": assignStringTo(&minfo.Version), - - "SupportedShareURLTypes": assignStringListTo(&minfo.SupportedShareURLTypes), - "SupportsCobalt": assignBoolTo(&minfo.SupportsCobalt), - "SupportsContainers": assignBoolTo(&minfo.SupportsContainers), - "SupportsDeleteFile": assignBoolTo(&minfo.SupportsDeleteFile), - "SupportsEcosystem": assignBoolTo(&minfo.SupportsEcosystem), - "SupportsExtendedLockLength": assignBoolTo(&minfo.SupportsExtendedLockLength), - "SupportsFolders": assignBoolTo(&minfo.SupportsFolders), - //SupportsGetFileWopiSrc bool `json:"SupportsGetFileWopiSrc"` // wopivalidator is complaining and the property isn't used for now -> commented - "SupportsGetLock": assignBoolTo(&minfo.SupportsGetLock), - "SupportsLocks": assignBoolTo(&minfo.SupportsLocks), - "SupportsRename": assignBoolTo(&minfo.SupportsRename), - "SupportsUpdate": assignBoolTo(&minfo.SupportsUpdate), - "SupportsUserInfo": assignBoolTo(&minfo.SupportsUserInfo), - - "IsAnonymousUser": assignBoolTo(&minfo.IsAnonymousUser), - "IsEduUser": assignBoolTo(&minfo.IsEduUser), - "LicenseCheckForEditIsEnabled": assignBoolTo(&minfo.LicenseCheckForEditIsEnabled), - "UserFriendlyName": assignStringTo(&minfo.UserFriendlyName), - "UserInfo": assignStringTo(&minfo.UserInfo), - - "ReadOnly": assignBoolTo(&minfo.ReadOnly), - "RestrictedWebViewOnly": assignBoolTo(&minfo.RestrictedWebViewOnly), - "UserCanAttend": assignBoolTo(&minfo.UserCanAttend), - "UserCanNotWriteRelative": assignBoolTo(&minfo.UserCanNotWriteRelative), - "UserCanPresent": assignBoolTo(&minfo.UserCanPresent), - "UserCanRename": assignBoolTo(&minfo.UserCanRename), - "UserCanWrite": assignBoolTo(&minfo.UserCanWrite), - - "CloseURL": assignStringTo(&minfo.CloseURL), - "DownloadURL": assignStringTo(&minfo.DownloadURL), - "FileEmbedCommandURL": assignStringTo(&minfo.FileEmbedCommandURL), - "FileSharingURL": assignStringTo(&minfo.FileSharingURL), - "FileURL": assignStringTo(&minfo.FileURL), - "FileVersionURL": assignStringTo(&minfo.FileVersionURL), - "HostEditURL": assignStringTo(&minfo.HostEditURL), - "HostEmbeddedViewURL": assignStringTo(&minfo.HostEmbeddedViewURL), - "HostViewURL": assignStringTo(&minfo.HostViewURL), - "SignoutURL": assignStringTo(&minfo.SignoutURL), - - "AllowAdditionalMicrosoftServices": assignBoolTo(&minfo.AllowAdditionalMicrosoftServices), - "AllowErrorReportPrompt": assignBoolTo(&minfo.AllowErrorReportPrompt), - "AllowExternalMarketplace": assignBoolTo(&minfo.AllowExternalMarketplace), - "ClientThrottlingProtection": assignStringTo(&minfo.ClientThrottlingProtection), - "CloseButtonClosesWindow": assignBoolTo(&minfo.CloseButtonClosesWindow), - "CopyPasteRestrictions": assignStringTo(&minfo.CopyPasteRestrictions), - "DisablePrint": assignBoolTo(&minfo.DisablePrint), - "DisableTranslation": assignBoolTo(&minfo.DisableTranslation), - "FileExtension": assignStringTo(&minfo.FileExtension), - "FileNameMaxLength": assignIntTo(&minfo.FileNameMaxLength), - "LastModifiedTime": assignStringTo(&minfo.LastModifiedTime), - "RequestedCallThrottling": assignStringTo(&minfo.RequestedCallThrottling), - "SHA256": assignStringTo(&minfo.SHA256), - "SharingStatus": assignStringTo(&minfo.SharingStatus), - "TemporarilyNotWritable": assignBoolTo(&minfo.TemporarilyNotWritable), - - "BreadcrumbBrandName": assignStringTo(&minfo.BreadcrumbBrandName), - "BreadcrumbBrandURL": assignStringTo(&minfo.BreadcrumbBrandURL), - "BreadcrumbDocName": assignStringTo(&minfo.BreadcrumbDocName), - "BreadcrumbFolderName": assignStringTo(&minfo.BreadcrumbFolderName), - "BreadcrumbFolderURL": assignStringTo(&minfo.BreadcrumbFolderURL), - } - for key, value := range props { - setterFn := setters[key] - if setterFn != nil { - setterFn(value) + switch key { + case "BaseFileName": + minfo.BaseFileName = value.(string) + case "OwnerID": + minfo.OwnerID = value.(string) + case "Size": + minfo.Size = value.(int64) + case "UserID": + minfo.UserID = value.(string) + case "Version": + minfo.Version = value.(string) + + case "SupportedShareURLTypes": + minfo.SupportedShareURLTypes = value.([]string) + case "SupportsCobalt": + minfo.SupportsCobalt = value.(bool) + case "SupportsContainers": + minfo.SupportsContainers = value.(bool) + case "SupportsDeleteFile": + minfo.SupportsDeleteFile = value.(bool) + case "SupportsEcosystem": + minfo.SupportsEcosystem = value.(bool) + case "SupportsExtendedLockLength": + minfo.SupportsExtendedLockLength = value.(bool) + case "SupportsFolders": + minfo.SupportsFolders = value.(bool) + //SupportsGetFileWopiSrc bool `json:"SupportsGetFileWopiSrc"` // wopivalidator is complaining and the property isn't used for now -> commented + case "SupportsGetLock": + minfo.SupportsGetLock = value.(bool) + case "SupportsLocks": + minfo.SupportsLocks = value.(bool) + case "SupportsRename": + minfo.SupportsRename = value.(bool) + case "SupportsUpdate": + minfo.SupportsUpdate = value.(bool) + case "SupportsUserInfo": + minfo.SupportsUserInfo = value.(bool) + + case "IsAnonymousUser": + minfo.IsAnonymousUser = value.(bool) + case "IsEduUser": + minfo.IsEduUser = value.(bool) + case "LicenseCheckForEditIsEnabled": + minfo.LicenseCheckForEditIsEnabled = value.(bool) + case "UserFriendlyName": + minfo.UserFriendlyName = value.(string) + case "UserInfo": + minfo.UserInfo = value.(string) + + case "ReadOnly": + minfo.ReadOnly = value.(bool) + case "RestrictedWebViewOnly": + minfo.RestrictedWebViewOnly = value.(bool) + case "UserCanAttend": + minfo.UserCanAttend = value.(bool) + case "UserCanNotWriteRelative": + minfo.UserCanNotWriteRelative = value.(bool) + case "UserCanPresent": + minfo.UserCanPresent = value.(bool) + case "UserCanRename": + minfo.UserCanRename = value.(bool) + case "UserCanWrite": + minfo.UserCanWrite = value.(bool) + + case "CloseURL": + minfo.CloseURL = value.(string) + case "DownloadURL": + minfo.DownloadURL = value.(string) + case "FileEmbedCommandURL": + minfo.FileEmbedCommandURL = value.(string) + case "FileSharingURL": + minfo.FileSharingURL = value.(string) + case "FileURL": + minfo.FileURL = value.(string) + case "FileVersionURL": + minfo.FileVersionURL = value.(string) + case "HostEditURL": + minfo.HostEditURL = value.(string) + case "HostEmbeddedViewURL": + minfo.HostEmbeddedViewURL = value.(string) + case "HostViewURL": + minfo.HostViewURL = value.(string) + case "SignoutURL": + minfo.SignoutURL = value.(string) + + case "AllowAdditionalMicrosoftServices": + minfo.AllowAdditionalMicrosoftServices = value.(bool) + case "AllowErrorReportPrompt": + minfo.AllowErrorReportPrompt = value.(bool) + case "AllowExternalMarketplace": + minfo.AllowExternalMarketplace = value.(bool) + case "ClientThrottlingProtection": + minfo.ClientThrottlingProtection = value.(string) + case "CloseButtonClosesWindow": + minfo.CloseButtonClosesWindow = value.(bool) + case "CopyPasteRestrictions": + minfo.CopyPasteRestrictions = value.(string) + case "DisablePrint": + minfo.DisablePrint = value.(bool) + case "DisableTranslation": + minfo.DisableTranslation = value.(bool) + case "FileExtension": + minfo.FileExtension = value.(string) + case "FileNameMaxLength": + minfo.FileNameMaxLength = value.(int) + case "LastModifiedTime": + minfo.LastModifiedTime = value.(string) + case "RequestedCallThrottling": + minfo.RequestedCallThrottling = value.(string) + case "SHA256": + minfo.SHA256 = value.(string) + case "SharingStatus": + minfo.SharingStatus = value.(string) + case "TemporarilyNotWritable": + minfo.TemporarilyNotWritable = value.(bool) + + case "BreadcrumbBrandName": + minfo.BreadcrumbBrandName = value.(string) + case "BreadcrumbBrandURL": + minfo.BreadcrumbBrandURL = value.(string) + case "BreadcrumbDocName": + minfo.BreadcrumbDocName = value.(string) + case "BreadcrumbFolderName": + minfo.BreadcrumbFolderName = value.(string) + case "BreadcrumbFolderURL": + minfo.BreadcrumbFolderURL = value.(string) } } } diff --git a/services/collaboration/pkg/connector/fileinfo/onlyoffice.go b/services/collaboration/pkg/connector/fileinfo/onlyoffice.go index d2315e669..96237c4da 100644 --- a/services/collaboration/pkg/connector/fileinfo/onlyoffice.go +++ b/services/collaboration/pkg/connector/fileinfo/onlyoffice.go @@ -129,57 +129,88 @@ type OnlyOffice struct { // SetProperties will set the file properties for the OnlyOffice implementation. func (oinfo *OnlyOffice) SetProperties(props map[string]interface{}) { - setters := map[string]func(value interface{}){ - "BaseFileName": assignStringTo(&oinfo.BaseFileName), - "Version": assignStringTo(&oinfo.Version), - - "BreadcrumbBrandName": assignStringTo(&oinfo.BreadcrumbBrandName), - "BreadcrumbBrandURL": assignStringTo(&oinfo.BreadcrumbBrandURL), - "BreadcrumbDocName": assignStringTo(&oinfo.BreadcrumbDocName), - "BreadcrumbFolderName": assignStringTo(&oinfo.BreadcrumbFolderName), - "BreadcrumbFolderURL": assignStringTo(&oinfo.BreadcrumbFolderURL), - - "ClosePostMessage": assignBoolTo(&oinfo.ClosePostMessage), - "EditModePostMessage": assignBoolTo(&oinfo.EditModePostMessage), - "EditNotificationPostMessage": assignBoolTo(&oinfo.EditNotificationPostMessage), - "FileSharingPostMessage": assignBoolTo(&oinfo.FileSharingPostMessage), - "FileVersionPostMessage": assignBoolTo(&oinfo.FileVersionPostMessage), - "PostMessageOrigin": assignStringTo(&oinfo.PostMessageOrigin), - - "CloseURL": assignStringTo(&oinfo.CloseURL), - "FileSharingURL": assignStringTo(&oinfo.FileSharingURL), - "FileVersionURL": assignStringTo(&oinfo.FileVersionURL), - "HostEditURL": assignStringTo(&oinfo.HostEditURL), - - "CopyPasteRestrictions": assignStringTo(&oinfo.CopyPasteRestrictions), - "DisablePrint": assignBoolTo(&oinfo.DisablePrint), - "FileExtension": assignStringTo(&oinfo.FileExtension), - "FileNameMaxLength": assignIntTo(&oinfo.FileNameMaxLength), - "LastModifiedTime": assignStringTo(&oinfo.LastModifiedTime), - - "IsAnonymousUser": assignBoolTo(&oinfo.IsAnonymousUser), - "UserFriendlyName": assignStringTo(&oinfo.UserFriendlyName), - "UserID": assignStringTo(&oinfo.UserID), - - "ReadOnly": assignBoolTo(&oinfo.ReadOnly), - "UserCanNotWriteRelative": assignBoolTo(&oinfo.UserCanNotWriteRelative), - "UserCanRename": assignBoolTo(&oinfo.UserCanRename), - "UserCanReview": assignBoolTo(&oinfo.UserCanReview), - "UserCanWrite": assignBoolTo(&oinfo.UserCanWrite), - - "SupportsLocks": assignBoolTo(&oinfo.SupportsLocks), - "SupportsRename": assignBoolTo(&oinfo.SupportsRename), - "SupportsReviewing": assignBoolTo(&oinfo.SupportsReviewing), - "SupportsUpdate": assignBoolTo(&oinfo.SupportsUpdate), - - "EnableInsertRemoteImage": assignBoolTo(&oinfo.EnableInsertRemoteImage), - "HidePrintOption": assignBoolTo(&oinfo.HidePrintOption), - } - for key, value := range props { - setterFn := setters[key] - if setterFn != nil { - setterFn(value) + switch key { + case "BaseFileName": + oinfo.BaseFileName = value.(string) + case "Version": + oinfo.Version = value.(string) + + case "BreadcrumbBrandName": + oinfo.BreadcrumbBrandName = value.(string) + case "BreadcrumbBrandURL": + oinfo.BreadcrumbBrandURL = value.(string) + case "BreadcrumbDocName": + oinfo.BreadcrumbDocName = value.(string) + case "BreadcrumbFolderName": + oinfo.BreadcrumbFolderName = value.(string) + case "BreadcrumbFolderURL": + oinfo.BreadcrumbFolderURL = value.(string) + + case "ClosePostMessage": + oinfo.ClosePostMessage = value.(bool) + case "EditModePostMessage": + oinfo.EditModePostMessage = value.(bool) + case "EditNotificationPostMessage": + oinfo.EditNotificationPostMessage = value.(bool) + case "FileSharingPostMessage": + oinfo.FileSharingPostMessage = value.(bool) + case "FileVersionPostMessage": + oinfo.FileVersionPostMessage = value.(bool) + case "PostMessageOrigin": + oinfo.PostMessageOrigin = value.(string) + + case "CloseURL": + oinfo.CloseURL = value.(string) + case "FileSharingURL": + oinfo.FileSharingURL = value.(string) + case "FileVersionURL": + oinfo.FileVersionURL = value.(string) + case "HostEditURL": + oinfo.HostEditURL = value.(string) + + case "CopyPasteRestrictions": + oinfo.CopyPasteRestrictions = value.(string) + case "DisablePrint": + oinfo.DisablePrint = value.(bool) + case "FileExtension": + oinfo.FileExtension = value.(string) + case "FileNameMaxLength": + oinfo.FileNameMaxLength = value.(int) + case "LastModifiedTime": + oinfo.LastModifiedTime = value.(string) + + case "IsAnonymousUser": + oinfo.IsAnonymousUser = value.(bool) + case "UserFriendlyName": + oinfo.UserFriendlyName = value.(string) + case "UserID": + oinfo.UserID = value.(string) + + case "ReadOnly": + oinfo.ReadOnly = value.(bool) + case "UserCanNotWriteRelative": + oinfo.UserCanNotWriteRelative = value.(bool) + case "UserCanRename": + oinfo.UserCanRename = value.(bool) + case "UserCanReview": + oinfo.UserCanReview = value.(bool) + case "UserCanWrite": + oinfo.UserCanWrite = value.(bool) + + case "SupportsLocks": + oinfo.SupportsLocks = value.(bool) + case "SupportsRename": + oinfo.SupportsRename = value.(bool) + case "SupportsReviewing": + oinfo.SupportsReviewing = value.(bool) + case "SupportsUpdate": + oinfo.SupportsUpdate = value.(bool) + + case "EnableInsertRemoteImage": + oinfo.EnableInsertRemoteImage = value.(bool) + case "HidePrintOption": + oinfo.HidePrintOption = value.(bool) } } } From ab636a611f05ee5634bf27f97e5a6d2139085c4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Fri, 21 Jun 2024 12:46:33 +0200 Subject: [PATCH 10/10] fix: use constants for the properties --- .../pkg/connector/fileconnector.go | 42 +++---- .../pkg/connector/fileinfo/collabora.go | 56 ++++----- .../pkg/connector/fileinfo/fileinfo.go | 106 ++++++++++++++++ .../pkg/connector/fileinfo/microsoft.go | 118 +++++++++--------- .../pkg/connector/fileinfo/onlyoffice.go | 72 +++++------ 5 files changed, 250 insertions(+), 144 deletions(-) diff --git a/services/collaboration/pkg/connector/fileconnector.go b/services/collaboration/pkg/connector/fileconnector.go index 21ab33acd..720757f5c 100644 --- a/services/collaboration/pkg/connector/fileconnector.go +++ b/services/collaboration/pkg/connector/fileconnector.go @@ -538,42 +538,42 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (fileinfo.FileInfo, e // fileinfo map infoMap := map[string]interface{}{ - "OwnerID": hexEncodedOwnerId, - "Size": int64(statRes.GetInfo().GetSize()), - "Version": version, - "BaseFileName": path.Base(statRes.GetInfo().GetPath()), - "BreadcrumbDocName": path.Base(statRes.GetInfo().GetPath()), + fileinfo.KeyOwnerID: hexEncodedOwnerId, + fileinfo.KeySize: int64(statRes.GetInfo().GetSize()), + fileinfo.KeyVersion: version, + fileinfo.KeyBaseFileName: path.Base(statRes.GetInfo().GetPath()), + fileinfo.KeyBreadcrumbDocName: path.Base(statRes.GetInfo().GetPath()), // to get the folder we actually need to do a GetPath() request //BreadcrumbFolderName: path.Dir(statRes.Info.Path), - "HostViewURL": wopiContext.ViewAppUrl, - "HostEditURL": wopiContext.EditAppUrl, + fileinfo.KeyHostViewURL: wopiContext.ViewAppUrl, + fileinfo.KeyHostEditURL: wopiContext.EditAppUrl, - "EnableOwnerTermination": true, // only for collabora - "SupportsExtendedLockLength": true, - "SupportsGetLock": true, - "SupportsLocks": true, - "SupportsUpdate": true, + fileinfo.KeyEnableOwnerTermination: true, // only for collabora + fileinfo.KeySupportsExtendedLockLength: true, + fileinfo.KeySupportsGetLock: true, + fileinfo.KeySupportsLocks: true, + fileinfo.KeySupportsUpdate: true, - "UserCanNotWriteRelative": true, - "IsAnonymousUser": isAnonymousUser, - "UserFriendlyName": userFriendlyName, - "UserID": userId, + fileinfo.KeyUserCanNotWriteRelative: true, + fileinfo.KeyIsAnonymousUser: isAnonymousUser, + fileinfo.KeyUserFriendlyName: userFriendlyName, + fileinfo.KeyUserID: userId, } switch wopiContext.ViewMode { case appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE: - infoMap["UserCanWrite"] = true + infoMap[fileinfo.KeyUserCanWrite] = true case appproviderv1beta1.ViewMode_VIEW_MODE_READ_ONLY: // nothing special to do here for now case appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY: - infoMap["DisableExport"] = true // only for collabora - infoMap["DisableCopy"] = true // only for collabora - infoMap["DisablePrint"] = true + infoMap[fileinfo.KeyDisableExport] = true // only for collabora + infoMap[fileinfo.KeyDisableCopy] = true // only for collabora + infoMap[fileinfo.KeyDisablePrint] = true if !isPublicShare { - infoMap["WatermarkText"] = f.watermarkText(wopiContext.User) // only for collabora + infoMap[fileinfo.KeyWatermarkText] = f.watermarkText(wopiContext.User) // only for collabora } } diff --git a/services/collaboration/pkg/connector/fileinfo/collabora.go b/services/collaboration/pkg/connector/fileinfo/collabora.go index fa200dcbe..82b157361 100644 --- a/services/collaboration/pkg/connector/fileinfo/collabora.go +++ b/services/collaboration/pkg/connector/fileinfo/collabora.go @@ -84,65 +84,65 @@ type Collabora struct { func (cinfo *Collabora) SetProperties(props map[string]interface{}) { for key, value := range props { switch key { - case "BaseFileName": + case KeyBaseFileName: cinfo.BaseFileName = value.(string) - case "DisablePrint": + case KeyDisablePrint: cinfo.DisablePrint = value.(bool) - case "OwnerID": + case KeyOwnerID: cinfo.OwnerID = value.(string) - case "PostMessageOrigin": + case KeyPostMessageOrigin: cinfo.PostMessageOrigin = value.(string) - case "Size": + case KeySize: cinfo.Size = value.(int64) - case "TemplateSource": + case KeyTemplateSource: cinfo.TemplateSource = value.(string) - case "UserCanWrite": + case KeyUserCanWrite: cinfo.UserCanWrite = value.(bool) - case "UserCanNotWriteRelative": + case KeyUserCanNotWriteRelative: cinfo.UserCanNotWriteRelative = value.(bool) - case "UserID": + case KeyUserID: cinfo.UserID = value.(string) - case "UserFriendlyName": + case KeyUserFriendlyName: cinfo.UserFriendlyName = value.(string) - case "EnableInsertRemoteImage": + case KeyEnableInsertRemoteImage: cinfo.EnableInsertRemoteImage = value.(bool) - case "DisableInsertLocalImage": + case KeyDisableInsertLocalImage: cinfo.DisableInsertLocalImage = value.(bool) - case "HidePrintOption": + case KeyHidePrintOption: cinfo.HidePrintOption = value.(bool) - case "HideSaveOption": + case KeyHideSaveOption: cinfo.HideSaveOption = value.(bool) - case "HideExportOption": + case KeyHideExportOption: cinfo.HideExportOption = value.(bool) - case "DisableExport": + case KeyDisableExport: cinfo.DisableExport = value.(bool) - case "DisableCopy": + case KeyDisableCopy: cinfo.DisableCopy = value.(bool) - case "DisableInactiveMessages": + case KeyDisableInactiveMessages: cinfo.DisableInactiveMessages = value.(bool) - case "DownloadAsPostMessage": + case KeyDownloadAsPostMessage: cinfo.DownloadAsPostMessage = value.(bool) - case "SaveAsPostmessage": + case KeySaveAsPostmessage: cinfo.SaveAsPostmessage = value.(bool) - case "EnableOwnerTermination": + case KeyEnableOwnerTermination: cinfo.EnableOwnerTermination = value.(bool) //UserExtraInfo -> requires definition, currently not used //UserPrivateInfo -> requires definition, currently not used - case "WatermarkText": + case KeyWatermarkText: cinfo.WatermarkText = value.(string) - case "EnableShare": + case KeyEnableShare: cinfo.EnableShare = value.(bool) - case "HideUserList": + case KeyHideUserList: cinfo.HideUserList = value.(string) - case "SupportsLocks": + case KeySupportsLocks: cinfo.SupportsLocks = value.(bool) - case "SupportsRename": + case KeySupportsRename: cinfo.SupportsRename = value.(bool) - case "UserCanRename": + case KeyUserCanRename: cinfo.UserCanRename = value.(bool) - case "BreadcrumbDocName": + case KeyBreadcrumbDocName: cinfo.BreadcrumbDocName = value.(string) } } diff --git a/services/collaboration/pkg/connector/fileinfo/fileinfo.go b/services/collaboration/pkg/connector/fileinfo/fileinfo.go index 35349b938..72f8ae74d 100644 --- a/services/collaboration/pkg/connector/fileinfo/fileinfo.go +++ b/services/collaboration/pkg/connector/fileinfo/fileinfo.go @@ -24,3 +24,109 @@ type FileInfo interface { // Note that the returned value must be unique among all the implementations GetTarget() string } + +// constants that can be used to refer the fileinfo properties for the +// SetProperties method of the FileInfo interface +const ( + KeyBaseFileName = "BaseFileName" + KeyOwnerID = "OwnerId" + KeySize = "Size" + KeyUserID = "UserID" + KeyVersion = "Version" + + KeySupportedShareURLTypes = "SupportedShareURLTypes" + KeySupportsCobalt = "SupportsCobalt" + KeySupportsContainers = "SupportsContainers" + KeySupportsDeleteFile = "SupportsDeleteFile" + KeySupportsEcosystem = "SupportsEcosystem" + KeySupportsExtendedLockLength = "SupportsExtendedLockLength" + KeySupportsFolders = "SupportsFolders" + //KeySupportsGetFileWopiSrc = "SupportsGetFileWopiSrc" // wopivalidator is complaining and the property isn't used for now -> commented + KeySupportsGetLock = "SupportsGetLock" + KeySupportsLocks = "SupportsLocks" + KeySupportsRename = "SupportsRename" + KeySupportsUpdate = "SupportsUpdate" + KeySupportsUserInfo = "SupportsUserInfo" + + KeyIsAnonymousUser = "IsAnonymousUser" + KeyIsEduUser = "IsEduUser" + KeyLicenseCheckForEditIsEnabled = "LicenseCheckForEditIsEnabled" + KeyUserFriendlyName = "UserFriendlyName" + KeyUserInfo = "UserInfo" + + KeyReadOnly = "ReadOnly" + KeyRestrictedWebViewOnly = "RestrictedWebViewOnly" + KeyUserCanAttend = "UserCanAttend" + KeyUserCanNotWriteRelative = "UserCanNotWriteRelative" + KeyUserCanPresent = "UserCanPresent" + KeyUserCanRename = "UserCanRename" + KeyUserCanWrite = "UserCanWrite" + + KeyCloseURL = "CloseURL" + KeyDownloadURL = "DownloadURL" + KeyFileEmbedCommandURL = "FileEmbedCommandURL" + KeyFileSharingURL = "FileSharingURL" + KeyFileURL = "FileURL" + KeyFileVersionURL = "FileVersionURL" + KeyHostEditURL = "HostEditURL" + KeyHostEmbeddedViewURL = "HostEmbeddedViewURL" + KeyHostViewURL = "HostViewURL" + KeySignoutURL = "SignoutURL" + + KeyAllowAdditionalMicrosoftServices = "AllowAdditionalMicrosoftServices" + KeyAllowErrorReportPrompt = "AllowErrorReportPrompt" + KeyAllowExternalMarketplace = "AllowExternalMarketplace" + KeyClientThrottlingProtection = "ClientThrottlingProtection" + KeyCloseButtonClosesWindow = "CloseButtonClosesWindow" + KeyCopyPasteRestrictions = "CopyPasteRestrictions" + KeyDisablePrint = "DisablePrint" + KeyDisableTranslation = "DisableTranslation" + KeyFileExtension = "FileExtension" + KeyFileNameMaxLength = "FileNameMaxLength" + KeyLastModifiedTime = "LastModifiedTime" + KeyRequestedCallThrottling = "RequestedCallThrottling" + KeySHA256 = "SHA256" + KeySharingStatus = "SharingStatus" + KeyTemporarilyNotWritable = "TemporarilyNotWritable" + //KeyUniqueContentId = "UniqueContentId" // From microsoft docs: Not supported in CSPP -> commented + + KeyBreadcrumbBrandName = "BreadcrumbBrandName" + KeyBreadcrumbBrandURL = "BreadcrumbBrandURL" + KeyBreadcrumbDocName = "BreadcrumbDocName" + KeyBreadcrumbFolderName = "BreadcrumbFolderName" + KeyBreadcrumbFolderURL = "BreadcrumbFolderUrl" + + // Collabora (non-dupped) properties below + + KeyPostMessageOrigin = "PostMessageOrigin" + KeyTemplateSource = "TemplateSource" + + KeyEnableInsertRemoteImage = "EnableInsertRemoteImage" + KeyDisableInsertLocalImage = "DisableInsertLocalImage" + KeyHidePrintOption = "HidePrintOption" + KeyHideSaveOption = "HideSaveOption" + KeyHideExportOption = "HideExportOption" + KeyDisableExport = "DisableExport" + KeyDisableCopy = "DisableCopy" + KeyDisableInactiveMessages = "DisableInactiveMessages" + KeyDownloadAsPostMessage = "DownloadAsPostMessage" + KeySaveAsPostmessage = "SaveAsPostmessage" + KeyEnableOwnerTermination = "EnableOwnerTermination" + //KeyUserExtraInfo -> requires definition, currently not used + //KeyUserPrivateInfo -> requires definition, currently not used + KeyWatermarkText = "WatermarkText" + + KeyEnableShare = "EnableShare" + KeyHideUserList = "HideUserList" + + // OnlyOffice (non-dupped) properties below + + KeyClosePostMessage = "ClosePostMessage" + KeyEditModePostMessage = "EditModePostMessage" + KeyEditNotificationPostMessage = "EditNotificationPostMessage" + KeyFileSharingPostMessage = "FileSharingPostMessage" + KeyFileVersionPostMessage = "FileVersionPostMessage" + + KeyUserCanReview = "UserCanReview" + KeySupportsReviewing = "SupportsReviewing" +) diff --git a/services/collaboration/pkg/connector/fileinfo/microsoft.go b/services/collaboration/pkg/connector/fileinfo/microsoft.go index 72cbcc3bc..66be0c0f0 100644 --- a/services/collaboration/pkg/connector/fileinfo/microsoft.go +++ b/services/collaboration/pkg/connector/fileinfo/microsoft.go @@ -167,130 +167,130 @@ type Microsoft struct { func (minfo *Microsoft) SetProperties(props map[string]interface{}) { for key, value := range props { switch key { - case "BaseFileName": + case KeyBaseFileName: minfo.BaseFileName = value.(string) - case "OwnerID": + case KeyOwnerID: minfo.OwnerID = value.(string) - case "Size": + case KeySize: minfo.Size = value.(int64) - case "UserID": + case KeyUserID: minfo.UserID = value.(string) - case "Version": + case KeyVersion: minfo.Version = value.(string) - case "SupportedShareURLTypes": + case KeySupportedShareURLTypes: minfo.SupportedShareURLTypes = value.([]string) - case "SupportsCobalt": + case KeySupportsCobalt: minfo.SupportsCobalt = value.(bool) - case "SupportsContainers": + case KeySupportsContainers: minfo.SupportsContainers = value.(bool) - case "SupportsDeleteFile": + case KeySupportsDeleteFile: minfo.SupportsDeleteFile = value.(bool) - case "SupportsEcosystem": + case KeySupportsEcosystem: minfo.SupportsEcosystem = value.(bool) - case "SupportsExtendedLockLength": + case KeySupportsExtendedLockLength: minfo.SupportsExtendedLockLength = value.(bool) - case "SupportsFolders": + case KeySupportsFolders: minfo.SupportsFolders = value.(bool) //SupportsGetFileWopiSrc bool `json:"SupportsGetFileWopiSrc"` // wopivalidator is complaining and the property isn't used for now -> commented - case "SupportsGetLock": + case KeySupportsGetLock: minfo.SupportsGetLock = value.(bool) - case "SupportsLocks": + case KeySupportsLocks: minfo.SupportsLocks = value.(bool) - case "SupportsRename": + case KeySupportsRename: minfo.SupportsRename = value.(bool) - case "SupportsUpdate": + case KeySupportsUpdate: minfo.SupportsUpdate = value.(bool) - case "SupportsUserInfo": + case KeySupportsUserInfo: minfo.SupportsUserInfo = value.(bool) - case "IsAnonymousUser": + case KeyIsAnonymousUser: minfo.IsAnonymousUser = value.(bool) - case "IsEduUser": + case KeyIsEduUser: minfo.IsEduUser = value.(bool) - case "LicenseCheckForEditIsEnabled": + case KeyLicenseCheckForEditIsEnabled: minfo.LicenseCheckForEditIsEnabled = value.(bool) - case "UserFriendlyName": + case KeyUserFriendlyName: minfo.UserFriendlyName = value.(string) - case "UserInfo": + case KeyUserInfo: minfo.UserInfo = value.(string) - case "ReadOnly": + case KeyReadOnly: minfo.ReadOnly = value.(bool) - case "RestrictedWebViewOnly": + case KeyRestrictedWebViewOnly: minfo.RestrictedWebViewOnly = value.(bool) - case "UserCanAttend": + case KeyUserCanAttend: minfo.UserCanAttend = value.(bool) - case "UserCanNotWriteRelative": + case KeyUserCanNotWriteRelative: minfo.UserCanNotWriteRelative = value.(bool) - case "UserCanPresent": + case KeyUserCanPresent: minfo.UserCanPresent = value.(bool) - case "UserCanRename": + case KeyUserCanRename: minfo.UserCanRename = value.(bool) - case "UserCanWrite": + case KeyUserCanWrite: minfo.UserCanWrite = value.(bool) - case "CloseURL": + case KeyCloseURL: minfo.CloseURL = value.(string) - case "DownloadURL": + case KeyDownloadURL: minfo.DownloadURL = value.(string) - case "FileEmbedCommandURL": + case KeyFileEmbedCommandURL: minfo.FileEmbedCommandURL = value.(string) - case "FileSharingURL": + case KeyFileSharingURL: minfo.FileSharingURL = value.(string) - case "FileURL": + case KeyFileURL: minfo.FileURL = value.(string) - case "FileVersionURL": + case KeyFileVersionURL: minfo.FileVersionURL = value.(string) - case "HostEditURL": + case KeyHostEditURL: minfo.HostEditURL = value.(string) - case "HostEmbeddedViewURL": + case KeyHostEmbeddedViewURL: minfo.HostEmbeddedViewURL = value.(string) - case "HostViewURL": + case KeyHostViewURL: minfo.HostViewURL = value.(string) - case "SignoutURL": + case KeySignoutURL: minfo.SignoutURL = value.(string) - case "AllowAdditionalMicrosoftServices": + case KeyAllowAdditionalMicrosoftServices: minfo.AllowAdditionalMicrosoftServices = value.(bool) - case "AllowErrorReportPrompt": + case KeyAllowErrorReportPrompt: minfo.AllowErrorReportPrompt = value.(bool) - case "AllowExternalMarketplace": + case KeyAllowExternalMarketplace: minfo.AllowExternalMarketplace = value.(bool) - case "ClientThrottlingProtection": + case KeyClientThrottlingProtection: minfo.ClientThrottlingProtection = value.(string) - case "CloseButtonClosesWindow": + case KeyCloseButtonClosesWindow: minfo.CloseButtonClosesWindow = value.(bool) - case "CopyPasteRestrictions": + case KeyCopyPasteRestrictions: minfo.CopyPasteRestrictions = value.(string) - case "DisablePrint": + case KeyDisablePrint: minfo.DisablePrint = value.(bool) - case "DisableTranslation": + case KeyDisableTranslation: minfo.DisableTranslation = value.(bool) - case "FileExtension": + case KeyFileExtension: minfo.FileExtension = value.(string) - case "FileNameMaxLength": + case KeyFileNameMaxLength: minfo.FileNameMaxLength = value.(int) - case "LastModifiedTime": + case KeyLastModifiedTime: minfo.LastModifiedTime = value.(string) - case "RequestedCallThrottling": + case KeyRequestedCallThrottling: minfo.RequestedCallThrottling = value.(string) - case "SHA256": + case KeySHA256: minfo.SHA256 = value.(string) - case "SharingStatus": + case KeySharingStatus: minfo.SharingStatus = value.(string) - case "TemporarilyNotWritable": + case KeyTemporarilyNotWritable: minfo.TemporarilyNotWritable = value.(bool) - case "BreadcrumbBrandName": + case KeyBreadcrumbBrandName: minfo.BreadcrumbBrandName = value.(string) - case "BreadcrumbBrandURL": + case KeyBreadcrumbBrandURL: minfo.BreadcrumbBrandURL = value.(string) - case "BreadcrumbDocName": + case KeyBreadcrumbDocName: minfo.BreadcrumbDocName = value.(string) - case "BreadcrumbFolderName": + case KeyBreadcrumbFolderName: minfo.BreadcrumbFolderName = value.(string) - case "BreadcrumbFolderURL": + case KeyBreadcrumbFolderURL: minfo.BreadcrumbFolderURL = value.(string) } } diff --git a/services/collaboration/pkg/connector/fileinfo/onlyoffice.go b/services/collaboration/pkg/connector/fileinfo/onlyoffice.go index 96237c4da..772670ff8 100644 --- a/services/collaboration/pkg/connector/fileinfo/onlyoffice.go +++ b/services/collaboration/pkg/connector/fileinfo/onlyoffice.go @@ -131,85 +131,85 @@ type OnlyOffice struct { func (oinfo *OnlyOffice) SetProperties(props map[string]interface{}) { for key, value := range props { switch key { - case "BaseFileName": + case KeyBaseFileName: oinfo.BaseFileName = value.(string) - case "Version": + case KeyVersion: oinfo.Version = value.(string) - case "BreadcrumbBrandName": + case KeyBreadcrumbBrandName: oinfo.BreadcrumbBrandName = value.(string) - case "BreadcrumbBrandURL": + case KeyBreadcrumbBrandURL: oinfo.BreadcrumbBrandURL = value.(string) - case "BreadcrumbDocName": + case KeyBreadcrumbDocName: oinfo.BreadcrumbDocName = value.(string) - case "BreadcrumbFolderName": + case KeyBreadcrumbFolderName: oinfo.BreadcrumbFolderName = value.(string) - case "BreadcrumbFolderURL": + case KeyBreadcrumbFolderURL: oinfo.BreadcrumbFolderURL = value.(string) - case "ClosePostMessage": + case KeyClosePostMessage: oinfo.ClosePostMessage = value.(bool) - case "EditModePostMessage": + case KeyEditModePostMessage: oinfo.EditModePostMessage = value.(bool) - case "EditNotificationPostMessage": + case KeyEditNotificationPostMessage: oinfo.EditNotificationPostMessage = value.(bool) - case "FileSharingPostMessage": + case KeyFileSharingPostMessage: oinfo.FileSharingPostMessage = value.(bool) - case "FileVersionPostMessage": + case KeyFileVersionPostMessage: oinfo.FileVersionPostMessage = value.(bool) - case "PostMessageOrigin": + case KeyPostMessageOrigin: oinfo.PostMessageOrigin = value.(string) - case "CloseURL": + case KeyCloseURL: oinfo.CloseURL = value.(string) - case "FileSharingURL": + case KeyFileSharingURL: oinfo.FileSharingURL = value.(string) - case "FileVersionURL": + case KeyFileVersionURL: oinfo.FileVersionURL = value.(string) - case "HostEditURL": + case KeyHostEditURL: oinfo.HostEditURL = value.(string) - case "CopyPasteRestrictions": + case KeyCopyPasteRestrictions: oinfo.CopyPasteRestrictions = value.(string) - case "DisablePrint": + case KeyDisablePrint: oinfo.DisablePrint = value.(bool) - case "FileExtension": + case KeyFileExtension: oinfo.FileExtension = value.(string) - case "FileNameMaxLength": + case KeyFileNameMaxLength: oinfo.FileNameMaxLength = value.(int) - case "LastModifiedTime": + case KeyLastModifiedTime: oinfo.LastModifiedTime = value.(string) - case "IsAnonymousUser": + case KeyIsAnonymousUser: oinfo.IsAnonymousUser = value.(bool) - case "UserFriendlyName": + case KeyUserFriendlyName: oinfo.UserFriendlyName = value.(string) - case "UserID": + case KeyUserID: oinfo.UserID = value.(string) - case "ReadOnly": + case KeyReadOnly: oinfo.ReadOnly = value.(bool) - case "UserCanNotWriteRelative": + case KeyUserCanNotWriteRelative: oinfo.UserCanNotWriteRelative = value.(bool) - case "UserCanRename": + case KeyUserCanRename: oinfo.UserCanRename = value.(bool) - case "UserCanReview": + case KeyUserCanReview: oinfo.UserCanReview = value.(bool) - case "UserCanWrite": + case KeyUserCanWrite: oinfo.UserCanWrite = value.(bool) - case "SupportsLocks": + case KeySupportsLocks: oinfo.SupportsLocks = value.(bool) - case "SupportsRename": + case KeySupportsRename: oinfo.SupportsRename = value.(bool) - case "SupportsReviewing": + case KeySupportsReviewing: oinfo.SupportsReviewing = value.(bool) - case "SupportsUpdate": + case KeySupportsUpdate: oinfo.SupportsUpdate = value.(bool) - case "EnableInsertRemoteImage": + case KeyEnableInsertRemoteImage: oinfo.EnableInsertRemoteImage = value.(bool) - case "HidePrintOption": + case KeyHidePrintOption: oinfo.HidePrintOption = value.(bool) } }