From b118451f3de4d678e35d3d6c7f188439d3e0add0 Mon Sep 17 00:00:00 2001 From: Jason Blais Date: Wed, 21 Mar 2018 09:11:51 -0400 Subject: Update plugin.go (#8486) --- app/plugin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/plugin.go b/app/plugin.go index 6702e9227..903f4b767 100644 --- a/app/plugin.go +++ b/app/plugin.go @@ -401,7 +401,7 @@ func (a *App) InitPlugins(pluginPath, webappPath string, supervisorOverride plug options = append(options, pluginenv.SupervisorProvider(supervisorOverride)) } else if err := sandbox.CheckSupport(); err != nil { l4g.Warn(err.Error()) - l4g.Warn("plugin sandboxing is not supported. plugins will run with the same access level as the server") + l4g.Warn("plugin sandboxing is not supported. plugins will run with the same access level as the server. See documentation to learn more: https://developers.mattermost.com/extend/plugins/security/") options = append(options, pluginenv.SupervisorProvider(rpcplugin.SupervisorProvider)) } else { options = append(options, pluginenv.SupervisorProvider(sandbox.SupervisorProvider)) -- cgit v1.2.3-1-g7c22 From 6ef6c6996842be5d408a4f9d6fcdabc323bf31c9 Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Wed, 21 Mar 2018 09:13:20 -0400 Subject: Fixed missing error in log message (#8485) --- app/session.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/session.go b/app/session.go index 88f52477f..c9208f2b2 100644 --- a/app/session.go +++ b/app/session.go @@ -225,7 +225,7 @@ func (a *App) UpdateLastActivityAtIfNeeded(session model.Session) { } if result := <-a.Srv.Store.Session().UpdateLastActivityAt(session.Id, now); result.Err != nil { - l4g.Error(utils.T("api.status.last_activity.error"), session.UserId, session.Id) + l4g.Error(utils.T("api.status.last_activity.error"), session.UserId, session.Id, result.Err) } session.LastActivityAt = now -- cgit v1.2.3-1-g7c22 From 9d701c704416a1d8648dd2818a8a15c4da99b424 Mon Sep 17 00:00:00 2001 From: Jesse Hallam Date: Wed, 21 Mar 2018 14:27:14 -0400 Subject: Fix various segfaults when running `go test` manually (#8448) * failing to find i18n shouldn't segfault The server was trying to handle the fact that it couldn't find the i18n directory, by emitting a translated log message... * fix utils.FindDir The attempts to find the directory in the parent or grandparent directory don't work if the current working directory was inside `enterprise`, with `enterprise` itself being a symlink as per the usual developer setup. Recurse to the root of the filesystem, cleaning the path along the way to work around this limitation (and allow tests to be run from an arbitrarily deep nesting level.) Fix corresponding usages to employ filepath.Join. * failing to find html templates shouldn't segfault * fail fast if the test user cannot be created * rework utils.FindDir to retain backwards compatibility --- app/app.go | 6 +++++- app/auto_posts.go | 3 ++- app/import_test.go | 7 ++++--- app/saml.go | 3 +-- app/user.go | 3 ++- 5 files changed, 14 insertions(+), 8 deletions(-) (limited to 'app') diff --git a/app/app.go b/app/app.go index f5e5dd21e..48e95fb99 100644 --- a/app/app.go +++ b/app/app.go @@ -439,7 +439,11 @@ func (a *App) WaitForGoroutines() { } func (a *App) HTMLTemplates() *template.Template { - return a.htmlTemplateWatcher.Templates() + if a.htmlTemplateWatcher != nil { + return a.htmlTemplateWatcher.Templates() + } + + return nil } func (a *App) HTTPClient(trustURLs bool) *http.Client { diff --git a/app/auto_posts.go b/app/auto_posts.go index 379c74ab7..a2adb9d6c 100644 --- a/app/auto_posts.go +++ b/app/auto_posts.go @@ -7,6 +7,7 @@ import ( "bytes" "io" "os" + "path/filepath" "github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/utils" @@ -43,7 +44,7 @@ func (cfg *AutoPostCreator) UploadTestFile() ([]string, bool) { filename := cfg.ImageFilenames[utils.RandIntFromRange(utils.Range{Begin: 0, End: len(cfg.ImageFilenames) - 1})] path, _ := utils.FindDir("web/static/images") - file, err := os.Open(path + "/" + filename) + file, err := os.Open(filepath.Join(path, filename)) if err != nil { return nil, false } diff --git a/app/import_test.go b/app/import_test.go index 6a284f63d..f294c8731 100644 --- a/app/import_test.go +++ b/app/import_test.go @@ -4,6 +4,7 @@ package app import ( + "path/filepath" "runtime/debug" "strings" "testing" @@ -370,7 +371,7 @@ func TestImportValidateUserImportData(t *testing.T) { // Test a valid User with all fields populated. testsDir, _ := utils.FindDir("tests") data = UserImportData{ - ProfileImage: ptrStr(testsDir + "test.png"), + ProfileImage: ptrStr(filepath.Join(testsDir, "test.png")), Username: ptrStr("bob"), Email: ptrStr("bob@example.com"), AuthService: ptrStr("ldap"), @@ -1487,7 +1488,7 @@ func TestImportImportUser(t *testing.T) { username := model.NewId() testsDir, _ := utils.FindDir("tests") data = UserImportData{ - ProfileImage: ptrStr(testsDir + "test.png"), + ProfileImage: ptrStr(filepath.Join(testsDir, "test.png")), Username: &username, Email: ptrStr(model.NewId() + "@example.com"), Nickname: ptrStr(model.NewId()), @@ -1543,7 +1544,7 @@ func TestImportImportUser(t *testing.T) { // Alter all the fields of that user. data.Email = ptrStr(model.NewId() + "@example.com") - data.ProfileImage = ptrStr(testsDir + "testgif.gif") + data.ProfileImage = ptrStr(filepath.Join(testsDir, "testgif.gif")) data.AuthService = ptrStr("ldap") data.AuthData = &username data.Nickname = ptrStr(model.NewId()) diff --git a/app/saml.go b/app/saml.go index bd9f647a1..29d5f8772 100644 --- a/app/saml.go +++ b/app/saml.go @@ -8,7 +8,6 @@ import ( "mime/multipart" "net/http" "os" - "path/filepath" "github.com/mattermost/mattermost-server/model" @@ -42,7 +41,7 @@ func WriteSamlFile(fileData *multipart.FileHeader) *model.AppError { defer file.Close() configDir, _ := utils.FindDir("config") - out, err := os.Create(configDir + filename) + out, err := os.Create(filepath.Join(configDir, filename)) if err != nil { return model.NewAppError("AddSamlCertificate", "api.admin.add_certificate.saving.app_error", nil, err.Error(), http.StatusInternalServerError) } diff --git a/app/user.go b/app/user.go index 7a6dc0b49..8f393038a 100644 --- a/app/user.go +++ b/app/user.go @@ -18,6 +18,7 @@ import ( "io/ioutil" "mime/multipart" "net/http" + "path/filepath" "strconv" "strings" @@ -717,7 +718,7 @@ func CreateProfileImage(username string, userId string, initialFont string) ([]b initial := string(strings.ToUpper(username)[0]) fontDir, _ := utils.FindDir("fonts") - fontBytes, err := ioutil.ReadFile(fontDir + initialFont) + fontBytes, err := ioutil.ReadFile(filepath.Join(fontDir, initialFont)) if err != nil { return nil, model.NewAppError("CreateProfileImage", "api.user.create_profile_image.default_font.app_error", nil, err.Error(), http.StatusInternalServerError) } -- cgit v1.2.3-1-g7c22 From 74e703f58daff2aded07a969410f988cff9ada9b Mon Sep 17 00:00:00 2001 From: Chris Duarte Date: Thu, 22 Mar 2018 06:53:43 -0700 Subject: Timezone feature (#8185) * Add supported timezones into config Remove Timezone list creation in favor of timezone from configs Add Timezone field to Users table Clean up format of SupportedTimezones in config * Remove unwanted change * Add test for updating user timezone * Add empty map[string]string if Timezone is null * Add EnableTimezoneSelection config * Revert back to map[string]string for ClientConfig * Refactor SupportedTimezones into timezones.json * Include timezones.json in TestConfigFlag * Add timezone api endpoint * Bump varchar size to 256 and setMaxSize in user_store * Refactor LoadConfig to LoadConfig and LoadTimezoneConfig * Remove unnecessary argument in LoadConfig, mail_test * Add test for timezone endpoint * Add license header * Refactor timezones endpoint to system.go * Add system base route to timezone endpoint * db timezone upgrade in db v4.9 * Avoid saving SupportedTimezones to config.json * Add timezonePath support in config * Remove EnableTimezoneSelection from config * Use return statement without return parameter * Refactor test for SupportedTimezones * Check for supportedTimezone != nil instead of using len * Decouple SupportedTimezones out of Config * Fix failing test * Add LastTeamIconUpdate back in upgrade.go * Write timezone config in config_flag_test * Add code fallback for default timezone support --- app/app.go | 5 +++++ app/timezone.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 app/timezone.go (limited to 'app') diff --git a/app/app.go b/app/app.go index 48e95fb99..6329a80d3 100644 --- a/app/app.go +++ b/app/app.go @@ -63,6 +63,8 @@ type App struct { clientLicenseValue atomic.Value licenseListeners map[string]func() + timezones atomic.Value + siteURL string newStore func() store.Store @@ -125,6 +127,9 @@ func New(options ...Option) (outApp *App, outErr error) { return nil, err } app.EnableConfigWatch() + + app.LoadTimezones() + if err := utils.InitTranslations(app.Config().LocalizationSettings); err != nil { return nil, errors.Wrapf(err, "unable to load Mattermost translation files") } diff --git a/app/timezone.go b/app/timezone.go new file mode 100644 index 000000000..84d912da6 --- /dev/null +++ b/app/timezone.go @@ -0,0 +1,28 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package app + +import ( + "github.com/mattermost/mattermost-server/model" + "github.com/mattermost/mattermost-server/utils" +) + +func (a *App) Timezones() model.SupportedTimezones { + if cfg := a.timezones.Load(); cfg != nil { + return cfg.(model.SupportedTimezones) + } + return model.SupportedTimezones{} +} + +func (a *App) LoadTimezones() { + timezonePath := "timezones.json" + + if a.Config().TimezoneSettings.SupportedTimezonesPath != nil && len(*a.Config().TimezoneSettings.SupportedTimezonesPath) > 0 { + timezonePath = *a.Config().TimezoneSettings.SupportedTimezonesPath + } + + timezoneCfg := utils.LoadTimezones(timezonePath) + + a.timezones.Store(timezoneCfg) +} -- cgit v1.2.3-1-g7c22 From 87762ae62eb887dfb3fd0957040919aede46f7d4 Mon Sep 17 00:00:00 2001 From: Jesse Hallam Date: Thu, 22 Mar 2018 15:33:02 -0400 Subject: Improved bulkload error handling (#8491) * log the config file path used by the server on startup * return an err if the bulk import command fails * log the underlying errors that occur when importing The code assumed all errors meant a missing resource, but it's possible something else is at fault. Including the error helps pinpoint that more readily. --- app/config.go | 1 + app/import.go | 36 ++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 18 deletions(-) (limited to 'app') diff --git a/app/config.go b/app/config.go index 460d580d8..ccd7236a0 100644 --- a/app/config.go +++ b/app/config.go @@ -54,6 +54,7 @@ func (a *App) LoadConfig(configFile string) *model.AppError { a.configFile = configPath utils.ConfigureLog(&cfg.LogSettings) + l4g.Info("Using config file at %s", configPath) a.config.Store(cfg) diff --git a/app/import.go b/app/import.go index 5a3158fab..e2e3aa1b7 100644 --- a/app/import.go +++ b/app/import.go @@ -399,7 +399,7 @@ func (a *App) ImportChannel(data *ChannelImportData, dryRun bool) *model.AppErro var team *model.Team if result := <-a.Srv.Store.Team().GetByName(*data.Team); result.Err != nil { - return model.NewAppError("BulkImport", "app.import.import_channel.team_not_found.error", map[string]interface{}{"TeamName": *data.Team}, "", http.StatusBadRequest) + return model.NewAppError("BulkImport", "app.import.import_channel.team_not_found.error", map[string]interface{}{"TeamName": *data.Team}, result.Err.Error(), http.StatusBadRequest) } else { team = result.Data.(*model.Team) } @@ -781,7 +781,7 @@ func (a *App) ImportUser(data *UserImportData, dryRun bool) *model.AppError { if len(preferences) > 0 { if result := <-a.Srv.Store.Preference().Save(&preferences); result.Err != nil { - return model.NewAppError("BulkImport", "app.import.import_user.save_preferences.error", nil, "", http.StatusInternalServerError) + return model.NewAppError("BulkImport", "app.import.import_user.save_preferences.error", nil, result.Err.Error(), http.StatusInternalServerError) } } @@ -899,7 +899,7 @@ func (a *App) ImportUserChannels(user *model.User, team *model.Team, teamMember if len(preferences) > 0 { if result := <-a.Srv.Store.Preference().Save(&preferences); result.Err != nil { - return model.NewAppError("BulkImport", "app.import.import_user_channels.save_preferences.error", nil, "", http.StatusInternalServerError) + return model.NewAppError("BulkImport", "app.import.import_user_channels.save_preferences.error", nil, result.Err.Error(), http.StatusInternalServerError) } } @@ -1069,7 +1069,7 @@ func (a *App) ImportReaction(data *ReactionImportData, post *model.Post, dryRun var user *model.User if result := <-a.Srv.Store.User().GetByUsername(*data.User); result.Err != nil { - return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": data.User}, "", http.StatusBadRequest) + return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": data.User}, result.Err.Error(), http.StatusBadRequest) } else { user = result.Data.(*model.User) } @@ -1092,7 +1092,7 @@ func (a *App) ImportReply(data *ReplyImportData, post *model.Post, dryRun bool) var user *model.User if result := <-a.Srv.Store.User().GetByUsername(*data.User); result.Err != nil { - return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": data.User}, "", http.StatusBadRequest) + return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": data.User}, result.Err.Error(), http.StatusBadRequest) } else { user = result.Data.(*model.User) } @@ -1147,21 +1147,21 @@ func (a *App) ImportPost(data *PostImportData, dryRun bool) *model.AppError { var team *model.Team if result := <-a.Srv.Store.Team().GetByName(*data.Team); result.Err != nil { - return model.NewAppError("BulkImport", "app.import.import_post.team_not_found.error", map[string]interface{}{"TeamName": *data.Team}, "", http.StatusBadRequest) + return model.NewAppError("BulkImport", "app.import.import_post.team_not_found.error", map[string]interface{}{"TeamName": *data.Team}, result.Err.Error(), http.StatusBadRequest) } else { team = result.Data.(*model.Team) } var channel *model.Channel if result := <-a.Srv.Store.Channel().GetByName(team.Id, *data.Channel, false); result.Err != nil { - return model.NewAppError("BulkImport", "app.import.import_post.channel_not_found.error", map[string]interface{}{"ChannelName": *data.Channel}, "", http.StatusBadRequest) + return model.NewAppError("BulkImport", "app.import.import_post.channel_not_found.error", map[string]interface{}{"ChannelName": *data.Channel}, result.Err.Error(), http.StatusBadRequest) } else { channel = result.Data.(*model.Channel) } var user *model.User if result := <-a.Srv.Store.User().GetByUsername(*data.User); result.Err != nil { - return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": *data.User}, "", http.StatusBadRequest) + return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": *data.User}, result.Err.Error(), http.StatusBadRequest) } else { user = result.Data.(*model.User) } @@ -1210,7 +1210,7 @@ func (a *App) ImportPost(data *PostImportData, dryRun bool) *model.AppError { var user *model.User if result := <-a.Srv.Store.User().GetByUsername(username); result.Err != nil { - return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": username}, "", http.StatusBadRequest) + return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": username}, result.Err.Error(), http.StatusBadRequest) } else { user = result.Data.(*model.User) } @@ -1225,7 +1225,7 @@ func (a *App) ImportPost(data *PostImportData, dryRun bool) *model.AppError { if len(preferences) > 0 { if result := <-a.Srv.Store.Preference().Save(&preferences); result.Err != nil { - return model.NewAppError("BulkImport", "app.import.import_post.save_preferences.error", nil, "", http.StatusInternalServerError) + return model.NewAppError("BulkImport", "app.import.import_post.save_preferences.error", nil, result.Err.Error(), http.StatusInternalServerError) } } } @@ -1351,7 +1351,7 @@ func (a *App) ImportDirectChannel(data *DirectChannelImportData, dryRun bool) *m userIds = append(userIds, user.Id) userMap[username] = user.Id } else { - return model.NewAppError("BulkImport", "app.import.import_direct_channel.member_not_found.error", nil, "", http.StatusBadRequest) + return model.NewAppError("BulkImport", "app.import.import_direct_channel.member_not_found.error", nil, result.Err.Error(), http.StatusBadRequest) } } @@ -1360,14 +1360,14 @@ func (a *App) ImportDirectChannel(data *DirectChannelImportData, dryRun bool) *m if len(userIds) == 2 { ch, err := a.createDirectChannel(userIds[0], userIds[1]) if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR { - return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_direct_channel.error", nil, "", http.StatusBadRequest) + return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_direct_channel.error", nil, err.Error(), http.StatusBadRequest) } else { channel = ch } } else { ch, err := a.createGroupChannel(userIds, userIds[0]) if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR { - return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_group_channel.error", nil, "", http.StatusBadRequest) + return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_group_channel.error", nil, err.Error(), http.StatusBadRequest) } else { channel = ch } @@ -1403,7 +1403,7 @@ func (a *App) ImportDirectChannel(data *DirectChannelImportData, dryRun bool) *m if data.Header != nil { channel.Header = *data.Header if result := <-a.Srv.Store.Channel().Update(channel); result.Err != nil { - return model.NewAppError("BulkImport", "app.import.import_direct_channel.update_header_failed.error", nil, "", http.StatusBadRequest) + return model.NewAppError("BulkImport", "app.import.import_direct_channel.update_header_failed.error", nil, result.Err.Error(), http.StatusBadRequest) } } @@ -1461,7 +1461,7 @@ func (a *App) ImportDirectPost(data *DirectPostImportData, dryRun bool) *model.A user := result.Data.(*model.User) userIds = append(userIds, user.Id) } else { - return model.NewAppError("BulkImport", "app.import.import_direct_post.channel_member_not_found.error", nil, "", http.StatusBadRequest) + return model.NewAppError("BulkImport", "app.import.import_direct_post.channel_member_not_found.error", nil, result.Err.Error(), http.StatusBadRequest) } } @@ -1469,14 +1469,14 @@ func (a *App) ImportDirectPost(data *DirectPostImportData, dryRun bool) *model.A if len(userIds) == 2 { ch, err := a.createDirectChannel(userIds[0], userIds[1]) if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR { - return model.NewAppError("BulkImport", "app.import.import_direct_post.create_direct_channel.error", nil, "", http.StatusBadRequest) + return model.NewAppError("BulkImport", "app.import.import_direct_post.create_direct_channel.error", nil, err.Error(), http.StatusBadRequest) } else { channel = ch } } else { ch, err := a.createGroupChannel(userIds, userIds[0]) if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR { - return model.NewAppError("BulkImport", "app.import.import_direct_post.create_group_channel.error", nil, "", http.StatusBadRequest) + return model.NewAppError("BulkImport", "app.import.import_direct_post.create_group_channel.error", nil, err.Error(), http.StatusBadRequest) } else { channel = ch } @@ -1548,7 +1548,7 @@ func (a *App) ImportDirectPost(data *DirectPostImportData, dryRun bool) *model.A if len(preferences) > 0 { if result := <-a.Srv.Store.Preference().Save(&preferences); result.Err != nil { - return model.NewAppError("BulkImport", "app.import.import_direct_post.save_preferences.error", nil, "", http.StatusInternalServerError) + return model.NewAppError("BulkImport", "app.import.import_direct_post.save_preferences.error", nil, result.Err.Error(), http.StatusInternalServerError) } } } -- cgit v1.2.3-1-g7c22