Remove usages of AppError on filesstore service (#15841)

* Remove usages of AppError on filesstore service

* Fixing a golint error

* Fixing shadowed variable

* Adding err.Error() to the NewAppError calls

* Fixing tests

* Adding missed translations

* Fix error handling and updating the translation that affects it

* Fixing two typos
Этот коммит содержится в:
Jesús Espino
2020-12-20 12:53:07 +01:00
коммит произвёл GitHub
родитель 10be00f005
Коммит 7419898449
13 изменённых файлов: 366 добавлений и 289 удалений

Просмотреть файл

@@ -19,7 +19,6 @@ import (
"github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/mlog"
"github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/services/cache" "github.com/mattermost/mattermost-server/v5/services/cache"
"github.com/mattermost/mattermost-server/v5/services/filesstore"
"github.com/mattermost/mattermost-server/v5/services/upgrader" "github.com/mattermost/mattermost-server/v5/services/upgrader"
) )
@@ -117,16 +116,8 @@ func getSystemPing(c *Context, w http.ResponseWriter, r *http.Request) {
filestoreStatusKey := "filestore_status" filestoreStatusKey := "filestore_status"
s[filestoreStatusKey] = model.STATUS_OK s[filestoreStatusKey] = model.STATUS_OK
license := c.App.Srv().License() appErr := c.App.TestFilesStoreConnection()
backend, appErr := filesstore.NewFileBackend(&c.App.Config().FileSettings, license != nil && *license.Features.Compliance) if appErr != nil {
if appErr == nil {
appErr = backend.TestConnection()
if appErr != nil {
s[filestoreStatusKey] = model.STATUS_UNHEALTHY
s[model.STATUS] = model.STATUS_UNHEALTHY
}
} else {
mlog.Debug("Unable to get filestore for ping status.", mlog.Err(appErr))
s[filestoreStatusKey] = model.STATUS_UNHEALTHY s[filestoreStatusKey] = model.STATUS_UNHEALTHY
s[model.STATUS] = model.STATUS_UNHEALTHY s[model.STATUS] = model.STATUS_UNHEALTHY
} }
@@ -393,7 +384,7 @@ func testS3(c *Context, w http.ResponseWriter, r *http.Request) {
return return
} }
err := filesstore.CheckMandatoryS3Fields(&cfg.FileSettings) err := c.App.CheckMandatoryS3Fields(&cfg.FileSettings)
if err != nil { if err != nil {
c.Err = err c.Err = err
return return
@@ -403,11 +394,7 @@ func testS3(c *Context, w http.ResponseWriter, r *http.Request) {
cfg.FileSettings.AmazonS3SecretAccessKey = c.App.Config().FileSettings.AmazonS3SecretAccessKey cfg.FileSettings.AmazonS3SecretAccessKey = c.App.Config().FileSettings.AmazonS3SecretAccessKey
} }
license := c.App.Srv().License() appErr := c.App.TestFilesStoreConnectionWithConfig(&cfg.FileSettings)
backend, appErr := filesstore.NewFileBackend(&cfg.FileSettings, license != nil && *license.Features.Compliance)
if appErr == nil {
appErr = backend.TestConnection()
}
if appErr != nil { if appErr != nil {
c.Err = appErr c.Err = appErr
return return

Просмотреть файл

@@ -478,7 +478,7 @@ func TestS3TestConnection(t *testing.T) {
config.FileSettings.AmazonS3Bucket = model.NewString("Wrong_bucket") config.FileSettings.AmazonS3Bucket = model.NewString("Wrong_bucket")
_, resp = th.SystemAdminClient.TestS3Connection(&config) _, resp = th.SystemAdminClient.TestS3Connection(&config)
CheckInternalErrorStatus(t, resp) CheckInternalErrorStatus(t, resp)
assert.Equal(t, "Unable to create bucket.", resp.Error.Message) assert.Equal(t, "api.file.test_connection.app_error", resp.Error.Id)
*config.FileSettings.AmazonS3Bucket = "shouldcreatenewbucket" *config.FileSettings.AmazonS3Bucket = "shouldcreatenewbucket"
_, resp = th.SystemAdminClient.TestS3Connection(&config) _, resp = th.SystemAdminClient.TestS3Connection(&config)

Просмотреть файл

@@ -393,6 +393,7 @@ type AppIface interface {
ChannelMembersToRemove(teamID *string) ([]*model.ChannelMember, *model.AppError) ChannelMembersToRemove(teamID *string) ([]*model.ChannelMember, *model.AppError)
CheckAndSendUserLimitWarningEmails() *model.AppError CheckAndSendUserLimitWarningEmails() *model.AppError
CheckForClientSideCert(r *http.Request) (string, string, string) CheckForClientSideCert(r *http.Request) (string, string, string)
CheckMandatoryS3Fields(settings *model.FileSettings) *model.AppError
CheckPasswordAndAllCriteria(user *model.User, password string, mfaToken string) *model.AppError CheckPasswordAndAllCriteria(user *model.User, password string, mfaToken string) *model.AppError
CheckRolesExist(roleNames []string) *model.AppError CheckRolesExist(roleNames []string) *model.AppError
CheckUserAllAuthenticationCriteria(user *model.User, mfaToken string) *model.AppError CheckUserAllAuthenticationCriteria(user *model.User, mfaToken string) *model.AppError
@@ -834,6 +835,7 @@ type AppIface interface {
ReloadConfig() error ReloadConfig() error
RemoveAllDeactivatedMembersFromChannel(channel *model.Channel) *model.AppError RemoveAllDeactivatedMembersFromChannel(channel *model.Channel) *model.AppError
RemoveConfigListener(id string) RemoveConfigListener(id string)
RemoveDirectory(path string) *model.AppError
RemoveFile(path string) *model.AppError RemoveFile(path string) *model.AppError
RemoveLdapPrivateCertificate() *model.AppError RemoveLdapPrivateCertificate() *model.AppError
RemoveLdapPublicCertificate() *model.AppError RemoveLdapPublicCertificate() *model.AppError
@@ -957,6 +959,8 @@ type AppIface interface {
TelemetryId() string TelemetryId() string
TestElasticsearch(cfg *model.Config) *model.AppError TestElasticsearch(cfg *model.Config) *model.AppError
TestEmail(userId string, cfg *model.Config) *model.AppError TestEmail(userId string, cfg *model.Config) *model.AppError
TestFilesStoreConnection() *model.AppError
TestFilesStoreConnectionWithConfig(cfg *model.FileSettings) *model.AppError
TestLdap() *model.AppError TestLdap() *model.AppError
TestSiteURL(siteURL string) *model.AppError TestSiteURL(siteURL string) *model.AppError
Timezones() *timezones.Timezones Timezones() *timezones.Timezones

Просмотреть файл

@@ -76,12 +76,49 @@ func (a *App) FileBackend() (filesstore.FileBackend, *model.AppError) {
return a.Srv().FileBackend() return a.Srv().FileBackend()
} }
func (a *App) CheckMandatoryS3Fields(settings *model.FileSettings) *model.AppError {
err := filesstore.CheckMandatoryS3Fields(settings)
if err != nil {
return model.NewAppError("CheckMandatoryS3Fields", "api.admin.test_s3.missing_s3_bucket", nil, err.Error(), http.StatusBadRequest)
}
return nil
}
func (a *App) TestFilesStoreConnection() *model.AppError {
backend, err := a.FileBackend()
if err != nil {
return err
}
nErr := backend.TestConnection()
if nErr != nil {
return model.NewAppError("TestConnection", "api.file.test_connection.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}
return nil
}
func (a *App) TestFilesStoreConnectionWithConfig(cfg *model.FileSettings) *model.AppError {
license := a.Srv().License()
backend, err := filesstore.NewFileBackend(cfg, license != nil && *license.Features.Compliance)
if err != nil {
return model.NewAppError("FileBackend", "api.file.no_driver.app_error", nil, err.Error(), http.StatusInternalServerError)
}
nErr := backend.TestConnection()
if nErr != nil {
return model.NewAppError("TestConnection", "api.file.test_connection.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}
return nil
}
func (a *App) ReadFile(path string) ([]byte, *model.AppError) { func (a *App) ReadFile(path string) ([]byte, *model.AppError) {
backend, err := a.FileBackend() backend, err := a.FileBackend()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return backend.ReadFile(path) result, nErr := backend.ReadFile(path)
if nErr != nil {
return nil, model.NewAppError("ReadFile", "api.file.read_file.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}
return result, nil
} }
// Caller must close the first return value // Caller must close the first return value
@@ -90,7 +127,11 @@ func (a *App) FileReader(path string) (filesstore.ReadCloseSeeker, *model.AppErr
if err != nil { if err != nil {
return nil, err return nil, err
} }
return backend.Reader(path) result, nErr := backend.Reader(path)
if nErr != nil {
return nil, model.NewAppError("FileReader", "api.file.file_reader.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}
return result, nil
} }
func (a *App) FileExists(path string) (bool, *model.AppError) { func (a *App) FileExists(path string) (bool, *model.AppError) {
@@ -98,7 +139,11 @@ func (a *App) FileExists(path string) (bool, *model.AppError) {
if err != nil { if err != nil {
return false, err return false, err
} }
return backend.FileExists(path) result, nErr := backend.FileExists(path)
if nErr != nil {
return false, model.NewAppError("FileExists", "api.file.file_exists.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}
return result, nil
} }
func (a *App) FileSize(path string) (int64, *model.AppError) { func (a *App) FileSize(path string) (int64, *model.AppError) {
@@ -106,7 +151,11 @@ func (a *App) FileSize(path string) (int64, *model.AppError) {
if err != nil { if err != nil {
return 0, err return 0, err
} }
return backend.FileSize(path) size, nErr := backend.FileSize(path)
if nErr != nil {
return 0, model.NewAppError("FileSize", "api.file.file_size.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}
return size, nil
} }
func (a *App) MoveFile(oldPath, newPath string) *model.AppError { func (a *App) MoveFile(oldPath, newPath string) *model.AppError {
@@ -114,7 +163,11 @@ func (a *App) MoveFile(oldPath, newPath string) *model.AppError {
if err != nil { if err != nil {
return err return err
} }
return backend.MoveFile(oldPath, newPath) nErr := backend.MoveFile(oldPath, newPath)
if nErr != nil {
return model.NewAppError("MoveFile", "api.file.move_file.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}
return nil
} }
func (a *App) WriteFile(fr io.Reader, path string) (int64, *model.AppError) { func (a *App) WriteFile(fr io.Reader, path string) (int64, *model.AppError) {
@@ -123,7 +176,11 @@ func (a *App) WriteFile(fr io.Reader, path string) (int64, *model.AppError) {
return 0, err return 0, err
} }
return backend.WriteFile(fr, path) result, nErr := backend.WriteFile(fr, path)
if nErr != nil {
return result, model.NewAppError("WriteFile", "api.file.write_file.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}
return result, nil
} }
func (a *App) AppendFile(fr io.Reader, path string) (int64, *model.AppError) { func (a *App) AppendFile(fr io.Reader, path string) (int64, *model.AppError) {
@@ -132,7 +189,11 @@ func (a *App) AppendFile(fr io.Reader, path string) (int64, *model.AppError) {
return 0, err return 0, err
} }
return backend.AppendFile(fr, path) result, nErr := backend.AppendFile(fr, path)
if nErr != nil {
return result, model.NewAppError("AppendFile", "api.file.append_file.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}
return result, nil
} }
func (a *App) RemoveFile(path string) *model.AppError { func (a *App) RemoveFile(path string) *model.AppError {
@@ -140,7 +201,11 @@ func (a *App) RemoveFile(path string) *model.AppError {
if err != nil { if err != nil {
return err return err
} }
return backend.RemoveFile(path) nErr := backend.RemoveFile(path)
if nErr != nil {
return model.NewAppError("RemoveFile", "api.file.remove_file.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}
return nil
} }
func (a *App) ListDirectory(path string) ([]string, *model.AppError) { func (a *App) ListDirectory(path string) ([]string, *model.AppError) {
@@ -148,14 +213,27 @@ func (a *App) ListDirectory(path string) ([]string, *model.AppError) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
paths, err := backend.ListDirectory(path) paths, nErr := backend.ListDirectory(path)
if err != nil { if nErr != nil {
return nil, err return nil, model.NewAppError("ListDirectory", "api.file.list_directory.app_error", nil, nErr.Error(), http.StatusInternalServerError)
} }
return *paths, nil return *paths, nil
} }
func (a *App) RemoveDirectory(path string) *model.AppError {
backend, err := a.FileBackend()
if err != nil {
return err
}
nErr := backend.RemoveDirectory(path)
if nErr != nil {
return model.NewAppError("RemoveDirectory", "api.file.remove_directory.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}
return nil
}
func (a *App) getInfoForFilename(post *model.Post, teamId, channelId, userId, oldId, filename string) *model.FileInfo { func (a *App) getInfoForFilename(post *model.Post, teamId, channelId, userId, oldId, filename string) *model.FileInfo {
name, _ := url.QueryUnescape(filename) name, _ := url.QueryUnescape(filename)
pathPrefix := fmt.Sprintf("teams/%s/channels/%s/users/%s/%s/", teamId, channelId, userId, oldId) pathPrefix := fmt.Sprintf("teams/%s/channels/%s/users/%s/%s/", teamId, channelId, userId, oldId)

Просмотреть файл

@@ -1071,6 +1071,28 @@ func (a *OpenTracingAppLayer) CheckForClientSideCert(r *http.Request) (string, s
return resultVar0, resultVar1, resultVar2 return resultVar0, resultVar1, resultVar2
} }
func (a *OpenTracingAppLayer) CheckMandatoryS3Fields(settings *model.FileSettings) *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CheckMandatoryS3Fields")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.CheckMandatoryS3Fields(settings)
if resultVar0 != nil {
span.LogFields(spanlog.Error(resultVar0))
ext.Error.Set(span, true)
}
return resultVar0
}
func (a *OpenTracingAppLayer) CheckPasswordAndAllCriteria(user *model.User, password string, mfaToken string) *model.AppError { func (a *OpenTracingAppLayer) CheckPasswordAndAllCriteria(user *model.User, password string, mfaToken string) *model.AppError {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CheckPasswordAndAllCriteria") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CheckPasswordAndAllCriteria")
@@ -11709,6 +11731,28 @@ func (a *OpenTracingAppLayer) RemoveConfigListener(id string) {
a.app.RemoveConfigListener(id) a.app.RemoveConfigListener(id)
} }
func (a *OpenTracingAppLayer) RemoveDirectory(path string) *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RemoveDirectory")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.RemoveDirectory(path)
if resultVar0 != nil {
span.LogFields(spanlog.Error(resultVar0))
ext.Error.Set(span, true)
}
return resultVar0
}
func (a *OpenTracingAppLayer) RemoveFile(path string) *model.AppError { func (a *OpenTracingAppLayer) RemoveFile(path string) *model.AppError {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RemoveFile") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RemoveFile")
@@ -14300,6 +14344,50 @@ func (a *OpenTracingAppLayer) TestEmail(userId string, cfg *model.Config) *model
return resultVar0 return resultVar0
} }
func (a *OpenTracingAppLayer) TestFilesStoreConnection() *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.TestFilesStoreConnection")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.TestFilesStoreConnection()
if resultVar0 != nil {
span.LogFields(spanlog.Error(resultVar0))
ext.Error.Set(span, true)
}
return resultVar0
}
func (a *OpenTracingAppLayer) TestFilesStoreConnectionWithConfig(cfg *model.FileSettings) *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.TestFilesStoreConnectionWithConfig")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.TestFilesStoreConnectionWithConfig(cfg)
if resultVar0 != nil {
span.LogFields(spanlog.Error(resultVar0))
ext.Error.Set(span, true)
}
return resultVar0
}
func (a *OpenTracingAppLayer) TestLdap() *model.AppError { func (a *OpenTracingAppLayer) TestLdap() *model.AppError {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.TestLdap") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.TestLdap")

Просмотреть файл

@@ -465,11 +465,13 @@ func NewServer(options ...Option) (*Server, error) {
} }
backend, appErr := s.FileBackend() backend, appErr := s.FileBackend()
if appErr == nil {
appErr = backend.TestConnection()
}
if appErr != nil { if appErr != nil {
mlog.Error("Problem with file storage settings", mlog.Err(appErr)) mlog.Error("Problem with file storage settings", mlog.Err(appErr))
} else {
nErr := backend.TestConnection()
if nErr != nil {
mlog.Error("Problem with file storage settings", mlog.Err(nErr))
}
} }
s.timezones = timezones.New() s.timezones = timezones.New()
@@ -1531,7 +1533,11 @@ func (s *Server) stopSearchEngine() {
func (s *Server) FileBackend() (filesstore.FileBackend, *model.AppError) { func (s *Server) FileBackend() (filesstore.FileBackend, *model.AppError) {
license := s.License() license := s.License()
return filesstore.NewFileBackend(&s.Config().FileSettings, license != nil && *license.Features.Compliance) backend, err := filesstore.NewFileBackend(&s.Config().FileSettings, license != nil && *license.Features.Compliance)
if err != nil {
return nil, model.NewAppError("FileBackend", "api.file.no_driver.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return backend, nil
} }
func (s *Server) TotalWebsocketConnections() int { func (s *Server) TotalWebsocketConnections() int {

Просмотреть файл

@@ -1317,39 +1317,23 @@
"translation": "Unable to create the emoji. An error occurred when trying to open the attached image." "translation": "Unable to create the emoji. An error occurred when trying to open the attached image."
}, },
{ {
"id": "api.file.append_file.no_exist.app_error", "id": "api.file.append_file.app_error",
"translation": "File does not exist." "translation": "Unable to append data to the file."
},
{
"id": "api.file.append_file.opening.app_error",
"translation": "Encountered an error opening the file."
},
{
"id": "api.file.append_file.s3.app_error",
"translation": "Encountered an error appending to a file in S3."
},
{
"id": "api.file.append_file.writing.app_error",
"translation": "Encountered an error writing to S3."
}, },
{ {
"id": "api.file.attachments.disabled.app_error", "id": "api.file.attachments.disabled.app_error",
"translation": "File attachments have been disabled on this server." "translation": "File attachments have been disabled on this server."
}, },
{ {
"id": "api.file.file_exists.exists_local.app_error", "id": "api.file.file_exists.app_error",
"translation": "Unable to check if the file exists." "translation": "Unable to check if the file exists."
}, },
{ {
"id": "api.file.file_exists.s3.app_error", "id": "api.file.file_reader.app_error",
"translation": "Unable to check if the file exists." "translation": "Unable to get a file reader."
}, },
{ {
"id": "api.file.file_size.local.app_error", "id": "api.file.file_size.app_error",
"translation": "Unable to get the file size."
},
{
"id": "api.file.file_size.s3.app_error",
"translation": "Unable to get the file size." "translation": "Unable to get the file size."
}, },
{ {
@@ -1373,56 +1357,36 @@
"translation": "Unable to get public link for file. File must be attached to a post that can be read by the current user." "translation": "Unable to get public link for file. File must be attached to a post that can be read by the current user."
}, },
{ {
"id": "api.file.move_file.copy_within_s3.app_error", "id": "api.file.list_directory.app_error",
"translation": "Unable to copy file within S3." "translation": "Unable to list directory."
}, },
{ {
"id": "api.file.move_file.delete_from_s3.app_error", "id": "api.file.move_file.app_error",
"translation": "Unable to delete file from S3." "translation": "Unable to move file."
},
{
"id": "api.file.move_file.rename.app_error",
"translation": "Unable to move file locally."
},
{
"id": "api.file.new_backend.s3.app_error",
"translation": "Encountered an error opening a connection to S3."
}, },
{ {
"id": "api.file.no_driver.app_error", "id": "api.file.no_driver.app_error",
"translation": "No file driver selected." "translation": "No file driver selected."
}, },
{
"id": "api.file.read_file.app_error",
"translation": "Unable to read the file."
},
{ {
"id": "api.file.read_file.reading_local.app_error", "id": "api.file.read_file.reading_local.app_error",
"translation": "Encountered an error reading from local server file storage." "translation": "Encountered an error reading from local server file storage."
}, },
{ {
"id": "api.file.read_file.s3.app_error", "id": "api.file.remove_directory.app_error",
"translation": "Encountered an error reading from S3 storage." "translation": "Unable to remove the directory."
}, },
{ {
"id": "api.file.reader.reading_local.app_error", "id": "api.file.remove_file.app_error",
"translation": "Encountered an error opening a reader from local server file storage." "translation": "Unable to remove the file."
}, },
{ {
"id": "api.file.reader.s3.app_error", "id": "api.file.test_connection.app_error",
"translation": "Encountered an error opening a reader from S3 storage." "translation": "Unable to access the file storage."
},
{
"id": "api.file.test_connection.local.connection.app_error",
"translation": "Don't have permissions to write to local path specified or other error."
},
{
"id": "api.file.test_connection.s3.bucket_create.app_error",
"translation": "Unable to create bucket."
},
{
"id": "api.file.test_connection.s3.bucket_exists.app_error",
"translation": "Error checking if bucket exists."
},
{
"id": "api.file.test_connection.s3.list_objects.app_error",
"translation": "Error trying to list objects."
}, },
{ {
"id": "api.file.upload_file.incorrect_channelId.app_error", "id": "api.file.upload_file.incorrect_channelId.app_error",
@@ -1465,16 +1429,8 @@
"translation": "Unable to upload file {{.Filename}}. {{.Length}} bytes exceeds the maximum allowed {{.Limit}} bytes." "translation": "Unable to upload file {{.Filename}}. {{.Length}} bytes exceeds the maximum allowed {{.Limit}} bytes."
}, },
{ {
"id": "api.file.write_file.s3.app_error", "id": "api.file.write_file.app_error",
"translation": "Encountered an error writing to S3." "translation": "Unable to write the file."
},
{
"id": "api.file.write_file_locally.create_dir.app_error",
"translation": "Encountered an error creating the directory for the new file."
},
{
"id": "api.file.write_file_locally.writing.app_error",
"translation": "Encountered an error writing to local server storage."
}, },
{ {
"id": "api.image.get.app_error", "id": "api.image.get.app_error",
@@ -6026,6 +5982,10 @@
"id": "ent.actiance.export.marshalToXml.appError", "id": "ent.actiance.export.marshalToXml.appError",
"translation": "Unable to convert export to XML." "translation": "Unable to convert export to XML."
}, },
{
"id": "ent.actiance.export.write_file.appError",
"translation": "Unable to write the export file."
},
{ {
"id": "ent.api.post.send_notifications_and_forget.push_image_only", "id": "ent.api.post.send_notifications_and_forget.push_image_only",
"translation": " attached a file." "translation": " attached a file."
@@ -6106,6 +6066,10 @@
"id": "ent.compliance.csv.warning.appError", "id": "ent.compliance.csv.warning.appError",
"translation": "Unable to create the warning file." "translation": "Unable to create the warning file."
}, },
{
"id": "ent.compliance.csv.write_file.appError",
"translation": "Unable to write the csv file."
},
{ {
"id": "ent.compliance.csv.zip.creation.appError", "id": "ent.compliance.csv.zip.creation.appError",
"translation": "Unable to create the zip export file." "translation": "Unable to create the zip export file."
@@ -6122,6 +6086,10 @@
"id": "ent.compliance.global_relay.rewind_temporary_file.appError", "id": "ent.compliance.global_relay.rewind_temporary_file.appError",
"translation": "Unable to re-read the Global Relay temporary export file." "translation": "Unable to re-read the Global Relay temporary export file."
}, },
{
"id": "ent.compliance.global_relay.write_file.appError",
"translation": "Unable to write the global relay file."
},
{ {
"id": "ent.compliance.licence_disable.app_error", "id": "ent.compliance.licence_disable.app_error",
"translation": "Compliance functionality disabled by current license. Please contact your system administrator about upgrading your enterprise license." "translation": "Compliance functionality disabled by current license. Please contact your system administrator about upgrading your enterprise license."
@@ -8246,30 +8214,6 @@
"id": "system.message.name", "id": "system.message.name",
"translation": "System" "translation": "System"
}, },
{
"id": "utils.file.list_directory.local.app_error",
"translation": "Encountered an error listing directory from local server file storage."
},
{
"id": "utils.file.list_directory.s3.app_error",
"translation": "Encountered an error listing directory from S3."
},
{
"id": "utils.file.remove_directory.local.app_error",
"translation": "Encountered an error removing directory from local server file storage."
},
{
"id": "utils.file.remove_directory.s3.app_error",
"translation": "Encountered an error removing directory from S3."
},
{
"id": "utils.file.remove_file.local.app_error",
"translation": "Encountered an error removing file from local server file storage."
},
{
"id": "utils.file.remove_file.s3.app_error",
"translation": "Encountered an error removing file from S3."
},
{ {
"id": "utils.mail.connect_smtp.helo.app_error", "id": "utils.mail.connect_smtp.helo.app_error",
"translation": "Failed to set HELO." "translation": "Failed to set HELO."

Просмотреть файл

@@ -5,7 +5,8 @@ package filesstore
import ( import (
"io" "io"
"net/http"
"github.com/pkg/errors"
"github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/model"
) )
@@ -16,28 +17,28 @@ type ReadCloseSeeker interface {
} }
type FileBackend interface { type FileBackend interface {
TestConnection() *model.AppError TestConnection() error
Reader(path string) (ReadCloseSeeker, *model.AppError) Reader(path string) (ReadCloseSeeker, error)
ReadFile(path string) ([]byte, *model.AppError) ReadFile(path string) ([]byte, error)
FileExists(path string) (bool, *model.AppError) FileExists(path string) (bool, error)
FileSize(path string) (int64, *model.AppError) FileSize(path string) (int64, error)
CopyFile(oldPath, newPath string) *model.AppError CopyFile(oldPath, newPath string) error
MoveFile(oldPath, newPath string) *model.AppError MoveFile(oldPath, newPath string) error
WriteFile(fr io.Reader, path string) (int64, *model.AppError) WriteFile(fr io.Reader, path string) (int64, error)
AppendFile(fr io.Reader, path string) (int64, *model.AppError) AppendFile(fr io.Reader, path string) (int64, error)
RemoveFile(path string) *model.AppError RemoveFile(path string) error
ListDirectory(path string) (*[]string, *model.AppError) ListDirectory(path string) (*[]string, error)
RemoveDirectory(path string) *model.AppError RemoveDirectory(path string) error
} }
func NewFileBackend(settings *model.FileSettings, enableComplianceFeatures bool) (FileBackend, *model.AppError) { func NewFileBackend(settings *model.FileSettings, enableComplianceFeatures bool) (FileBackend, error) {
switch *settings.DriverName { switch *settings.DriverName {
case model.IMAGE_DRIVER_S3: case model.IMAGE_DRIVER_S3:
backend, err := NewS3FileBackend(settings, enableComplianceFeatures) backend, err := NewS3FileBackend(settings, enableComplianceFeatures)
if err != nil { if err != nil {
return nil, model.NewAppError("NewFileBackend", "api.file.new_backend.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, errors.Wrap(err, "unable to connect to the s3 backend")
} }
return backend, nil return backend, nil
case model.IMAGE_DRIVER_LOCAL: case model.IMAGE_DRIVER_LOCAL:
@@ -45,5 +46,5 @@ func NewFileBackend(settings *model.FileSettings, enableComplianceFeatures bool)
directory: *settings.Directory, directory: *settings.Directory,
}, nil }, nil
} }
return nil, model.NewAppError("NewFileBackend", "api.file.no_driver.app_error", nil, "", http.StatusInternalServerError) return nil, errors.New("no valid filestorage driver found")
} }

Просмотреть файл

@@ -7,12 +7,12 @@ import (
"bytes" "bytes"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
"github.com/pkg/errors"
"github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/mlog"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/utils" "github.com/mattermost/mattermost-server/v5/utils"
) )
@@ -24,33 +24,33 @@ type LocalFileBackend struct {
directory string directory string
} }
func (b *LocalFileBackend) TestConnection() *model.AppError { func (b *LocalFileBackend) TestConnection() error {
f := bytes.NewReader([]byte("testingwrite")) f := bytes.NewReader([]byte("testingwrite"))
if _, err := writeFileLocally(f, filepath.Join(b.directory, TEST_FILE_PATH)); err != nil { if _, err := writeFileLocally(f, filepath.Join(b.directory, TEST_FILE_PATH)); err != nil {
return model.NewAppError("TestFileConnection", "api.file.test_connection.local.connection.app_error", nil, err.Error(), http.StatusInternalServerError) return errors.Wrap(err, "unable to write to the local filesystem storage")
} }
os.Remove(filepath.Join(b.directory, TEST_FILE_PATH)) os.Remove(filepath.Join(b.directory, TEST_FILE_PATH))
mlog.Debug("Able to write files to local storage.") mlog.Debug("Able to write files to local storage.")
return nil return nil
} }
func (b *LocalFileBackend) Reader(path string) (ReadCloseSeeker, *model.AppError) { func (b *LocalFileBackend) Reader(path string) (ReadCloseSeeker, error) {
f, err := os.Open(filepath.Join(b.directory, path)) f, err := os.Open(filepath.Join(b.directory, path))
if err != nil { if err != nil {
return nil, model.NewAppError("Reader", "api.file.reader.reading_local.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, errors.Wrapf(err, "unable to open file %s", path)
} }
return f, nil return f, nil
} }
func (b *LocalFileBackend) ReadFile(path string) ([]byte, *model.AppError) { func (b *LocalFileBackend) ReadFile(path string) ([]byte, error) {
f, err := ioutil.ReadFile(filepath.Join(b.directory, path)) f, err := ioutil.ReadFile(filepath.Join(b.directory, path))
if err != nil { if err != nil {
return nil, model.NewAppError("ReadFile", "api.file.read_file.reading_local.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, errors.Wrapf(err, "unable to read file %s", path)
} }
return f, nil return f, nil
} }
func (b *LocalFileBackend) FileExists(path string) (bool, *model.AppError) { func (b *LocalFileBackend) FileExists(path string) (bool, error) {
_, err := os.Stat(filepath.Join(b.directory, path)) _, err := os.Stat(filepath.Join(b.directory, path))
if os.IsNotExist(err) { if os.IsNotExist(err) {
@@ -58,91 +58,91 @@ func (b *LocalFileBackend) FileExists(path string) (bool, *model.AppError) {
} }
if err != nil { if err != nil {
return false, model.NewAppError("ReadFile", "api.file.file_exists.exists_local.app_error", nil, err.Error(), http.StatusInternalServerError) return false, errors.Wrapf(err, "unable to know if file %s exists", path)
} }
return true, nil return true, nil
} }
func (b *LocalFileBackend) FileSize(path string) (int64, *model.AppError) { func (b *LocalFileBackend) FileSize(path string) (int64, error) {
info, err := os.Stat(filepath.Join(b.directory, path)) info, err := os.Stat(filepath.Join(b.directory, path))
if err != nil { if err != nil {
return 0, model.NewAppError("FileSize", "api.file.file_size.local.app_error", nil, err.Error(), http.StatusInternalServerError) return 0, errors.Wrapf(err, "unable to get file size for %s", path)
} }
return info.Size(), nil return info.Size(), nil
} }
func (b *LocalFileBackend) CopyFile(oldPath, newPath string) *model.AppError { func (b *LocalFileBackend) CopyFile(oldPath, newPath string) error {
if err := utils.CopyFile(filepath.Join(b.directory, oldPath), filepath.Join(b.directory, newPath)); err != nil { if err := utils.CopyFile(filepath.Join(b.directory, oldPath), filepath.Join(b.directory, newPath)); err != nil {
return model.NewAppError("copyFile", "api.file.move_file.rename.app_error", nil, err.Error(), http.StatusInternalServerError) return errors.Wrapf(err, "unable to copy file from %s to %s", oldPath, newPath)
} }
return nil return nil
} }
func (b *LocalFileBackend) MoveFile(oldPath, newPath string) *model.AppError { func (b *LocalFileBackend) MoveFile(oldPath, newPath string) error {
if err := os.MkdirAll(filepath.Dir(filepath.Join(b.directory, newPath)), 0750); err != nil { if err := os.MkdirAll(filepath.Dir(filepath.Join(b.directory, newPath)), 0750); err != nil {
return model.NewAppError("moveFile", "api.file.move_file.rename.app_error", nil, err.Error(), http.StatusInternalServerError) return errors.Wrapf(err, "unable to create the new destination directory %s", filepath.Dir(newPath))
} }
if err := os.Rename(filepath.Join(b.directory, oldPath), filepath.Join(b.directory, newPath)); err != nil { if err := os.Rename(filepath.Join(b.directory, oldPath), filepath.Join(b.directory, newPath)); err != nil {
return model.NewAppError("moveFile", "api.file.move_file.rename.app_error", nil, err.Error(), http.StatusInternalServerError) return errors.Wrapf(err, "unable to move the file to %s to the destination directory", newPath)
} }
return nil return nil
} }
func (b *LocalFileBackend) WriteFile(fr io.Reader, path string) (int64, *model.AppError) { func (b *LocalFileBackend) WriteFile(fr io.Reader, path string) (int64, error) {
return writeFileLocally(fr, filepath.Join(b.directory, path)) return writeFileLocally(fr, filepath.Join(b.directory, path))
} }
func writeFileLocally(fr io.Reader, path string) (int64, *model.AppError) { func writeFileLocally(fr io.Reader, path string) (int64, error) {
if err := os.MkdirAll(filepath.Dir(path), 0750); err != nil { if err := os.MkdirAll(filepath.Dir(path), 0750); err != nil {
directory, _ := filepath.Abs(filepath.Dir(path)) directory, _ := filepath.Abs(filepath.Dir(path))
return 0, model.NewAppError("WriteFile", "api.file.write_file_locally.create_dir.app_error", nil, "directory="+directory+", err="+err.Error(), http.StatusInternalServerError) return 0, errors.Wrapf(err, "unable to create the directory %s for the file %s", directory, path)
} }
fw, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) fw, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil { if err != nil {
return 0, model.NewAppError("WriteFile", "api.file.write_file_locally.writing.app_error", nil, err.Error(), http.StatusInternalServerError) return 0, errors.Wrapf(err, "unable to open the file %s to write the data", path)
} }
defer fw.Close() defer fw.Close()
written, err := io.Copy(fw, fr) written, err := io.Copy(fw, fr)
if err != nil { if err != nil {
return written, model.NewAppError("WriteFile", "api.file.write_file_locally.writing.app_error", nil, err.Error(), http.StatusInternalServerError) return written, errors.Wrapf(err, "unable write the data in the file %s", path)
} }
return written, nil return written, nil
} }
func (b *LocalFileBackend) AppendFile(fr io.Reader, path string) (int64, *model.AppError) { func (b *LocalFileBackend) AppendFile(fr io.Reader, path string) (int64, error) {
fp := filepath.Join(b.directory, path) fp := filepath.Join(b.directory, path)
if _, err := os.Stat(fp); err != nil { if _, err := os.Stat(fp); err != nil {
return 0, model.NewAppError("AppendFile", "api.file.append_file.no_exist.app_error", nil, err.Error(), http.StatusInternalServerError) return 0, errors.Wrapf(err, "unable to find the file %s to append the data", path)
} }
fw, err := os.OpenFile(fp, os.O_WRONLY|os.O_APPEND, 0600) fw, err := os.OpenFile(fp, os.O_WRONLY|os.O_APPEND, 0600)
if err != nil { if err != nil {
return 0, model.NewAppError("AppendFile", "api.file.append_file.opening.app_error", nil, err.Error(), http.StatusInternalServerError) return 0, errors.Wrapf(err, "unable to open the file %s to append the data", path)
} }
defer fw.Close() defer fw.Close()
written, err := io.Copy(fw, fr) written, err := io.Copy(fw, fr)
if err != nil { if err != nil {
return written, model.NewAppError("AppendFile", "api.file.append_file.writing.app_error", nil, err.Error(), http.StatusInternalServerError) return written, errors.Wrapf(err, "unable append the data in the file %s", path)
} }
return written, nil return written, nil
} }
func (b *LocalFileBackend) RemoveFile(path string) *model.AppError { func (b *LocalFileBackend) RemoveFile(path string) error {
if err := os.Remove(filepath.Join(b.directory, path)); err != nil { if err := os.Remove(filepath.Join(b.directory, path)); err != nil {
return model.NewAppError("RemoveFile", "utils.file.remove_file.local.app_error", nil, err.Error(), http.StatusInternalServerError) return errors.Wrapf(err, "unable to remove the file %s", path)
} }
return nil return nil
} }
func (b *LocalFileBackend) ListDirectory(path string) (*[]string, *model.AppError) { func (b *LocalFileBackend) ListDirectory(path string) (*[]string, error) {
var paths []string var paths []string
fileInfos, err := ioutil.ReadDir(filepath.Join(b.directory, path)) fileInfos, err := ioutil.ReadDir(filepath.Join(b.directory, path))
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return &paths, nil return &paths, nil
} }
return nil, model.NewAppError("ListDirectory", "utils.file.list_directory.local.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, errors.Wrapf(err, "unable to list the directory %s", path)
} }
for _, fileInfo := range fileInfos { for _, fileInfo := range fileInfos {
paths = append(paths, filepath.Join(path, fileInfo.Name())) paths = append(paths, filepath.Join(path, fileInfo.Name()))
@@ -150,9 +150,9 @@ func (b *LocalFileBackend) ListDirectory(path string) (*[]string, *model.AppErro
return &paths, nil return &paths, nil
} }
func (b *LocalFileBackend) RemoveDirectory(path string) *model.AppError { func (b *LocalFileBackend) RemoveDirectory(path string) error {
if err := os.RemoveAll(filepath.Join(b.directory, path)); err != nil { if err := os.RemoveAll(filepath.Join(b.directory, path)); err != nil {
return model.NewAppError("RemoveDirectory", "utils.file.remove_directory.local.app_error", nil, err.Error(), http.StatusInternalServerError) return errors.Wrapf(err, "unable to remove the directory %s", path)
} }
return nil return nil
} }

Просмотреть файл

@@ -10,8 +10,6 @@ import (
filesstore "github.com/mattermost/mattermost-server/v5/services/filesstore" filesstore "github.com/mattermost/mattermost-server/v5/services/filesstore"
mock "github.com/stretchr/testify/mock" mock "github.com/stretchr/testify/mock"
model "github.com/mattermost/mattermost-server/v5/model"
) )
// FileBackend is an autogenerated mock type for the FileBackend type // FileBackend is an autogenerated mock type for the FileBackend type
@@ -20,7 +18,7 @@ type FileBackend struct {
} }
// AppendFile provides a mock function with given fields: fr, path // AppendFile provides a mock function with given fields: fr, path
func (_m *FileBackend) AppendFile(fr io.Reader, path string) (int64, *model.AppError) { func (_m *FileBackend) AppendFile(fr io.Reader, path string) (int64, error) {
ret := _m.Called(fr, path) ret := _m.Called(fr, path)
var r0 int64 var r0 int64
@@ -30,36 +28,32 @@ func (_m *FileBackend) AppendFile(fr io.Reader, path string) (int64, *model.AppE
r0 = ret.Get(0).(int64) r0 = ret.Get(0).(int64)
} }
var r1 *model.AppError var r1 error
if rf, ok := ret.Get(1).(func(io.Reader, string) *model.AppError); ok { if rf, ok := ret.Get(1).(func(io.Reader, string) error); ok {
r1 = rf(fr, path) r1 = rf(fr, path)
} else { } else {
if ret.Get(1) != nil { r1 = ret.Error(1)
r1 = ret.Get(1).(*model.AppError)
}
} }
return r0, r1 return r0, r1
} }
// CopyFile provides a mock function with given fields: oldPath, newPath // CopyFile provides a mock function with given fields: oldPath, newPath
func (_m *FileBackend) CopyFile(oldPath string, newPath string) *model.AppError { func (_m *FileBackend) CopyFile(oldPath string, newPath string) error {
ret := _m.Called(oldPath, newPath) ret := _m.Called(oldPath, newPath)
var r0 *model.AppError var r0 error
if rf, ok := ret.Get(0).(func(string, string) *model.AppError); ok { if rf, ok := ret.Get(0).(func(string, string) error); ok {
r0 = rf(oldPath, newPath) r0 = rf(oldPath, newPath)
} else { } else {
if ret.Get(0) != nil { r0 = ret.Error(0)
r0 = ret.Get(0).(*model.AppError)
}
} }
return r0 return r0
} }
// FileExists provides a mock function with given fields: path // FileExists provides a mock function with given fields: path
func (_m *FileBackend) FileExists(path string) (bool, *model.AppError) { func (_m *FileBackend) FileExists(path string) (bool, error) {
ret := _m.Called(path) ret := _m.Called(path)
var r0 bool var r0 bool
@@ -69,20 +63,18 @@ func (_m *FileBackend) FileExists(path string) (bool, *model.AppError) {
r0 = ret.Get(0).(bool) r0 = ret.Get(0).(bool)
} }
var r1 *model.AppError var r1 error
if rf, ok := ret.Get(1).(func(string) *model.AppError); ok { if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(path) r1 = rf(path)
} else { } else {
if ret.Get(1) != nil { r1 = ret.Error(1)
r1 = ret.Get(1).(*model.AppError)
}
} }
return r0, r1 return r0, r1
} }
// ListDirectory provides a mock function with given fields: path // ListDirectory provides a mock function with given fields: path
func (_m *FileBackend) ListDirectory(path string) (*[]string, *model.AppError) { func (_m *FileBackend) ListDirectory(path string) (*[]string, error) {
ret := _m.Called(path) ret := _m.Called(path)
var r0 *[]string var r0 *[]string
@@ -94,36 +86,32 @@ func (_m *FileBackend) ListDirectory(path string) (*[]string, *model.AppError) {
} }
} }
var r1 *model.AppError var r1 error
if rf, ok := ret.Get(1).(func(string) *model.AppError); ok { if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(path) r1 = rf(path)
} else { } else {
if ret.Get(1) != nil { r1 = ret.Error(1)
r1 = ret.Get(1).(*model.AppError)
}
} }
return r0, r1 return r0, r1
} }
// MoveFile provides a mock function with given fields: oldPath, newPath // MoveFile provides a mock function with given fields: oldPath, newPath
func (_m *FileBackend) MoveFile(oldPath string, newPath string) *model.AppError { func (_m *FileBackend) MoveFile(oldPath string, newPath string) error {
ret := _m.Called(oldPath, newPath) ret := _m.Called(oldPath, newPath)
var r0 *model.AppError var r0 error
if rf, ok := ret.Get(0).(func(string, string) *model.AppError); ok { if rf, ok := ret.Get(0).(func(string, string) error); ok {
r0 = rf(oldPath, newPath) r0 = rf(oldPath, newPath)
} else { } else {
if ret.Get(0) != nil { r0 = ret.Error(0)
r0 = ret.Get(0).(*model.AppError)
}
} }
return r0 return r0
} }
// ReadFile provides a mock function with given fields: path // ReadFile provides a mock function with given fields: path
func (_m *FileBackend) ReadFile(path string) ([]byte, *model.AppError) { func (_m *FileBackend) ReadFile(path string) ([]byte, error) {
ret := _m.Called(path) ret := _m.Called(path)
var r0 []byte var r0 []byte
@@ -135,20 +123,18 @@ func (_m *FileBackend) ReadFile(path string) ([]byte, *model.AppError) {
} }
} }
var r1 *model.AppError var r1 error
if rf, ok := ret.Get(1).(func(string) *model.AppError); ok { if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(path) r1 = rf(path)
} else { } else {
if ret.Get(1) != nil { r1 = ret.Error(1)
r1 = ret.Get(1).(*model.AppError)
}
} }
return r0, r1 return r0, r1
} }
// Reader provides a mock function with given fields: path // Reader provides a mock function with given fields: path
func (_m *FileBackend) Reader(path string) (filesstore.ReadCloseSeeker, *model.AppError) { func (_m *FileBackend) Reader(path string) (filesstore.ReadCloseSeeker, error) {
ret := _m.Called(path) ret := _m.Called(path)
var r0 filesstore.ReadCloseSeeker var r0 filesstore.ReadCloseSeeker
@@ -160,68 +146,60 @@ func (_m *FileBackend) Reader(path string) (filesstore.ReadCloseSeeker, *model.A
} }
} }
var r1 *model.AppError var r1 error
if rf, ok := ret.Get(1).(func(string) *model.AppError); ok { if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(path) r1 = rf(path)
} else { } else {
if ret.Get(1) != nil { r1 = ret.Error(1)
r1 = ret.Get(1).(*model.AppError)
}
} }
return r0, r1 return r0, r1
} }
// RemoveDirectory provides a mock function with given fields: path // RemoveDirectory provides a mock function with given fields: path
func (_m *FileBackend) RemoveDirectory(path string) *model.AppError { func (_m *FileBackend) RemoveDirectory(path string) error {
ret := _m.Called(path) ret := _m.Called(path)
var r0 *model.AppError var r0 error
if rf, ok := ret.Get(0).(func(string) *model.AppError); ok { if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(path) r0 = rf(path)
} else { } else {
if ret.Get(0) != nil { r0 = ret.Error(0)
r0 = ret.Get(0).(*model.AppError)
}
} }
return r0 return r0
} }
// RemoveFile provides a mock function with given fields: path // RemoveFile provides a mock function with given fields: path
func (_m *FileBackend) RemoveFile(path string) *model.AppError { func (_m *FileBackend) RemoveFile(path string) error {
ret := _m.Called(path) ret := _m.Called(path)
var r0 *model.AppError var r0 error
if rf, ok := ret.Get(0).(func(string) *model.AppError); ok { if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(path) r0 = rf(path)
} else { } else {
if ret.Get(0) != nil { r0 = ret.Error(0)
r0 = ret.Get(0).(*model.AppError)
}
} }
return r0 return r0
} }
// TestConnection provides a mock function with given fields: // TestConnection provides a mock function with given fields:
func (_m *FileBackend) TestConnection() *model.AppError { func (_m *FileBackend) TestConnection() error {
ret := _m.Called() ret := _m.Called()
var r0 *model.AppError var r0 error
if rf, ok := ret.Get(0).(func() *model.AppError); ok { if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf() r0 = rf()
} else { } else {
if ret.Get(0) != nil { r0 = ret.Error(0)
r0 = ret.Get(0).(*model.AppError)
}
} }
return r0 return r0
} }
// WriteFile provides a mock function with given fields: fr, path // WriteFile provides a mock function with given fields: fr, path
func (_m *FileBackend) WriteFile(fr io.Reader, path string) (int64, *model.AppError) { func (_m *FileBackend) WriteFile(fr io.Reader, path string) (int64, error) {
ret := _m.Called(fr, path) ret := _m.Called(fr, path)
var r0 int64 var r0 int64
@@ -231,13 +209,11 @@ func (_m *FileBackend) WriteFile(fr io.Reader, path string) (int64, *model.AppEr
r0 = ret.Get(0).(int64) r0 = ret.Get(0).(int64)
} }
var r1 *model.AppError var r1 error
if rf, ok := ret.Get(1).(func(io.Reader, string) *model.AppError); ok { if rf, ok := ret.Get(1).(func(io.Reader, string) error); ok {
r1 = rf(fr, path) r1 = rf(fr, path)
} else { } else {
if ret.Get(1) != nil { r1 = ret.Error(1)
r1 = ret.Get(1).(*model.AppError)
}
} }
return r0, r1 return r0, r1

Просмотреть файл

@@ -5,10 +5,8 @@ package filesstore
import ( import (
"context" "context"
"errors"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@@ -16,6 +14,7 @@ import (
s3 "github.com/minio/minio-go/v7" s3 "github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials" "github.com/minio/minio-go/v7/pkg/credentials"
"github.com/minio/minio-go/v7/pkg/encrypt" "github.com/minio/minio-go/v7/pkg/encrypt"
"github.com/pkg/errors"
"github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/mlog"
"github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/model"
@@ -118,7 +117,7 @@ func (b *S3FileBackend) s3New() (*s3.Client, error) {
return s3Clnt, nil return s3Clnt, nil
} }
func (b *S3FileBackend) TestConnection() *model.AppError { func (b *S3FileBackend) TestConnection() error {
exists := true exists := true
var err error var err error
// If a path prefix is present, we attempt to test the bucket by listing objects under the path // If a path prefix is present, we attempt to test the bucket by listing objects under the path
@@ -129,14 +128,14 @@ func (b *S3FileBackend) TestConnection() *model.AppError {
if obj.Err != nil { if obj.Err != nil {
typedErr := s3.ToErrorResponse(obj.Err) typedErr := s3.ToErrorResponse(obj.Err)
if typedErr.Code != bucketNotFound { if typedErr.Code != bucketNotFound {
return model.NewAppError("TestFileConnection", "api.file.test_connection.s3.list_objects.app_error", nil, obj.Err.Error(), http.StatusInternalServerError) return errors.Wrap(err, "unable to list objects in the s3 bucket")
} }
exists = false exists = false
} }
} else { } else {
exists, err = b.client.BucketExists(context.Background(), b.bucket) exists, err = b.client.BucketExists(context.Background(), b.bucket)
if err != nil { if err != nil {
return model.NewAppError("TestFileConnection", "api.file.test_connection.s3.bucket_exists.app_error", nil, err.Error(), http.StatusInternalServerError) return errors.Wrap(err, "unable to check if the s3 bucket exists")
} }
} }
@@ -146,7 +145,7 @@ func (b *S3FileBackend) TestConnection() *model.AppError {
mlog.Warn("Bucket specified does not exist. Attempting to create...") mlog.Warn("Bucket specified does not exist. Attempting to create...")
err := b.client.MakeBucket(context.Background(), b.bucket, s3.MakeBucketOptions{Region: b.region}) err := b.client.MakeBucket(context.Background(), b.bucket, s3.MakeBucketOptions{Region: b.region})
if err != nil { if err != nil {
return model.NewAppError("TestFileConnection", "api.file.test_connection.s3.bucket_create.app_error", nil, err.Error(), http.StatusInternalServerError) return errors.Wrap(err, "unable to create the s3 bucket")
} }
} }
@@ -154,32 +153,32 @@ func (b *S3FileBackend) TestConnection() *model.AppError {
} }
// Caller must close the first return value // Caller must close the first return value
func (b *S3FileBackend) Reader(path string) (ReadCloseSeeker, *model.AppError) { func (b *S3FileBackend) Reader(path string) (ReadCloseSeeker, error) {
path = filepath.Join(b.pathPrefix, path) path = filepath.Join(b.pathPrefix, path)
minioObject, err := b.client.GetObject(context.Background(), b.bucket, path, s3.GetObjectOptions{}) minioObject, err := b.client.GetObject(context.Background(), b.bucket, path, s3.GetObjectOptions{})
if err != nil { if err != nil {
return nil, model.NewAppError("Reader", "api.file.reader.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, errors.Wrapf(err, "unable to open file %s", path)
} }
return minioObject, nil return minioObject, nil
} }
func (b *S3FileBackend) ReadFile(path string) ([]byte, *model.AppError) { func (b *S3FileBackend) ReadFile(path string) ([]byte, error) {
path = filepath.Join(b.pathPrefix, path) path = filepath.Join(b.pathPrefix, path)
minioObject, err := b.client.GetObject(context.Background(), b.bucket, path, s3.GetObjectOptions{}) minioObject, err := b.client.GetObject(context.Background(), b.bucket, path, s3.GetObjectOptions{})
if err != nil { if err != nil {
return nil, model.NewAppError("ReadFile", "api.file.read_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, errors.Wrapf(err, "unable to open file %s", path)
} }
defer minioObject.Close() defer minioObject.Close()
if f, err := ioutil.ReadAll(minioObject); err != nil { if f, err := ioutil.ReadAll(minioObject); err != nil {
return nil, model.NewAppError("ReadFile", "api.file.read_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, errors.Wrapf(err, "unable to read file %s", path)
} else { } else {
return f, nil return f, nil
} }
} }
func (b *S3FileBackend) FileExists(path string) (bool, *model.AppError) { func (b *S3FileBackend) FileExists(path string) (bool, error) {
path = filepath.Join(b.pathPrefix, path) path = filepath.Join(b.pathPrefix, path)
_, err := b.client.StatObject(context.Background(), b.bucket, path, s3.StatObjectOptions{}) _, err := b.client.StatObject(context.Background(), b.bucket, path, s3.StatObjectOptions{})
@@ -192,21 +191,21 @@ func (b *S3FileBackend) FileExists(path string) (bool, *model.AppError) {
return false, nil return false, nil
} }
return false, model.NewAppError("FileExists", "api.file.file_exists.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return false, errors.Wrapf(err, "unable to know if file %s exists", path)
} }
func (b *S3FileBackend) FileSize(path string) (int64, *model.AppError) { func (b *S3FileBackend) FileSize(path string) (int64, error) {
path = filepath.Join(b.pathPrefix, path) path = filepath.Join(b.pathPrefix, path)
info, err := b.client.StatObject(context.Background(), b.bucket, path, s3.StatObjectOptions{}) info, err := b.client.StatObject(context.Background(), b.bucket, path, s3.StatObjectOptions{})
if err != nil { if err != nil {
return 0, model.NewAppError("FileSize", "api.file.file_size.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return 0, errors.Wrapf(err, "unable to get file size for %s", path)
} }
return info.Size, nil return info.Size, nil
} }
func (b *S3FileBackend) CopyFile(oldPath, newPath string) *model.AppError { func (b *S3FileBackend) CopyFile(oldPath, newPath string) error {
oldPath = filepath.Join(b.pathPrefix, oldPath) oldPath = filepath.Join(b.pathPrefix, oldPath)
newPath = filepath.Join(b.pathPrefix, newPath) newPath = filepath.Join(b.pathPrefix, newPath)
srcOpts := s3.CopySrcOptions{ srcOpts := s3.CopySrcOptions{
@@ -220,12 +219,12 @@ func (b *S3FileBackend) CopyFile(oldPath, newPath string) *model.AppError {
Encryption: encrypt.NewSSE(), Encryption: encrypt.NewSSE(),
} }
if _, err := b.client.CopyObject(context.Background(), dstOpts, srcOpts); err != nil { if _, err := b.client.CopyObject(context.Background(), dstOpts, srcOpts); err != nil {
return model.NewAppError("copyFile", "api.file.move_file.copy_within_s3.app_error", nil, err.Error(), http.StatusInternalServerError) return errors.Wrapf(err, "unable to copy file from %s to %s", oldPath, newPath)
} }
return nil return nil
} }
func (b *S3FileBackend) MoveFile(oldPath, newPath string) *model.AppError { func (b *S3FileBackend) MoveFile(oldPath, newPath string) error {
oldPath = filepath.Join(b.pathPrefix, oldPath) oldPath = filepath.Join(b.pathPrefix, oldPath)
newPath = filepath.Join(b.pathPrefix, newPath) newPath = filepath.Join(b.pathPrefix, newPath)
srcOpts := s3.CopySrcOptions{ srcOpts := s3.CopySrcOptions{
@@ -240,17 +239,17 @@ func (b *S3FileBackend) MoveFile(oldPath, newPath string) *model.AppError {
} }
if _, err := b.client.CopyObject(context.Background(), dstOpts, srcOpts); err != nil { if _, err := b.client.CopyObject(context.Background(), dstOpts, srcOpts); err != nil {
return model.NewAppError("moveFile", "api.file.move_file.copy_within_s3.app_error", nil, err.Error(), http.StatusInternalServerError) return errors.Wrapf(err, "unable to copy the file to %s to the new destionation", newPath)
} }
if err := b.client.RemoveObject(context.Background(), b.bucket, oldPath, s3.RemoveObjectOptions{}); err != nil { if err := b.client.RemoveObject(context.Background(), b.bucket, oldPath, s3.RemoveObjectOptions{}); err != nil {
return model.NewAppError("moveFile", "api.file.move_file.delete_from_s3.app_error", nil, err.Error(), http.StatusInternalServerError) return errors.Wrapf(err, "unable to remove the file old file %s", oldPath)
} }
return nil return nil
} }
func (b *S3FileBackend) WriteFile(fr io.Reader, path string) (int64, *model.AppError) { func (b *S3FileBackend) WriteFile(fr io.Reader, path string) (int64, error) {
var contentType string var contentType string
path = filepath.Join(b.pathPrefix, path) path = filepath.Join(b.pathPrefix, path)
if ext := filepath.Ext(path); model.IsFileExtImage(ext) { if ext := filepath.Ext(path); model.IsFileExtImage(ext) {
@@ -262,16 +261,16 @@ func (b *S3FileBackend) WriteFile(fr io.Reader, path string) (int64, *model.AppE
options := s3PutOptions(b.encrypt, contentType) options := s3PutOptions(b.encrypt, contentType)
info, err := b.client.PutObject(context.Background(), b.bucket, path, fr, -1, options) info, err := b.client.PutObject(context.Background(), b.bucket, path, fr, -1, options)
if err != nil { if err != nil {
return info.Size, model.NewAppError("WriteFile", "api.file.write_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return info.Size, errors.Wrapf(err, "unable write the data in the file %s", path)
} }
return info.Size, nil return info.Size, nil
} }
func (b *S3FileBackend) AppendFile(fr io.Reader, path string) (int64, *model.AppError) { func (b *S3FileBackend) AppendFile(fr io.Reader, path string) (int64, error) {
fp := filepath.Join(b.pathPrefix, path) fp := filepath.Join(b.pathPrefix, path)
if _, err := b.client.StatObject(context.Background(), b.bucket, fp, s3.StatObjectOptions{}); err != nil { if _, err := b.client.StatObject(context.Background(), b.bucket, fp, s3.StatObjectOptions{}); err != nil {
return 0, model.NewAppError("AppendFile", "api.file.append_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return 0, errors.Wrapf(err, "unable to find the file %s to append the data", path)
} }
var contentType string var contentType string
@@ -302,23 +301,18 @@ func (b *S3FileBackend) AppendFile(fr io.Reader, path string) (int64, *model.App
} }
_, err = b.client.ComposeObject(context.Background(), dstOpts, src1Opts, src2Opts) _, err = b.client.ComposeObject(context.Background(), dstOpts, src1Opts, src2Opts)
if err != nil { if err != nil {
return 0, model.NewAppError("AppendFile", "api.file.append_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return 0, errors.Wrapf(err, "unable append the data in the file %s", path)
} }
return info.Size, nil return info.Size, nil
} }
var errString string return 0, errors.Wrapf(err, "unable append the data in the file %s", path)
if err != nil {
errString = err.Error()
}
return 0, model.NewAppError("AppendFile", "api.file.append_file.s3.app_error", nil, errString, http.StatusInternalServerError)
} }
func (b *S3FileBackend) RemoveFile(path string) *model.AppError { func (b *S3FileBackend) RemoveFile(path string) error {
path = filepath.Join(b.pathPrefix, path) path = filepath.Join(b.pathPrefix, path)
if err := b.client.RemoveObject(context.Background(), b.bucket, path, s3.RemoveObjectOptions{}); err != nil { if err := b.client.RemoveObject(context.Background(), b.bucket, path, s3.RemoveObjectOptions{}); err != nil {
return model.NewAppError("RemoveFile", "utils.file.remove_file.s3.app_error", nil, err.Error(), http.StatusInternalServerError) return errors.Wrapf(err, "unable to remove the file %s", path)
} }
return nil return nil
@@ -344,9 +338,7 @@ func getPathsFromObjectInfos(in <-chan s3.ObjectInfo) <-chan s3.ObjectInfo {
return out return out
} }
func (b *S3FileBackend) ListDirectory(path string) (*[]string, *model.AppError) { func (b *S3FileBackend) ListDirectory(path string) (*[]string, error) {
var paths []string
path = filepath.Join(b.pathPrefix, path) path = filepath.Join(b.pathPrefix, path)
if !strings.HasSuffix(path, "/") && len(path) > 0 { if !strings.HasSuffix(path, "/") && len(path) > 0 {
// s3Clnt returns only the path itself when "/" is not present // s3Clnt returns only the path itself when "/" is not present
@@ -357,9 +349,10 @@ func (b *S3FileBackend) ListDirectory(path string) (*[]string, *model.AppError)
opts := s3.ListObjectsOptions{ opts := s3.ListObjectsOptions{
Prefix: path, Prefix: path,
} }
var paths []string
for object := range b.client.ListObjects(context.Background(), b.bucket, opts) { for object := range b.client.ListObjects(context.Background(), b.bucket, opts) {
if object.Err != nil { if object.Err != nil {
return nil, model.NewAppError("ListDirectory", "utils.file.list_directory.s3.app_error", nil, object.Err.Error(), http.StatusInternalServerError) return nil, errors.Wrapf(object.Err, "unable to list the directory %s", path)
} }
// We strip the path prefix that gets applied, // We strip the path prefix that gets applied,
// so that it remains transparent to the application. // so that it remains transparent to the application.
@@ -373,7 +366,7 @@ func (b *S3FileBackend) ListDirectory(path string) (*[]string, *model.AppError)
return &paths, nil return &paths, nil
} }
func (b *S3FileBackend) RemoveDirectory(path string) *model.AppError { func (b *S3FileBackend) RemoveDirectory(path string) error {
opts := s3.ListObjectsOptions{ opts := s3.ListObjectsOptions{
Prefix: filepath.Join(b.pathPrefix, path), Prefix: filepath.Join(b.pathPrefix, path),
Recursive: true, Recursive: true,
@@ -382,7 +375,7 @@ func (b *S3FileBackend) RemoveDirectory(path string) *model.AppError {
objectsCh := b.client.RemoveObjects(context.Background(), b.bucket, getPathsFromObjectInfos(list), s3.RemoveObjectsOptions{}) objectsCh := b.client.RemoveObjects(context.Background(), b.bucket, getPathsFromObjectInfos(list), s3.RemoveObjectsOptions{})
for err := range objectsCh { for err := range objectsCh {
if err.Err != nil { if err.Err != nil {
return model.NewAppError("RemoveDirectory", "utils.file.remove_directory.s3.app_error", nil, err.Err.Error(), http.StatusInternalServerError) return errors.Wrapf(err.Err, "unable to remove the directory %s", path)
} }
} }
@@ -402,9 +395,9 @@ func s3PutOptions(encrypted bool, contentType string) s3.PutObjectOptions {
return options return options
} }
func CheckMandatoryS3Fields(settings *model.FileSettings) *model.AppError { func CheckMandatoryS3Fields(settings *model.FileSettings) error {
if settings.AmazonS3Bucket == nil || len(*settings.AmazonS3Bucket) == 0 { if settings.AmazonS3Bucket == nil || len(*settings.AmazonS3Bucket) == 0 {
return model.NewAppError("S3File", "api.admin.test_s3.missing_s3_bucket", nil, "", http.StatusBadRequest) return errors.New("missing s3 bucket settings")
} }
// if S3 endpoint is not set call the set defaults to set that // if S3 endpoint is not set call the set defaults to set that

Просмотреть файл

@@ -15,7 +15,7 @@ func TestCheckMandatoryS3Fields(t *testing.T) {
err := CheckMandatoryS3Fields(&cfg) err := CheckMandatoryS3Fields(&cfg)
require.NotNil(t, err) require.NotNil(t, err)
require.Equal(t, err.Message, "api.admin.test_s3.missing_s3_bucket", "should've failed with missing s3 bucket") require.Equal(t, err.Error(), "missing s3 bucket settings", "should've failed with missing s3 bucket")
cfg.AmazonS3Bucket = model.NewString("test-mm") cfg.AmazonS3Bucket = model.NewString("test-mm")
err = CheckMandatoryS3Fields(&cfg) err = CheckMandatoryS3Fields(&cfg)

Просмотреть файл

@@ -298,9 +298,9 @@ func sendMailUsingConfigAdvanced(mail mailData, config *model.Config, enableComp
defer c.Quit() defer c.Quit()
defer c.Close() defer c.Close()
fileBackend, err := filesstore.NewFileBackend(&config.FileSettings, enableComplianceFeatures) fileBackend, nErr := filesstore.NewFileBackend(&config.FileSettings, enableComplianceFeatures)
if err != nil { if nErr != nil {
return err return model.NewAppError("sendMailUsingConfigAdvanced", "api.file.no_driver.app_error", nil, nErr.Error(), http.StatusInternalServerError)
} }
return SendMail(c, mail, fileBackend, time.Now()) return SendMail(c, mail, fileBackend, time.Now())
@@ -349,14 +349,14 @@ func SendMail(c smtpClient, mail mailData, fileBackend filesstore.FileBackend, d
} }
for _, fileInfo := range mail.attachments { for _, fileInfo := range mail.attachments {
bytes, err := fileBackend.ReadFile(fileInfo.Path) bytes, nErr := fileBackend.ReadFile(fileInfo.Path)
if err != nil { if nErr != nil {
return err return model.NewAppError("SendMail", "api.file.read_file.app_error", nil, nErr.Error(), http.StatusInternalServerError)
} }
m.Attach(fileInfo.Name, gomail.SetCopyFunc(func(writer io.Writer) error { m.Attach(fileInfo.Name, gomail.SetCopyFunc(func(writer io.Writer) error {
if _, err := writer.Write(bytes); err != nil { if _, nErr = writer.Write(bytes); nErr != nil {
return model.NewAppError("SendMail", "utils.mail.sendMail.attachments.write_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("SendMail", "utils.mail.sendMail.attachments.write_error", nil, nErr.Error(), http.StatusInternalServerError)
} }
return nil return nil
})) }))