diff --git a/app/file.go b/app/file.go index 089f69630c..5ddfd9f412 100644 --- a/app/file.go +++ b/app/file.go @@ -640,6 +640,20 @@ func (a *App) GetFileInfo(fileId string) (*model.FileInfo, *model.AppError) { return result.Data.(*model.FileInfo), nil } +func (a *App) GetFile(fileId string) ([]byte, *model.AppError) { + info, err := a.GetFileInfo(fileId) + if err != nil { + return nil, err + } + + data, err := a.ReadFile(info.Path) + if err != nil { + return nil, err + } + + return data, nil +} + func (a *App) CopyFileInfos(userId string, fileIds []string) ([]string, *model.AppError) { var newFileIds []string diff --git a/app/plugin_api.go b/app/plugin_api.go index 51fd2de89f..68e20f6117 100644 --- a/app/plugin_api.go +++ b/app/plugin_api.go @@ -484,6 +484,10 @@ func (api *PluginAPI) ReadFile(path string) ([]byte, *model.AppError) { return api.app.ReadFile(path) } +func (api *PluginAPI) GetFile(fileId string) ([]byte, *model.AppError) { + return api.app.GetFile(fileId) +} + func (api *PluginAPI) UploadFile(data []byte, channelId string, filename string) (*model.FileInfo, *model.AppError) { return api.app.UploadFile(data, channelId, filename) } diff --git a/app/plugin_api_test.go b/app/plugin_api_test.go index 1b9977f35d..cbdc812e8d 100644 --- a/app/plugin_api_test.go +++ b/app/plugin_api_test.go @@ -15,6 +15,7 @@ import ( "path/filepath" "strings" "testing" + "time" "github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/plugin" @@ -173,6 +174,31 @@ func TestPluginAPIUpdateUserStatus(t *testing.T) { assert.Nil(t, status) } +func TestPluginAPIGetFile(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + api := th.SetupPluginAPI() + + // check a valid file first + uploadTime := time.Date(2007, 2, 4, 1, 2, 3, 4, time.Local) + filename := "testGetFile" + fileData := []byte("Hello World") + info, err := th.App.DoUploadFile(uploadTime, th.BasicTeam.Id, th.BasicChannel.Id, th.BasicUser.Id, filename, fileData) + require.Nil(t, err) + defer func() { + <-th.App.Srv.Store.FileInfo().PermanentDelete(info.Id) + th.App.RemoveFile(info.Path) + }() + + data, err1 := api.GetFile(info.Id) + require.Nil(t, err1) + assert.Equal(t, data, fileData) + + // then checking invalid file + data, err = api.GetFile("../fake/testingApi") + require.NotNil(t, err) + require.Nil(t, data) +} func TestPluginAPISavePluginConfig(t *testing.T) { th := Setup().InitBasic() defer th.TearDown() diff --git a/plugin/api.go b/plugin/api.go index cff931c65d..b5c5a7be04 100644 --- a/plugin/api.go +++ b/plugin/api.go @@ -336,6 +336,11 @@ type API interface { // Minimum server version: 5.3 GetFileInfo(fileId string) (*model.FileInfo, *model.AppError) + // GetFile gets content of a file by it's ID + // + // Minimum Server version: 5.8 + GetFile(fileId string) ([]byte, *model.AppError) + // GetFileLink gets the public link to a file by fileId. // // Minimum server version: 5.6 diff --git a/plugin/client_rpc_generated.go b/plugin/client_rpc_generated.go index 9a5c831454..676214b695 100644 --- a/plugin/client_rpc_generated.go +++ b/plugin/client_rpc_generated.go @@ -2837,6 +2837,35 @@ func (s *apiRPCServer) GetFileInfo(args *Z_GetFileInfoArgs, returns *Z_GetFileIn return nil } +type Z_GetFileArgs struct { + A string +} + +type Z_GetFileReturns struct { + A []byte + B *model.AppError +} + +func (g *apiRPCClient) GetFile(fileId string) ([]byte, *model.AppError) { + _args := &Z_GetFileArgs{fileId} + _returns := &Z_GetFileReturns{} + if err := g.client.Call("Plugin.GetFile", _args, _returns); err != nil { + log.Printf("RPC call to GetFile API failed: %s", err.Error()) + } + return _returns.A, _returns.B +} + +func (s *apiRPCServer) GetFile(args *Z_GetFileArgs, returns *Z_GetFileReturns) error { + if hook, ok := s.impl.(interface { + GetFile(fileId string) ([]byte, *model.AppError) + }); ok { + returns.A, returns.B = hook.GetFile(args.A) + } else { + return encodableError(fmt.Errorf("API GetFile called but not implemented.")) + } + return nil +} + type Z_GetFileLinkArgs struct { A string } diff --git a/plugin/plugintest/api.go b/plugin/plugintest/api.go index 04e284f34a..345404d5bf 100644 --- a/plugin/plugintest/api.go +++ b/plugin/plugintest/api.go @@ -713,6 +713,31 @@ func (_m *API) GetEmojiList(sortBy string, page int, perPage int) ([]*model.Emoj return r0, r1 } +// GetFile provides a mock function with given fields: fileId +func (_m *API) GetFile(fileId string) ([]byte, *model.AppError) { + ret := _m.Called(fileId) + + var r0 []byte + if rf, ok := ret.Get(0).(func(string) []byte); ok { + r0 = rf(fileId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + var r1 *model.AppError + if rf, ok := ret.Get(1).(func(string) *model.AppError); ok { + r1 = rf(fileId) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.AppError) + } + } + + return r0, r1 +} + // GetFileInfo provides a mock function with given fields: fileId func (_m *API) GetFileInfo(fileId string) (*model.FileInfo, *model.AppError) { ret := _m.Called(fileId)