From 1ec295f88ca99e9423ffd91019cecf802ae3dc77 Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 6 Feb 2018 17:25:49 -0600 Subject: add App.License, remove utils.IsLicensed / utils.License calls (#8203) --- app/authentication.go | 7 ++++--- app/cluster_discovery.go | 3 +-- app/compliance.go | 7 +++---- app/config.go | 8 ++++++++ app/diagnostics.go | 17 ++++++++--------- app/email_batching.go | 2 +- app/ldap.go | 9 +++++---- app/license_test.go | 4 +--- app/notification.go | 4 ++-- app/oauth.go | 4 ++-- app/post.go | 8 ++++---- app/session.go | 3 ++- app/user.go | 3 ++- app/web_conn.go | 2 +- app/webhook.go | 2 +- 15 files changed, 45 insertions(+), 38 deletions(-) (limited to 'app') diff --git a/app/authentication.go b/app/authentication.go index 0b3659449..5c91f8038 100644 --- a/app/authentication.go +++ b/app/authentication.go @@ -36,7 +36,7 @@ func (tl TokenLocation) String() string { } func (a *App) IsPasswordValid(password string) *model.AppError { - if utils.IsLicensed() && *utils.License().Features.PasswordRequirements { + if license := a.License(); license != nil && *license.Features.PasswordRequirements { return utils.IsPasswordValidWithSettings(password, &a.Config().PasswordSettings) } return utils.IsPasswordValid(password) @@ -150,7 +150,7 @@ func (a *App) CheckUserPostflightAuthenticationCriteria(user *model.User) *model } func (a *App) CheckUserMfa(user *model.User, token string) *model.AppError { - if !user.MfaActive || !utils.IsLicensed() || !*utils.License().Features.MFA || !*a.Config().ServiceSettings.EnableMultifactorAuthentication { + if license := a.License(); !user.MfaActive || license == nil || !*license.Features.MFA || !*a.Config().ServiceSettings.EnableMultifactorAuthentication { return nil } @@ -183,7 +183,8 @@ func checkUserNotDisabled(user *model.User) *model.AppError { } func (a *App) authenticateUser(user *model.User, password, mfaToken string) (*model.User, *model.AppError) { - ldapAvailable := *a.Config().LdapSettings.Enable && a.Ldap != nil && utils.IsLicensed() && *utils.License().Features.LDAP + license := a.License() + ldapAvailable := *a.Config().LdapSettings.Enable && a.Ldap != nil && license != nil && *license.Features.LDAP if user.AuthService == model.USER_AUTH_SERVICE_LDAP { if !ldapAvailable { diff --git a/app/cluster_discovery.go b/app/cluster_discovery.go index 6418ab2be..2682425f5 100644 --- a/app/cluster_discovery.go +++ b/app/cluster_discovery.go @@ -9,7 +9,6 @@ import ( l4g "github.com/alecthomas/log4go" "github.com/mattermost/mattermost-server/model" - "github.com/mattermost/mattermost-server/utils" ) const ( @@ -80,7 +79,7 @@ func (me *ClusterDiscoveryService) Stop() { } func (a *App) IsLeader() bool { - if utils.IsLicensed() && *a.Config().ClusterSettings.Enable && a.Cluster != nil { + if a.License() != nil && *a.Config().ClusterSettings.Enable && a.Cluster != nil { return a.Cluster.IsLeader() } else { return true diff --git a/app/compliance.go b/app/compliance.go index 2a1b86a6b..5c62a49d9 100644 --- a/app/compliance.go +++ b/app/compliance.go @@ -9,11 +9,10 @@ import ( "net/http" "github.com/mattermost/mattermost-server/model" - "github.com/mattermost/mattermost-server/utils" ) func (a *App) GetComplianceReports(page, perPage int) (model.Compliances, *model.AppError) { - if !*a.Config().ComplianceSettings.Enable || !utils.IsLicensed() || !*utils.License().Features.Compliance { + if license := a.License(); !*a.Config().ComplianceSettings.Enable || license == nil || !*license.Features.Compliance { return nil, model.NewAppError("GetComplianceReports", "ent.compliance.licence_disable.app_error", nil, "", http.StatusNotImplemented) } @@ -25,7 +24,7 @@ func (a *App) GetComplianceReports(page, perPage int) (model.Compliances, *model } func (a *App) SaveComplianceReport(job *model.Compliance) (*model.Compliance, *model.AppError) { - if !*a.Config().ComplianceSettings.Enable || !utils.IsLicensed() || !*utils.License().Features.Compliance || a.Compliance == nil { + if license := a.License(); !*a.Config().ComplianceSettings.Enable || license == nil || !*license.Features.Compliance || a.Compliance == nil { return nil, model.NewAppError("saveComplianceReport", "ent.compliance.licence_disable.app_error", nil, "", http.StatusNotImplemented) } @@ -44,7 +43,7 @@ func (a *App) SaveComplianceReport(job *model.Compliance) (*model.Compliance, *m } func (a *App) GetComplianceReport(reportId string) (*model.Compliance, *model.AppError) { - if !*a.Config().ComplianceSettings.Enable || !utils.IsLicensed() || !*utils.License().Features.Compliance || a.Compliance == nil { + if license := a.License(); !*a.Config().ComplianceSettings.Enable || license == nil || !*license.Features.Compliance || a.Compliance == nil { return nil, model.NewAppError("downloadComplianceReport", "ent.compliance.licence_disable.app_error", nil, "", http.StatusNotImplemented) } diff --git a/app/config.go b/app/config.go index 526d47a77..a2398f9e9 100644 --- a/app/config.go +++ b/app/config.go @@ -166,3 +166,11 @@ func (a *App) Desanitize(cfg *model.Config) { cfg.SqlSettings.DataSourceSearchReplicas[i] = actual.SqlSettings.DataSourceSearchReplicas[i] } } + +// License returns the currently active license or nil if the application is unlicensed. +func (a *App) License() *model.License { + if utils.IsLicensed() { + return utils.License() + } + return nil +} diff --git a/app/diagnostics.go b/app/diagnostics.go index c74224f19..809d9ff1e 100644 --- a/app/diagnostics.go +++ b/app/diagnostics.go @@ -11,7 +11,6 @@ import ( "sync/atomic" "github.com/mattermost/mattermost-server/model" - "github.com/mattermost/mattermost-server/utils" "github.com/segmentio/analytics-go" ) @@ -509,17 +508,17 @@ func (a *App) trackConfig() { } func (a *App) trackLicense() { - if utils.IsLicensed() { + if license := a.License(); license != nil { data := map[string]interface{}{ - "customer_id": utils.License().Customer.Id, - "license_id": utils.License().Id, - "issued": utils.License().IssuedAt, - "start": utils.License().StartsAt, - "expire": utils.License().ExpiresAt, - "users": *utils.License().Features.Users, + "customer_id": license.Customer.Id, + "license_id": license.Id, + "issued": license.IssuedAt, + "start": license.StartsAt, + "expire": license.ExpiresAt, + "users": *license.Features.Users, } - features := utils.License().Features.ToMap() + features := license.Features.ToMap() for featureName, featureValue := range features { data["feature_"+featureName] = featureValue } diff --git a/app/email_batching.go b/app/email_batching.go index 70fd7eb40..2a33d7d3e 100644 --- a/app/email_batching.go +++ b/app/email_batching.go @@ -220,7 +220,7 @@ func (a *App) sendBatchedEmailNotification(userId string, notifications []*batch } emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - if utils.IsLicensed() && *utils.License().Features.EmailNotificationContents { + if license := a.License(); license != nil && *license.Features.EmailNotificationContents { emailNotificationContentsType = *a.Config().EmailSettings.EmailNotificationContentsType } diff --git a/app/ldap.go b/app/ldap.go index 49f3d034a..179529c52 100644 --- a/app/ldap.go +++ b/app/ldap.go @@ -14,7 +14,7 @@ import ( func (a *App) SyncLdap() { a.Go(func() { - if utils.IsLicensed() && *utils.License().Features.LDAP && *a.Config().LdapSettings.EnableSync { + if license := a.License(); license != nil && *license.Features.LDAP && *a.Config().LdapSettings.EnableSync { if ldapI := a.Ldap; ldapI != nil { ldapI.StartSynchronizeJob(false) } else { @@ -25,7 +25,8 @@ func (a *App) SyncLdap() { } func (a *App) TestLdap() *model.AppError { - if ldapI := a.Ldap; ldapI != nil && utils.IsLicensed() && *utils.License().Features.LDAP && (*a.Config().LdapSettings.Enable || *a.Config().LdapSettings.EnableSync) { + license := a.License() + if ldapI := a.Ldap; ldapI != nil && license != nil && *license.Features.LDAP && (*a.Config().LdapSettings.Enable || *a.Config().LdapSettings.EnableSync) { if err := ldapI.RunTest(); err != nil { err.StatusCode = 500 return err @@ -39,7 +40,7 @@ func (a *App) TestLdap() *model.AppError { } func (a *App) SwitchEmailToLdap(email, password, code, ldapId, ldapPassword string) (string, *model.AppError) { - if utils.IsLicensed() && !*a.Config().ServiceSettings.ExperimentalEnableAuthenticationTransfer { + if a.License() != nil && !*a.Config().ServiceSettings.ExperimentalEnableAuthenticationTransfer { return "", model.NewAppError("emailToLdap", "api.user.email_to_ldap.not_available.app_error", nil, "", http.StatusForbidden) } @@ -75,7 +76,7 @@ func (a *App) SwitchEmailToLdap(email, password, code, ldapId, ldapPassword stri } func (a *App) SwitchLdapToEmail(ldapPassword, code, email, newPassword string) (string, *model.AppError) { - if utils.IsLicensed() && !*a.Config().ServiceSettings.ExperimentalEnableAuthenticationTransfer { + if a.License() != nil && !*a.Config().ServiceSettings.ExperimentalEnableAuthenticationTransfer { return "", model.NewAppError("ldapToEmail", "api.user.ldap_to_email.not_available.app_error", nil, "", http.StatusForbidden) } diff --git a/app/license_test.go b/app/license_test.go index 632034b11..5b73d9d18 100644 --- a/app/license_test.go +++ b/app/license_test.go @@ -6,8 +6,6 @@ package app import ( //"github.com/mattermost/mattermost-server/model" "testing" - - "github.com/mattermost/mattermost-server/utils" ) func TestLoadLicense(t *testing.T) { @@ -15,7 +13,7 @@ func TestLoadLicense(t *testing.T) { defer th.TearDown() th.App.LoadLicense() - if utils.IsLicensed() { + if th.App.License() != nil { t.Fatal("shouldn't have a valid license") } } diff --git a/app/notification.go b/app/notification.go index 19f7894c5..1318308f8 100644 --- a/app/notification.go +++ b/app/notification.go @@ -233,7 +233,7 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod sendPushNotifications := false if *a.Config().EmailSettings.SendPushNotifications { pushServer := *a.Config().EmailSettings.PushNotificationServer - if pushServer == model.MHPNS && (!utils.IsLicensed() || !*utils.License().Features.MHPNS) { + if license := a.License(); pushServer == model.MHPNS && (license == nil || !*license.Features.MHPNS) { l4g.Warn(utils.T("api.post.send_notifications_and_forget.push_notification.mhpnsWarn")) sendPushNotifications = false } else { @@ -358,7 +358,7 @@ func (a *App) sendNotificationEmail(post *model.Post, user *model.User, channel } emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL - if utils.IsLicensed() && *utils.License().Features.EmailNotificationContents { + if license := a.License(); license != nil && *license.Features.EmailNotificationContents { emailNotificationContentsType = *a.Config().EmailSettings.EmailNotificationContentsType } diff --git a/app/oauth.go b/app/oauth.go index 1cce5a3a0..5a66f542e 100644 --- a/app/oauth.go +++ b/app/oauth.go @@ -717,7 +717,7 @@ func (a *App) AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service } func (a *App) SwitchEmailToOAuth(w http.ResponseWriter, r *http.Request, email, password, code, service string) (string, *model.AppError) { - if utils.IsLicensed() && !*a.Config().ServiceSettings.ExperimentalEnableAuthenticationTransfer { + if a.License() != nil && !*a.Config().ServiceSettings.ExperimentalEnableAuthenticationTransfer { return "", model.NewAppError("emailToOAuth", "api.user.email_to_oauth.not_available.app_error", nil, "", http.StatusForbidden) } @@ -747,7 +747,7 @@ func (a *App) SwitchEmailToOAuth(w http.ResponseWriter, r *http.Request, email, } func (a *App) SwitchOAuthToEmail(email, password, requesterId string) (string, *model.AppError) { - if utils.IsLicensed() && !*a.Config().ServiceSettings.ExperimentalEnableAuthenticationTransfer { + if a.License() != nil && !*a.Config().ServiceSettings.ExperimentalEnableAuthenticationTransfer { return "", model.NewAppError("oauthToEmail", "api.user.oauth_to_email.not_available.app_error", nil, "", http.StatusForbidden) } diff --git a/app/post.go b/app/post.go index 6890d1dd9..005624605 100644 --- a/app/post.go +++ b/app/post.go @@ -124,7 +124,7 @@ func (a *App) CreatePost(post *model.Post, channel *model.Channel, triggerWebhoo user = result.Data.(*model.User) } - if utils.IsLicensed() && *a.Config().TeamSettings.ExperimentalTownSquareIsReadOnly && + if a.License() != nil && *a.Config().TeamSettings.ExperimentalTownSquareIsReadOnly && !post.IsSystemMessage() && channel.Name == model.DEFAULT_CHANNEL && !a.CheckIfRolesGrantPermission(user.GetRoles(), model.PERMISSION_MANAGE_SYSTEM.Id) { @@ -332,7 +332,7 @@ func (a *App) UpdatePost(post *model.Post, safeUpdate bool) (*model.Post, *model } else { oldPost = result.Data.(*model.PostList).Posts[post.Id] - if utils.IsLicensed() { + if a.License() != nil { if *a.Config().ServiceSettings.AllowEditPost == model.ALLOW_EDIT_POST_NEVER && post.Message != oldPost.Message { err := model.NewAppError("UpdatePost", "api.post.update_post.permissions_denied.app_error", nil, "", http.StatusForbidden) return nil, err @@ -354,7 +354,7 @@ func (a *App) UpdatePost(post *model.Post, safeUpdate bool) (*model.Post, *model return nil, err } - if utils.IsLicensed() { + if a.License() != nil { if *a.Config().ServiceSettings.AllowEditPost == model.ALLOW_EDIT_POST_TIME_LIMIT && model.GetMillis() > oldPost.CreateAt+int64(*a.Config().ServiceSettings.PostEditTimeLimit*1000) && post.Message != oldPost.Message { err := model.NewAppError("UpdatePost", "api.post.update_post.permissions_time_limit.app_error", map[string]interface{}{"timeLimit": *a.Config().ServiceSettings.PostEditTimeLimit}, "", http.StatusBadRequest) return nil, err @@ -613,7 +613,7 @@ func (a *App) SearchPostsInTeam(terms string, userId string, teamId string, isOr paramsList := model.ParseSearchParams(terms) esInterface := a.Elasticsearch - if esInterface != nil && *a.Config().ElasticsearchSettings.EnableSearching && utils.IsLicensed() && *utils.License().Features.Elasticsearch { + if license := a.License(); esInterface != nil && *a.Config().ElasticsearchSettings.EnableSearching && license != nil && *license.Features.Elasticsearch { finalParamsList := []*model.SearchParams{} for _, params := range paramsList { diff --git a/app/session.go b/app/session.go index 1c5daf29e..459618439 100644 --- a/app/session.go +++ b/app/session.go @@ -69,8 +69,9 @@ func (a *App) GetSession(token string) (*model.Session, *model.AppError) { return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token}, "", http.StatusUnauthorized) } + license := a.License() if *a.Config().ServiceSettings.SessionIdleTimeoutInMinutes > 0 && - utils.IsLicensed() && *utils.License().Features.Compliance && + license != nil && *license.Features.Compliance && session != nil && !session.IsOAuth && !session.IsMobileApp() && session.Props[model.SESSION_PROP_TYPE] != model.SESSION_TYPE_USER_ACCESS_TOKEN { diff --git a/app/user.go b/app/user.go index 64e49e293..69c6d072b 100644 --- a/app/user.go +++ b/app/user.go @@ -374,7 +374,8 @@ func (a *App) GetUserByAuth(authData *string, authService string) (*model.User, } func (a *App) GetUserForLogin(loginId string, onlyLdap bool) (*model.User, *model.AppError) { - ldapAvailable := *a.Config().LdapSettings.Enable && a.Ldap != nil && utils.IsLicensed() && *utils.License().Features.LDAP + license := a.License() + ldapAvailable := *a.Config().LdapSettings.Enable && a.Ldap != nil && license != nil && *license.Features.LDAP if result := <-a.Srv.Store.User().GetForLogin( loginId, diff --git a/app/web_conn.go b/app/web_conn.go index e625e61b5..33c285af3 100644 --- a/app/web_conn.go +++ b/app/web_conn.go @@ -277,7 +277,7 @@ func (webCon *WebConn) IsAuthenticated() bool { func (webCon *WebConn) SendHello() { msg := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_HELLO, "", "", webCon.UserId, nil) - msg.Add("server_version", fmt.Sprintf("%v.%v.%v.%v", model.CurrentVersion, model.BuildNumber, webCon.App.ClientConfigHash(), utils.IsLicensed())) + msg.Add("server_version", fmt.Sprintf("%v.%v.%v.%v", model.CurrentVersion, model.BuildNumber, webCon.App.ClientConfigHash(), webCon.App.License() != nil)) webCon.Send <- msg } diff --git a/app/webhook.go b/app/webhook.go index a9bb32f35..f3777ab48 100644 --- a/app/webhook.go +++ b/app/webhook.go @@ -632,7 +632,7 @@ func (a *App) HandleIncomingWebhook(hookId string, req *model.IncomingWebhookReq } } - if utils.IsLicensed() && *a.Config().TeamSettings.ExperimentalTownSquareIsReadOnly && + if a.License() != nil && *a.Config().TeamSettings.ExperimentalTownSquareIsReadOnly && channel.Name == model.DEFAULT_CHANNEL { return model.NewAppError("HandleIncomingWebhook", "api.post.create_post.town_square_read_only", nil, "", http.StatusForbidden) } -- cgit v1.2.3-1-g7c22 From 809a16458f7483a2b762cd546493780fea6220ea Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 7 Feb 2018 13:41:15 +0530 Subject: Abort on critical error during server startup (#8204) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only a handful of critical errors are present in the codebase. They all occur during server startup (in `app.StartServer()`). Currently, when one of these critical error occurs, it is simpled mentionned in the logs – then the error is discarded, and the app attempts to continue the execution (and probably fails pretty quickly in a weird way). Rather than continuing operations in an unknow state, these errors should trigger a clean exit. This commit rewrites critical startup errors to be correctly propagated, logged, and then terminate the command execution. Additionnaly, it makes the server return a proper error code to the shell. --- app/app_test.go | 3 ++- app/apptestlib.go | 6 +++++- app/server.go | 12 +++++++----- app/server_test.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 app/server_test.go (limited to 'app') diff --git a/app/app_test.go b/app/app_test.go index 25b19ead8..09f8725d7 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -51,7 +51,8 @@ func TestAppRace(t *testing.T) { a, err := New() require.NoError(t, err) a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" }) - a.StartServer() + serverErr := a.StartServer() + require.NoError(t, serverErr) a.Shutdown() } } diff --git a/app/apptestlib.go b/app/apptestlib.go index 09afc8f76..016a68bec 100644 --- a/app/apptestlib.go +++ b/app/apptestlib.go @@ -96,7 +96,11 @@ func setupTestHelper(enterprise bool) *TestHelper { if testStore != nil { th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" }) } - th.App.StartServer() + serverErr := th.App.StartServer() + if serverErr != nil { + panic(serverErr) + } + th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = prevListenAddress }) th.App.Srv.Store.MarkSystemRanUnitTests() diff --git a/app/server.go b/app/server.go index 1659908b6..afa282ad6 100644 --- a/app/server.go +++ b/app/server.go @@ -17,6 +17,7 @@ import ( l4g "github.com/alecthomas/log4go" "github.com/gorilla/handlers" "github.com/gorilla/mux" + "github.com/pkg/errors" "golang.org/x/crypto/acme/autocert" "github.com/mattermost/mattermost-server/model" @@ -116,7 +117,7 @@ func redirectHTTPToHTTPS(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, url.String(), http.StatusFound) } -func (a *App) StartServer() { +func (a *App) StartServer() error { l4g.Info(utils.T("api.server.start_server.starting.info")) var handler http.Handler = &CorsWrapper{a.Config, a.Srv.Router} @@ -126,8 +127,7 @@ func (a *App) StartServer() { rateLimiter, err := NewRateLimiter(&a.Config().RateLimitSettings) if err != nil { - l4g.Critical(err.Error()) - return + return err } a.Srv.RateLimiter = rateLimiter @@ -151,8 +151,8 @@ func (a *App) StartServer() { listener, err := net.Listen("tcp", addr) if err != nil { - l4g.Critical(utils.T("api.server.start_server.starting.critical"), err) - return + errors.Wrapf(err, utils.T("api.server.start_server.starting.critical"), err) + return err } a.Srv.ListenAddr = listener.Addr().(*net.TCPAddr) @@ -214,6 +214,8 @@ func (a *App) StartServer() { } close(a.Srv.didFinishListen) }() + + return nil } type tcpKeepAliveListener struct { diff --git a/app/server_test.go b/app/server_test.go new file mode 100644 index 000000000..de358b976 --- /dev/null +++ b/app/server_test.go @@ -0,0 +1,50 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package app + +import ( + "testing" + + "github.com/mattermost/mattermost-server/model" + "github.com/stretchr/testify/require" +) + +func TestStartServerSuccess(t *testing.T) { + a, err := New() + require.NoError(t, err) + + a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" }) + serverErr := a.StartServer() + a.Shutdown() + require.NoError(t, serverErr) +} + +func TestStartServerRateLimiterCriticalError(t *testing.T) { + a, err := New() + require.NoError(t, err) + + // Attempt to use Rate Limiter with an invalid config + a.UpdateConfig(func(cfg *model.Config) { + *cfg.RateLimitSettings.Enable = true + *cfg.RateLimitSettings.MaxBurst = -100 + }) + + serverErr := a.StartServer() + a.Shutdown() + require.Error(t, serverErr) +} + +func TestStartServerPortUnavailable(t *testing.T) { + a, err := New() + require.NoError(t, err) + + // Attempt to listen on a system-reserved port + a.UpdateConfig(func(cfg *model.Config) { + *cfg.ServiceSettings.ListenAddress = ":21" + }) + + serverErr := a.StartServer() + a.Shutdown() + require.Error(t, serverErr) +} -- cgit v1.2.3-1-g7c22 From b2ee5077931013d308aaf60d790d341e2cb0c3e3 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 7 Feb 2018 07:21:40 -0600 Subject: allow plugins to set command hints (#8214) --- app/plugin.go | 1 + 1 file changed, 1 insertion(+) (limited to 'app') diff --git a/app/plugin.go b/app/plugin.go index 3f06a000f..fe671d26a 100644 --- a/app/plugin.go +++ b/app/plugin.go @@ -565,6 +565,7 @@ func (a *App) RegisterPluginCommand(pluginId string, command *model.Command) err TeamId: command.TeamId, AutoComplete: command.AutoComplete, AutoCompleteDesc: command.AutoCompleteDesc, + AutoCompleteHint: command.AutoCompleteHint, DisplayName: command.DisplayName, } -- cgit v1.2.3-1-g7c22 From d3e934d07ac0a58a24a435ea7c5b3bd222ef509a Mon Sep 17 00:00:00 2001 From: Jonathan Date: Wed, 7 Feb 2018 09:02:46 -0500 Subject: XYZ-35: Added Support for GlobalRelay Compliance Export Format * Added username to ChannelMemberHistory struct in anticipation of supporting GlobalRelay in Compliance Export * Removed translation from debug output - this makes it complicated to use utils functions from tests in the enterprise repo * Added an advanced email function that allows for greater control over message details. Updated MessageExport config to support GlobalRelay. Added attachment support to InBucket unit tests * Moving templates in from enterprise to solve test issues * Added export format to diagnostics * Changed email attachment code to use FileBackend so that S3 storage is properly supported --- app/diagnostics.go | 1 + 1 file changed, 1 insertion(+) (limited to 'app') diff --git a/app/diagnostics.go b/app/diagnostics.go index 809d9ff1e..6d83d3a89 100644 --- a/app/diagnostics.go +++ b/app/diagnostics.go @@ -501,6 +501,7 @@ func (a *App) trackConfig() { a.SendDiagnostic(TRACK_CONFIG_MESSAGE_EXPORT, map[string]interface{}{ "enable_message_export": *cfg.MessageExportSettings.EnableExport, + "export_format": *cfg.MessageExportSettings.ExportFormat, "daily_run_time": *cfg.MessageExportSettings.DailyRunTime, "default_export_from_timestamp": *cfg.MessageExportSettings.ExportFromTimestamp, "batch_size": *cfg.MessageExportSettings.BatchSize, -- cgit v1.2.3-1-g7c22 From 7bd298ceaa24c0721e0acd65692cb2d1ca4983f3 Mon Sep 17 00:00:00 2001 From: Vordimous Date: Wed, 7 Feb 2018 09:17:18 -0500 Subject: PLT-7537: Move channel CLI command posts system message to channel. (#8161) * [PTL-7537] implement feature and test * [PTL-7537] Update feature to post the the room requiring a username flag to be used * [PTL-7537] update tests with username * update test to remove changes to the test helper struct * use the basic team and user --- app/channel.go | 30 ++++++++++++++++++++++++++++-- app/channel_test.go | 4 ++-- 2 files changed, 30 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/channel.go b/app/channel.go index e4bf48654..8ac1f421c 100644 --- a/app/channel.go +++ b/app/channel.go @@ -1359,7 +1359,7 @@ func (a *App) PermanentDeleteChannel(channel *model.Channel) *model.AppError { // This function is intended for use from the CLI. It is not robust against people joining the channel while the move // is in progress, and therefore should not be used from the API without first fixing this potential race condition. -func (a *App) MoveChannel(team *model.Team, channel *model.Channel) *model.AppError { +func (a *App) MoveChannel(team *model.Team, channel *model.Channel, user *model.User) *model.AppError { // Check that all channel members are in the destination team. if channelMembers, err := a.GetChannelMembersPage(channel.Id, 0, 10000000); err != nil { return err @@ -1378,11 +1378,37 @@ func (a *App) MoveChannel(team *model.Team, channel *model.Channel) *model.AppEr } } - // Change the Team ID of the channel. + // keep instance of the previous team + var previousTeam *model.Team + if result := <-a.Srv.Store.Team().Get(channel.TeamId); result.Err != nil { + return result.Err + } else { + previousTeam = result.Data.(*model.Team) + } channel.TeamId = team.Id if result := <-a.Srv.Store.Channel().Update(channel); result.Err != nil { return result.Err } + a.postChannelMoveMessage(user, channel, previousTeam) + + return nil +} + +func (a *App) postChannelMoveMessage(user *model.User, channel *model.Channel, previousTeam *model.Team) *model.AppError { + + post := &model.Post{ + ChannelId: channel.Id, + Message: fmt.Sprintf(utils.T("api.team.move_channel.success"), previousTeam.Name), + Type: model.POST_MOVE_CHANNEL, + UserId: user.Id, + Props: model.StringInterface{ + "username": user.Username, + }, + } + + if _, err := a.CreatePost(post, channel, false); err != nil { + return model.NewAppError("postChannelMoveMessage", "api.team.move_channel.post.error", nil, err.Error(), http.StatusInternalServerError) + } return nil } diff --git a/app/channel_test.go b/app/channel_test.go index a414fbb35..d315fbae6 100644 --- a/app/channel_test.go +++ b/app/channel_test.go @@ -97,7 +97,7 @@ func TestMoveChannel(t *testing.T) { t.Fatal(err) } - if err := th.App.MoveChannel(targetTeam, channel1); err == nil { + if err := th.App.MoveChannel(targetTeam, channel1, th.BasicUser); err == nil { t.Fatal("Should have failed due to mismatched members.") } @@ -105,7 +105,7 @@ func TestMoveChannel(t *testing.T) { t.Fatal(err) } - if err := th.App.MoveChannel(targetTeam, channel1); err != nil { + if err := th.App.MoveChannel(targetTeam, channel1, th.BasicUser); err != nil { t.Fatal(err) } } -- cgit v1.2.3-1-g7c22