mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-03 02:39:52 -06:00
feat: template feature
Signed-off-by: Michael Barz <mbarz@owncloud.com>
This commit is contained in:
48
changelog/unreleased/template-conversions-for-apps.md
Normal file
48
changelog/unreleased/template-conversions-for-apps.md
Normal file
@@ -0,0 +1,48 @@
|
||||
Enhancement: WebOffice Templates
|
||||
|
||||
We are now able to use templates for WebOffice and use them as a starting point for new documents.
|
||||
|
||||
We are supporting the following mime types:
|
||||
|
||||
## OnlyOffice
|
||||
|
||||
- **MimeType:** `application/vnd.ms-word.template.macroenabled.12`
|
||||
**TargetExtension:** `docx`
|
||||
|
||||
- **MimeType:** `application/vnd.oasis.opendocument.text-template`
|
||||
**TargetExtension:** `docx`
|
||||
|
||||
- **MimeType:** `application/vnd.openxmlformats-officedocument.wordprocessingml.template`
|
||||
**TargetExtension:** `docx`
|
||||
|
||||
- **MimeType:** `application/vnd.oasis.opendocument.spreadsheet-template`
|
||||
**TargetExtension:** `xlsx`
|
||||
|
||||
- **MimeType:** `application/vnd.ms-excel.template.macroenabled.12`
|
||||
**TargetExtension:** `xlsx`
|
||||
|
||||
- **MimeType:** `application/vnd.openxmlformats-officedocument.spreadsheetml.template`
|
||||
**TargetExtension:** `xlsx`
|
||||
|
||||
- **MimeType:** `application/vnd.oasis.opendocument.presentation-template`
|
||||
**TargetExtension:** `pptx`
|
||||
|
||||
- **MimeType:** `application/vnd.ms-powerpoint.template.macroenabled.12`
|
||||
**TargetExtension:** `pptx`
|
||||
|
||||
- **MimeType:** `application/vnd.openxmlformats-officedocument.presentationml.template`
|
||||
**TargetExtension:** `pptx`
|
||||
|
||||
## Collabora
|
||||
|
||||
- **MimeType:** `application/vnd.oasis.opendocument.spreadsheet-template`
|
||||
**TargetExtension:** `ods`
|
||||
|
||||
- **MimeType:** `application/vnd.oasis.opendocument.text-template`
|
||||
**TargetExtension:** `odt`
|
||||
|
||||
- **MimeType:** `application/vnd.oasis.opendocument.presentation-template`
|
||||
**TargetExtension:** `odp`
|
||||
|
||||
https://github.com/owncloud/ocis/pull/10276
|
||||
https://github.com/owncloud/ocis/issues/9785
|
||||
@@ -1188,6 +1188,10 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
collaborationURL, err := url.Parse(f.cfg.Wopi.WopiSrc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
privateLinkURL := &url.URL{}
|
||||
*privateLinkURL = *ocisURL
|
||||
privateLinkURL.Path = path.Join(ocisURL.Path, "f", storagespace.FormatResourceID(statRes.GetInfo().GetId()))
|
||||
@@ -1240,12 +1244,43 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
|
||||
}
|
||||
}
|
||||
|
||||
// if the file content is empty and a template reference is set, add the template source URL
|
||||
if wopiContext.TemplateReference != nil && statRes.GetInfo().GetSize() == 0 {
|
||||
if tu, err := f.createDownloadURL(wopiContext, collaborationURL); err == nil {
|
||||
infoMap[fileinfo.KeyTemplateSource] = tu
|
||||
}
|
||||
}
|
||||
|
||||
info.SetProperties(infoMap)
|
||||
|
||||
logger.Debug().Interface("FileInfo", info).Msg("CheckFileInfo: success")
|
||||
return NewResponseSuccessBody(info), nil
|
||||
}
|
||||
|
||||
// createDownloadURL will create a download URL for the template file.
|
||||
// It uses a new wopi context with the template reference set as the file reference
|
||||
// and a reva access token to download the file.
|
||||
func (f *FileConnector) createDownloadURL(wopiContext middleware.WopiContext, collaborationURL *url.URL) (string, error) {
|
||||
templateContext := wopiContext
|
||||
templateContext.FileReference = wopiContext.TemplateReference
|
||||
templateContext.TemplateReference = nil
|
||||
|
||||
token, _, err := middleware.GenerateWopiToken(templateContext, f.cfg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
downloadURL := *collaborationURL
|
||||
downloadURL.Path = path.Join(
|
||||
collaborationURL.Path,
|
||||
"wopi/templates/",
|
||||
helpers.HashResourceId(templateContext.FileReference.GetResourceId()),
|
||||
)
|
||||
q := downloadURL.Query()
|
||||
q.Add("access_token", token)
|
||||
downloadURL.RawQuery = q.Encode()
|
||||
return downloadURL.String(), nil
|
||||
}
|
||||
|
||||
func createHostUrl(mode string, ocisUrl *url.URL, appName string, info *providerv1beta1.ResourceInfo) string {
|
||||
webUrl := createAppExternalURL(ocisUrl, appName, info)
|
||||
addURLParams(webUrl, map[string]string{"view_mode": mode})
|
||||
|
||||
@@ -51,6 +51,7 @@ var _ = Describe("FileConnector", func() {
|
||||
WopiSrc: "https://ocis.server.prv",
|
||||
Secret: "topsecret",
|
||||
},
|
||||
TokenManager: &config.TokenManager{JWTSecret: "secret"},
|
||||
}
|
||||
ccs = &collabmocks.ContentConnectorService{}
|
||||
|
||||
@@ -1843,5 +1844,83 @@ var _ = Describe("FileConnector", func() {
|
||||
Expect(response.Status).To(Equal(200))
|
||||
Expect(response.Body.(*fileinfo.Collabora)).To(Equal(expectedFileInfo))
|
||||
})
|
||||
It("Stat success with template", func() {
|
||||
wopiCtx.TemplateReference = &providerv1beta1.Reference{
|
||||
ResourceId: &providerv1beta1.ResourceId{
|
||||
StorageId: "storageid",
|
||||
OpaqueId: "opaqueid2",
|
||||
SpaceId: "spaceid",
|
||||
},
|
||||
}
|
||||
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)
|
||||
u := &userv1beta1.User{
|
||||
Id: &userv1beta1.UserId{
|
||||
Idp: "customIdp",
|
||||
OpaqueId: "admin",
|
||||
},
|
||||
DisplayName: "Pet Shaft",
|
||||
}
|
||||
ctx = ctxpkg.ContextSetUser(ctx, u)
|
||||
|
||||
gatewayClient.On("Stat", mock.Anything, mock.Anything).Times(1).Return(&providerv1beta1.StatResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
Info: &providerv1beta1.ResourceInfo{
|
||||
Owner: &userv1beta1.UserId{
|
||||
Idp: "customIdp",
|
||||
OpaqueId: "aabbcc",
|
||||
Type: userv1beta1.UserType_USER_TYPE_PRIMARY,
|
||||
},
|
||||
Size: uint64(0),
|
||||
Mtime: &typesv1beta1.Timestamp{
|
||||
Seconds: uint64(16273849),
|
||||
},
|
||||
Path: "/path/to/test.txt",
|
||||
Id: &providerv1beta1.ResourceId{
|
||||
StorageId: "storageid",
|
||||
OpaqueId: "opaqueid",
|
||||
SpaceId: "spaceid",
|
||||
},
|
||||
},
|
||||
}, nil)
|
||||
|
||||
expectedFileInfo := &fileinfo.OnlyOffice{
|
||||
Version: "v162738490",
|
||||
BaseFileName: "test.txt",
|
||||
BreadcrumbDocName: "test.txt",
|
||||
BreadcrumbFolderName: "/path/to",
|
||||
BreadcrumbFolderURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid",
|
||||
UserCanNotWriteRelative: false,
|
||||
SupportsLocks: true,
|
||||
SupportsUpdate: true,
|
||||
SupportsRename: true,
|
||||
UserCanWrite: true,
|
||||
UserCanRename: true,
|
||||
UserID: "61646d696e40637573746f6d496470", // hex of admin@customIdp
|
||||
UserFriendlyName: "Pet Shaft",
|
||||
FileSharingURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid?details=sharing",
|
||||
FileVersionURL: "https://ocis.example.prv/f/storageid$spaceid%21opaqueid?details=versions",
|
||||
HostEditURL: "https://ocis.example.prv/external-onlyoffice/path/to/test.txt?fileId=storageid%24spaceid%21opaqueid&view_mode=write",
|
||||
PostMessageOrigin: "https://ocis.example.prv",
|
||||
}
|
||||
|
||||
// change wopi app provider
|
||||
cfg.App.Name = "OnlyOffice"
|
||||
|
||||
response, err := fc.CheckFileInfo(ctx)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(response.Status).To(Equal(200))
|
||||
|
||||
returnedFileInfo := response.Body.(*fileinfo.OnlyOffice)
|
||||
templateSource := returnedFileInfo.TemplateSource
|
||||
expectedTemplateSource := "https://ocis.server.prv/wopi/templates/a340d017568d0d579ee061a9ac02109e32fb07082d35c40aa175864303bd9107?access_token="
|
||||
|
||||
// take TemplateSource out of the response for easier comparison
|
||||
returnedFileInfo.TemplateSource = ""
|
||||
Expect(returnedFileInfo).To(Equal(expectedFileInfo))
|
||||
// check if the template source is correct
|
||||
// the url is using a generated access token which always has a new ttl
|
||||
// so we can't compare the whole url
|
||||
Expect(templateSource).To(HavePrefix(expectedTemplateSource))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -77,6 +77,8 @@ type OnlyOffice struct {
|
||||
FileNameMaxLength int `json:"FileNameMaxLength,omitempty"`
|
||||
// copied from MS WOPI
|
||||
LastModifiedTime string `json:"LastModifiedTime,omitempty"`
|
||||
// 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"`
|
||||
|
||||
//
|
||||
// User metadata properties
|
||||
@@ -179,7 +181,8 @@ func (oinfo *OnlyOffice) SetProperties(props map[string]interface{}) {
|
||||
oinfo.FileNameMaxLength = value.(int)
|
||||
case KeyLastModifiedTime:
|
||||
oinfo.LastModifiedTime = value.(string)
|
||||
|
||||
case KeyTemplateSource:
|
||||
oinfo.TemplateSource = value.(string)
|
||||
case KeyIsAnonymousUser:
|
||||
oinfo.IsAnonymousUser = value.(bool)
|
||||
case KeyUserFriendlyName:
|
||||
|
||||
@@ -26,10 +26,11 @@ const (
|
||||
|
||||
// WopiContext wraps all the information we need for WOPI
|
||||
type WopiContext struct {
|
||||
AccessToken string
|
||||
ViewOnlyToken string
|
||||
FileReference *providerv1beta1.Reference
|
||||
ViewMode appproviderv1beta1.ViewMode
|
||||
AccessToken string
|
||||
ViewOnlyToken string
|
||||
FileReference *providerv1beta1.Reference
|
||||
TemplateReference *providerv1beta1.Reference
|
||||
ViewMode appproviderv1beta1.ViewMode
|
||||
}
|
||||
|
||||
// WopiContextAuthMiddleware will prepare an HTTP handler to be used as
|
||||
@@ -120,10 +121,21 @@ func WopiContextAuthMiddleware(cfg *config.Config, next http.Handler) http.Handl
|
||||
|
||||
hashedRef := helpers.HashResourceId(claims.WopiContext.FileReference.GetResourceId())
|
||||
fileID := parseWopiFileID(cfg, r.URL.Path)
|
||||
if fileID != hashedRef {
|
||||
wopiLogger.Error().Msg("file reference in the URL doesn't match the one inside the access token")
|
||||
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||
return
|
||||
if claims.WopiContext.TemplateReference != nil {
|
||||
hashedTemplateRef := helpers.HashResourceId(claims.WopiContext.TemplateReference.GetResourceId())
|
||||
// the fileID could be one of the references within the access token if both are set
|
||||
// because we can use the access token to get the contents of the template file
|
||||
if fileID != hashedTemplateRef && fileID != hashedRef {
|
||||
wopiLogger.Error().Msg("file reference in the URL doesn't match the one inside the access token")
|
||||
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if fileID != hashedRef {
|
||||
wopiLogger.Error().Msg("file reference in the URL doesn't match the one inside the access token")
|
||||
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
|
||||
@@ -165,6 +165,70 @@ var _ = Describe("Wopi Context Middleware", func() {
|
||||
mw.ServeHTTP(resp, req)
|
||||
Expect(resp.Code).To(Equal(http.StatusOK))
|
||||
})
|
||||
It("Should authorize successful with template reference", func() {
|
||||
req := httptest.NewRequest("GET", src.String(), nil).WithContext(ctx)
|
||||
token, err := tknMngr.MintToken(ctx, user, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
wopiContext := middleware.WopiContext{
|
||||
AccessToken: token,
|
||||
ViewMode: appprovider.ViewMode_VIEW_MODE_READ_WRITE,
|
||||
TemplateReference: &providerv1beta1.Reference{
|
||||
ResourceId: rid,
|
||||
Path: ".",
|
||||
},
|
||||
FileReference: &providerv1beta1.Reference{
|
||||
ResourceId: &providerv1beta1.ResourceId{
|
||||
StorageId: "storageID",
|
||||
OpaqueId: "opaqueID2",
|
||||
SpaceId: "spaceID",
|
||||
},
|
||||
},
|
||||
}
|
||||
wopiToken, ttl, err := middleware.GenerateWopiToken(wopiContext, cfg)
|
||||
q := req.URL.Query()
|
||||
q.Add("access_token", wopiToken)
|
||||
q.Add("access_token_ttl", strconv.FormatInt(ttl, 10))
|
||||
req.URL.RawQuery = q.Encode()
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
mw.ServeHTTP(resp, req)
|
||||
Expect(resp.Code).To(Equal(http.StatusOK))
|
||||
})
|
||||
It("Should not authorize when no reference matches", func() {
|
||||
req := httptest.NewRequest("GET", src.String(), nil).WithContext(ctx)
|
||||
token, err := tknMngr.MintToken(ctx, user, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
wopiContext := middleware.WopiContext{
|
||||
AccessToken: token,
|
||||
ViewMode: appprovider.ViewMode_VIEW_MODE_READ_WRITE,
|
||||
TemplateReference: &providerv1beta1.Reference{
|
||||
ResourceId: &providerv1beta1.ResourceId{
|
||||
StorageId: "storageID",
|
||||
OpaqueId: "opaqueID3",
|
||||
SpaceId: "spaceID",
|
||||
},
|
||||
Path: ".",
|
||||
},
|
||||
FileReference: &providerv1beta1.Reference{
|
||||
ResourceId: &providerv1beta1.ResourceId{
|
||||
StorageId: "storageID",
|
||||
OpaqueId: "opaqueID2",
|
||||
SpaceId: "spaceID",
|
||||
},
|
||||
},
|
||||
}
|
||||
wopiToken, ttl, err := middleware.GenerateWopiToken(wopiContext, cfg)
|
||||
q := req.URL.Query()
|
||||
q.Add("access_token", wopiToken)
|
||||
q.Add("access_token_ttl", strconv.FormatInt(ttl, 10))
|
||||
req.URL.RawQuery = q.Encode()
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
mw.ServeHTTP(resp, req)
|
||||
Expect(resp.Code).To(Equal(http.StatusUnauthorized))
|
||||
})
|
||||
It("Should not authorize with proxy when fileID mismatches", func() {
|
||||
cfg.Wopi.ProxySecret = "proxySecret"
|
||||
cfg.Wopi.ProxyURL = "https://proxy"
|
||||
|
||||
@@ -182,5 +182,17 @@ func prepareRoutes(r *chi.Mux, options Options) {
|
||||
})
|
||||
})
|
||||
})
|
||||
r.Route("/templates/{templateID}", func(r chi.Router) {
|
||||
r.Use(
|
||||
func(h stdhttp.Handler) stdhttp.Handler {
|
||||
// authentication and wopi context
|
||||
return colabmiddleware.WopiContextAuthMiddleware(options.Config, h)
|
||||
},
|
||||
colabmiddleware.CollaborationTracingMiddleware,
|
||||
)
|
||||
r.Get("/", func(w stdhttp.ResponseWriter, r *stdhttp.Request) {
|
||||
adapter.GetFile(w, r)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/v2/pkg/storagespace"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"github.com/owncloud/ocis/v2/services/collaboration/pkg/wopisrc"
|
||||
|
||||
@@ -102,7 +103,12 @@ func (s *Service) OpenInApp(
|
||||
appURL, err = s.addQueryToURL(appURL, req)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("OpenInApp: error parsing appUrl")
|
||||
return nil, err
|
||||
return &appproviderv1beta1.OpenInAppResponse{
|
||||
Status: &rpcv1beta1.Status{
|
||||
Code: rpcv1beta1.Code_CODE_INVALID_ARGUMENT,
|
||||
Message: "OpenInApp: error parsing appUrl",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// create the wopiContext and generate the token
|
||||
@@ -113,6 +119,25 @@ func (s *Service) OpenInApp(
|
||||
ViewMode: req.GetViewMode(),
|
||||
}
|
||||
|
||||
if templateID := utils.ReadPlainFromOpaque(req.GetOpaque(), "template"); templateID != "" {
|
||||
// we can ignore the error here, as we are sure that the templateID is not empty
|
||||
templateRes, _ := storagespace.ParseID(templateID)
|
||||
// we need to have at least both opaqueID and spaceID set
|
||||
if templateRes.GetOpaqueId() == "" || templateRes.GetSpaceId() == "" {
|
||||
logger.Error().Err(err).Msg("OpenInApp: error parsing templateID")
|
||||
return &appproviderv1beta1.OpenInAppResponse{
|
||||
Status: &rpcv1beta1.Status{
|
||||
Code: rpcv1beta1.Code_CODE_INVALID_ARGUMENT,
|
||||
Message: "OpenInApp: error parsing templateID",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
wopiContext.TemplateReference = &providerv1beta1.Reference{
|
||||
ResourceId: &templateRes,
|
||||
Path: ".",
|
||||
}
|
||||
}
|
||||
|
||||
accessToken, accessExpiration, err := middleware.GenerateWopiToken(wopiContext, s.config)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("OpenInApp: error generating the token")
|
||||
|
||||
@@ -89,7 +89,8 @@ var _ = Describe("Discovery", func() {
|
||||
".xlsb": "https://test.server.prv/hosting/wopi/cell/view",
|
||||
},
|
||||
"edit": map[string]string{
|
||||
".docx": "https://test.server.prv/hosting/wopi/word/edit",
|
||||
".docx": "https://test.server.prv/hosting/wopi/word/edit",
|
||||
".invalid": "://test.server.prv/hosting/wopi/cell/edit",
|
||||
},
|
||||
}),
|
||||
service.GatewayAPIClient(gatewayClient),
|
||||
@@ -242,5 +243,132 @@ var _ = Describe("Discovery", func() {
|
||||
Expect(resp.GetAppUrl().GetAppUrl()).To(Equal("https://test.server.prv/hosting/wopi/word/edit?UI_LLCC=en-US&WOPISrc=https%3A%2F%2Foffice.proxy.test.prv%2Fwopi%2Ffiles%2FeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1IjoiaHR0cHM6Ly93b3Bpc2VydmVyLnRlc3QucHJ2L3dvcGkvZmlsZXMvIiwiZiI6IjJmNmVjMTg2OTZkZDEwMDgxMDY3NDliZDk0MTA2ZTVjZmFkNWMwOWUxNWRlN2I3NzA4OGQwMzg0M2U3MWI0M2UifQ.yfyLHZ18Z1MFOa6u7AP0LqfIiQ9X5AMkYauEZGhbCNs"))
|
||||
Expect(resp.GetAppUrl().GetFormParameters()["access_token_ttl"]).To(Equal(strconv.FormatInt(nowTime.Add(5*time.Hour).Unix()*1000, 10)))
|
||||
})
|
||||
It("Fail with invalid app url", func() {
|
||||
ctx := context.Background()
|
||||
nowTime := time.Now()
|
||||
|
||||
cfg.Wopi.WopiSrc = "htttps://wopiserver.test.prv"
|
||||
cfg.Wopi.Secret = "my_supa_secret"
|
||||
cfg.App.Name = "Microsoft"
|
||||
|
||||
myself := &userv1beta1.User{
|
||||
Id: &userv1beta1.UserId{
|
||||
Idp: "myIdp",
|
||||
OpaqueId: "opaque001",
|
||||
Type: userv1beta1.UserType_USER_TYPE_PRIMARY,
|
||||
},
|
||||
Username: "username",
|
||||
}
|
||||
|
||||
req := &appproviderv1beta1.OpenInAppRequest{
|
||||
ResourceInfo: &providerv1beta1.ResourceInfo{
|
||||
Id: &providerv1beta1.ResourceId{
|
||||
StorageId: "myStorage",
|
||||
OpaqueId: "storageOpaque001",
|
||||
SpaceId: "SpaceA",
|
||||
},
|
||||
Path: "/path/to/file.invalid",
|
||||
},
|
||||
ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE,
|
||||
AccessToken: MintToken(myself, cfg.Wopi.Secret, nowTime),
|
||||
}
|
||||
req.Opaque = utils.AppendPlainToOpaque(req.Opaque, "lang", "en")
|
||||
|
||||
gatewayClient.On("WhoAmI", mock.Anything, mock.Anything).Times(1).Return(&gatewayv1beta1.WhoAmIResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
User: myself,
|
||||
}, nil)
|
||||
|
||||
resp, err := srv.OpenInApp(ctx, req)
|
||||
Expect(err).To(Succeed())
|
||||
Expect(resp.GetStatus().GetCode()).To(Equal(rpcv1beta1.Code_CODE_INVALID_ARGUMENT))
|
||||
Expect(resp.GetStatus().GetMessage()).To(Equal("OpenInApp: error parsing appUrl"))
|
||||
})
|
||||
It("Fail with invalid template id", func() {
|
||||
ctx := context.Background()
|
||||
nowTime := time.Now()
|
||||
|
||||
cfg.Wopi.WopiSrc = "htttps://wopiserver.test.prv"
|
||||
cfg.Wopi.Secret = "my_supa_secret"
|
||||
cfg.App.Name = "Microsoft"
|
||||
|
||||
myself := &userv1beta1.User{
|
||||
Id: &userv1beta1.UserId{
|
||||
Idp: "myIdp",
|
||||
OpaqueId: "opaque001",
|
||||
Type: userv1beta1.UserType_USER_TYPE_PRIMARY,
|
||||
},
|
||||
Username: "username",
|
||||
}
|
||||
|
||||
req := &appproviderv1beta1.OpenInAppRequest{
|
||||
ResourceInfo: &providerv1beta1.ResourceInfo{
|
||||
Id: &providerv1beta1.ResourceId{
|
||||
StorageId: "myStorage",
|
||||
OpaqueId: "storageOpaque001",
|
||||
SpaceId: "SpaceA",
|
||||
},
|
||||
Path: "/path/to/file.docx",
|
||||
},
|
||||
ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE,
|
||||
AccessToken: MintToken(myself, cfg.Wopi.Secret, nowTime),
|
||||
}
|
||||
req.Opaque = utils.AppendPlainToOpaque(req.Opaque, "lang", "en")
|
||||
req.Opaque = utils.AppendPlainToOpaque(req.Opaque, "template", "&file_id")
|
||||
|
||||
gatewayClient.On("WhoAmI", mock.Anything, mock.Anything).Times(1).Return(&gatewayv1beta1.WhoAmIResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
User: myself,
|
||||
}, nil)
|
||||
|
||||
resp, err := srv.OpenInApp(ctx, req)
|
||||
Expect(err).To(Succeed())
|
||||
Expect(resp.GetStatus().GetCode()).To(Equal(rpcv1beta1.Code_CODE_INVALID_ARGUMENT))
|
||||
Expect(resp.GetStatus().GetMessage()).To(Equal("OpenInApp: error parsing templateID"))
|
||||
})
|
||||
It("Success with valid template id", func() {
|
||||
ctx := context.Background()
|
||||
nowTime := time.Now()
|
||||
|
||||
cfg.Wopi.WopiSrc = "htttps://wopiserver.test.prv"
|
||||
cfg.Wopi.Secret = "my_supa_secret"
|
||||
cfg.App.Name = "OnlyOffice"
|
||||
|
||||
myself := &userv1beta1.User{
|
||||
Id: &userv1beta1.UserId{
|
||||
Idp: "myIdp",
|
||||
OpaqueId: "opaque001",
|
||||
Type: userv1beta1.UserType_USER_TYPE_PRIMARY,
|
||||
},
|
||||
Username: "username",
|
||||
}
|
||||
|
||||
req := &appproviderv1beta1.OpenInAppRequest{
|
||||
ResourceInfo: &providerv1beta1.ResourceInfo{
|
||||
Id: &providerv1beta1.ResourceId{
|
||||
StorageId: "myStorage",
|
||||
OpaqueId: "storageOpaque001",
|
||||
SpaceId: "SpaceA",
|
||||
},
|
||||
Path: "/path/to/file.docx",
|
||||
},
|
||||
ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE,
|
||||
AccessToken: MintToken(myself, cfg.Wopi.Secret, nowTime),
|
||||
}
|
||||
req.Opaque = utils.AppendPlainToOpaque(req.Opaque, "lang", "en")
|
||||
req.Opaque = utils.AppendPlainToOpaque(req.Opaque, "template", "prodiderID$spaceID!opaqueID")
|
||||
|
||||
gatewayClient.On("WhoAmI", mock.Anything, mock.Anything).Times(1).Return(&gatewayv1beta1.WhoAmIResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
User: myself,
|
||||
}, nil)
|
||||
|
||||
resp, err := srv.OpenInApp(ctx, req)
|
||||
Expect(err).To(Succeed())
|
||||
Expect(resp.GetStatus().GetCode()).To(Equal(rpcv1beta1.Code_CODE_OK))
|
||||
Expect(resp.GetAppUrl().GetMethod()).To(Equal("POST"))
|
||||
Expect(resp.GetAppUrl().GetAppUrl()).To(Equal("https://test.server.prv/hosting/wopi/word/edit?WOPISrc=htttps%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&ui=en-US"))
|
||||
Expect(resp.GetAppUrl().GetFormParameters()["access_token_ttl"]).To(Equal(strconv.FormatInt(nowTime.Add(5*time.Hour).Unix()*1000, 10)))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user