From 60359b4bae6d7b401f7b8b9f21685bde8a17ac1a Mon Sep 17 00:00:00 2001 From: George Goldberg Date: Tue, 26 Jun 2018 18:30:33 +0100 Subject: MM-10269: Make jobserver work without restart. (#9005) --- app/app.go | 3 +++ 1 file changed, 3 insertions(+) (limited to 'app') diff --git a/app/app.go b/app/app.go index 2041a24fe..911d359ae 100644 --- a/app/app.go +++ b/app/app.go @@ -208,6 +208,9 @@ func New(options ...Option) (outApp *App, outErr error) { } app.initJobs() + app.AddLicenseListener(func() { + app.initJobs() + }) subpath, err := utils.GetSubpathFromConfig(app.Config()) if err != nil { -- cgit v1.2.3-1-g7c22 From cbf9571c680514fd87d333c71f4f1eecc0bd6c5a Mon Sep 17 00:00:00 2001 From: Joram Wilander Date: Tue, 26 Jun 2018 13:40:39 -0400 Subject: MM-10700 - Updating default image preview size (#9002) (#9003) --- app/file.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/file.go b/app/file.go index add965fd7..95d11afed 100644 --- a/app/file.go +++ b/app/file.go @@ -54,7 +54,7 @@ const ( MaxImageSize = 6048 * 4032 // 24 megapixels, roughly 36MB as a raw image IMAGE_THUMBNAIL_PIXEL_WIDTH = 120 IMAGE_THUMBNAIL_PIXEL_HEIGHT = 100 - IMAGE_PREVIEW_PIXEL_WIDTH = 1024 + IMAGE_PREVIEW_PIXEL_WIDTH = 1920 ) func (a *App) FileBackend() (utils.FileBackend, *model.AppError) { -- cgit v1.2.3-1-g7c22 From 3e9fe291f155e711bc2371f5dd57d1d15960bb1d Mon Sep 17 00:00:00 2001 From: Jason Blais Date: Tue, 26 Jun 2018 13:47:07 -0400 Subject: Update diagnostics.go (#8989) --- app/diagnostics.go | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'app') diff --git a/app/diagnostics.go b/app/diagnostics.go index d833cdbec..3df62c41d 100644 --- a/app/diagnostics.go +++ b/app/diagnostics.go @@ -36,6 +36,7 @@ const ( TRACK_CONFIG_WEBRTC = "config_webrtc" TRACK_CONFIG_SUPPORT = "config_support" TRACK_CONFIG_NATIVEAPP = "config_nativeapp" + TRACK_CONFIG_EXPERIMENTAL = "config_experimental" TRACK_CONFIG_ANALYTICS = "config_analytics" TRACK_CONFIG_ANNOUNCEMENT = "config_announcement" TRACK_CONFIG_ELASTICSEARCH = "config_elasticsearch" @@ -252,6 +253,7 @@ func (a *App) trackConfig() { "allow_cookies_for_subdomains": *cfg.ServiceSettings.AllowCookiesForSubdomains, "enable_api_team_deletion": *cfg.ServiceSettings.EnableAPITeamDeletion, "experimental_enable_hardened_mode": *cfg.ServiceSettings.ExperimentalEnableHardenedMode, + "experimental_limit_client_config": *cfg.ServiceSettings.ExperimentalLimitClientConfig, }) a.SendDiagnostic(TRACK_CONFIG_TEAM, map[string]interface{}{ @@ -475,6 +477,11 @@ func (a *App) trackConfig() { "isdefault_turn_uri": isDefault(*cfg.WebrtcSettings.TurnURI, model.WEBRTC_SETTINGS_DEFAULT_TURN_URI), }) + a.SendDiagnostic(TRACK_CONFIG_EXPERIMENTAL, map[string]interface{}{ + "client_side_cert_enable": *cfg.ExperimentalSettings.ClientSideCertEnable, + "isdefault_client_side_cert_check": isDefault(*cfg.ExperimentalSettings.ClientSideCertCheck, model.CLIENT_SIDE_CERT_CHECK_PRIMARY_AUTH), + }) + a.SendDiagnostic(TRACK_CONFIG_ANALYTICS, map[string]interface{}{ "isdefault_max_users_for_statistics": isDefault(*cfg.AnalyticsSettings.MaxUsersForStatistics, model.ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS), }) -- cgit v1.2.3-1-g7c22 From 164e030d33b03cab347ddcdf064615cb9e144317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Tue, 26 Jun 2018 22:06:01 +0200 Subject: MM-11008: Fix translation and change the code to be auto-extracted (#9009) --- app/channel.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/channel.go b/app/channel.go index 7637e9d21..7394d813b 100644 --- a/app/channel.go +++ b/app/channel.go @@ -397,13 +397,13 @@ func (a *App) UpdateChannelPrivacy(oldChannel *model.Channel, user *model.User) } func (a *App) postChannelPrivacyMessage(user *model.User, channel *model.Channel) *model.AppError { - privacy := (map[string]string{ - model.CHANNEL_OPEN: "private_to_public", - model.CHANNEL_PRIVATE: "public_to_private", + message := (map[string]string{ + model.CHANNEL_OPEN: utils.T("api.channel.change_channel_privacy.private_to_public"), + model.CHANNEL_PRIVATE: utils.T("api.channel.change_channel_privacy.public_to_private"), })[channel.Type] post := &model.Post{ ChannelId: channel.Id, - Message: utils.T("api.channel.change_channel_privacy." + privacy), + Message: message, Type: model.POST_CHANGE_CHANNEL_PRIVACY, UserId: user.Id, Props: model.StringInterface{ -- cgit v1.2.3-1-g7c22 From 2d7cd02abcd62ffd60fe3c6e16e5189169de349e Mon Sep 17 00:00:00 2001 From: Jesse Hallam Date: Tue, 26 Jun 2018 16:46:58 -0400 Subject: MM-10833: send down computed channel props (#8953) * MM-10833: send down computed channel props This allows channel headers to reference channel mentions for a client that doesn't already know about the channels in question. We intentionally don't send down the props for the autocomplete and search endpoints since they aren't used in that context, and would add unnecessary overhead. * update channel props on patch * revert to treating channel purpose as plaintext --- app/channel.go | 64 ++++++++++++++++ app/channel_test.go | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+) (limited to 'app') diff --git a/app/channel.go b/app/channel.go index 7394d813b..eee27a6de 100644 --- a/app/channel.go +++ b/app/channel.go @@ -1591,3 +1591,67 @@ func (a *App) ToggleMuteChannel(channelId string, userId string) *model.ChannelM a.Srv.Store.Channel().UpdateMember(member) return member } + +func (a *App) FillInChannelProps(channel *model.Channel) *model.AppError { + return a.FillInChannelsProps(&model.ChannelList{channel}) +} + +func (a *App) FillInChannelsProps(channelList *model.ChannelList) *model.AppError { + // Group the channels by team and call GetChannelsByNames just once per team. + channelsByTeam := make(map[string]model.ChannelList) + for _, channel := range *channelList { + channelsByTeam[channel.TeamId] = append(channelsByTeam[channel.TeamId], channel) + } + + for teamId, channelList := range channelsByTeam { + allChannelMentions := make(map[string]bool) + channelMentions := make(map[*model.Channel][]string, len(channelList)) + + // Collect mentions across the channels so as to query just once for this team. + for _, channel := range channelList { + channelMentions[channel] = model.ChannelMentions(channel.Header) + + for _, channelMention := range channelMentions[channel] { + allChannelMentions[channelMention] = true + } + } + + allChannelMentionNames := make([]string, 0, len(allChannelMentions)) + for channelName := range allChannelMentions { + allChannelMentionNames = append(allChannelMentionNames, channelName) + } + + if len(allChannelMentionNames) > 0 { + mentionedChannels, err := a.GetChannelsByNames(allChannelMentionNames, teamId) + if err != nil { + return err + } + + mentionedChannelsByName := make(map[string]*model.Channel) + for _, channel := range mentionedChannels { + mentionedChannelsByName[channel.Name] = channel + } + + for _, channel := range channelList { + channelMentionsProp := make(map[string]interface{}, len(channelMentions[channel])) + for _, channelMention := range channelMentions[channel] { + if mentioned, ok := mentionedChannelsByName[channelMention]; ok { + if mentioned.Type == model.CHANNEL_OPEN { + channelMentionsProp[mentioned.Name] = map[string]interface{}{ + "display_name": mentioned.DisplayName, + } + } + } + } + + if len(channelMentionsProp) > 0 { + channel.AddProp("channel_mentions", channelMentionsProp) + } else if channel.Props != nil { + delete(channel.Props, "channel_mentions") + } + } + } + } + + return nil +} diff --git a/app/channel_test.go b/app/channel_test.go index 336d9b25b..4e6aaaf52 100644 --- a/app/channel_test.go +++ b/app/channel_test.go @@ -9,6 +9,7 @@ import ( "github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/store" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestPermanentDeleteChannel(t *testing.T) { @@ -399,3 +400,208 @@ func TestAppUpdateChannelScheme(t *testing.T) { t.Fatal("Wrong Channel SchemeId") } } + +func TestFillInChannelProps(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + + channelPublic1, err := th.App.CreateChannel(&model.Channel{DisplayName: "Public 1", Name: "public1", Type: model.CHANNEL_OPEN, TeamId: th.BasicTeam.Id}, false) + require.Nil(t, err) + defer th.App.PermanentDeleteChannel(channelPublic1) + + channelPublic2, err := th.App.CreateChannel(&model.Channel{DisplayName: "Public 2", Name: "public2", Type: model.CHANNEL_OPEN, TeamId: th.BasicTeam.Id}, false) + require.Nil(t, err) + defer th.App.PermanentDeleteChannel(channelPublic2) + + channelPrivate, err := th.App.CreateChannel(&model.Channel{DisplayName: "Private", Name: "private", Type: model.CHANNEL_PRIVATE, TeamId: th.BasicTeam.Id}, false) + require.Nil(t, err) + defer th.App.PermanentDeleteChannel(channelPrivate) + + otherTeamId := model.NewId() + otherTeam := &model.Team{ + DisplayName: "dn_" + otherTeamId, + Name: "name" + otherTeamId, + Email: "success+" + otherTeamId + "@simulator.amazonses.com", + Type: model.TEAM_OPEN, + } + otherTeam, err = th.App.CreateTeam(otherTeam) + require.Nil(t, err) + defer th.App.PermanentDeleteTeam(otherTeam) + + channelOtherTeam, err := th.App.CreateChannel(&model.Channel{DisplayName: "Other Team Channel", Name: "other-team", Type: model.CHANNEL_OPEN, TeamId: otherTeam.Id}, false) + require.Nil(t, err) + defer th.App.PermanentDeleteChannel(channelOtherTeam) + + // Note that purpose is intentionally plaintext below. + + t.Run("single channels", func(t *testing.T) { + testCases := []struct { + Description string + Channel *model.Channel + ExpectedChannelProps map[string]interface{} + }{ + { + "channel on basic team without references", + &model.Channel{ + TeamId: th.BasicTeam.Id, + Header: "No references", + Purpose: "No references", + }, + nil, + }, + { + "channel on basic team", + &model.Channel{ + TeamId: th.BasicTeam.Id, + Header: "~public1, ~private, ~other-team", + Purpose: "~public2, ~private, ~other-team", + }, + map[string]interface{}{ + "channel_mentions": map[string]interface{}{ + "public1": map[string]interface{}{ + "display_name": "Public 1", + }, + }, + }, + }, + { + "channel on other team", + &model.Channel{ + TeamId: otherTeam.Id, + Header: "~public1, ~private, ~other-team", + Purpose: "~public2, ~private, ~other-team", + }, + map[string]interface{}{ + "channel_mentions": map[string]interface{}{ + "other-team": map[string]interface{}{ + "display_name": "Other Team Channel", + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.Description, func(t *testing.T) { + err = th.App.FillInChannelProps(testCase.Channel) + require.Nil(t, err) + + assert.Equal(t, testCase.ExpectedChannelProps, testCase.Channel.Props) + }) + } + }) + + t.Run("multiple channels", func(t *testing.T) { + testCases := []struct { + Description string + Channels *model.ChannelList + ExpectedChannelProps map[string]interface{} + }{ + { + "single channel on basic team", + &model.ChannelList{ + { + Name: "test", + TeamId: th.BasicTeam.Id, + Header: "~public1, ~private, ~other-team", + Purpose: "~public2, ~private, ~other-team", + }, + }, + map[string]interface{}{ + "test": map[string]interface{}{ + "channel_mentions": map[string]interface{}{ + "public1": map[string]interface{}{ + "display_name": "Public 1", + }, + }, + }, + }, + }, + { + "multiple channels on basic team", + &model.ChannelList{ + { + Name: "test", + TeamId: th.BasicTeam.Id, + Header: "~public1, ~private, ~other-team", + Purpose: "~public2, ~private, ~other-team", + }, + { + Name: "test2", + TeamId: th.BasicTeam.Id, + Header: "~private, ~other-team", + Purpose: "~public2, ~private, ~other-team", + }, + { + Name: "test3", + TeamId: th.BasicTeam.Id, + Header: "No references", + Purpose: "No references", + }, + }, + map[string]interface{}{ + "test": map[string]interface{}{ + "channel_mentions": map[string]interface{}{ + "public1": map[string]interface{}{ + "display_name": "Public 1", + }, + }, + }, + "test2": map[string]interface{}(nil), + "test3": map[string]interface{}(nil), + }, + }, + { + "multiple channels across teams", + &model.ChannelList{ + { + Name: "test", + TeamId: th.BasicTeam.Id, + Header: "~public1, ~private, ~other-team", + Purpose: "~public2, ~private, ~other-team", + }, + { + Name: "test2", + TeamId: otherTeam.Id, + Header: "~private, ~other-team", + Purpose: "~public2, ~private, ~other-team", + }, + { + Name: "test3", + TeamId: th.BasicTeam.Id, + Header: "No references", + Purpose: "No references", + }, + }, + map[string]interface{}{ + "test": map[string]interface{}{ + "channel_mentions": map[string]interface{}{ + "public1": map[string]interface{}{ + "display_name": "Public 1", + }, + }, + }, + "test2": map[string]interface{}{ + "channel_mentions": map[string]interface{}{ + "other-team": map[string]interface{}{ + "display_name": "Other Team Channel", + }, + }, + }, + "test3": map[string]interface{}(nil), + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.Description, func(t *testing.T) { + err = th.App.FillInChannelsProps(testCase.Channels) + require.Nil(t, err) + + for _, channel := range *testCase.Channels { + assert.Equal(t, testCase.ExpectedChannelProps[channel.Name], channel.Props) + } + }) + } + }) +} -- cgit v1.2.3-1-g7c22 From f17c15c9d83e42e46adb8e8c1fb9706b22fe6f50 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Wed, 27 Jun 2018 01:23:13 +0100 Subject: Simplify oauth (#8972) * Remove unused OauthProvider::GetIdentifier Signed-off-by: Emil Velikov * Reuse gitlab's getAuthData() instead of open-coding it Signed-off-by: Emil Velikov * Remove OauthProvider::GetAuthDataFromJson interface The data is already available via GetUserFromJson().AuthData Signed-off-by: Emil Velikov --- app/oauth.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/oauth.go b/app/oauth.go index 477c0aeaf..80fe4342e 100644 --- a/app/oauth.go +++ b/app/oauth.go @@ -457,7 +457,13 @@ func (a *App) LoginByOAuth(service string, userData io.Reader, teamId string) (* return nil, model.NewAppError("LoginByOAuth", "api.user.login_by_oauth.not_available.app_error", map[string]interface{}{"Service": strings.Title(service)}, "", http.StatusNotImplemented) } else { - authData = provider.GetAuthDataFromJson(bytes.NewReader(buf.Bytes())) + authUser := provider.GetUserFromJson(bytes.NewReader(buf.Bytes())) + + if authUser.AuthData != nil { + authData = *authUser.AuthData + } else { + authData = "" + } } if len(authData) == 0 { -- cgit v1.2.3-1-g7c22 From 0d91bf323ec32f46453b2c4c1877e8eeb830ab4d Mon Sep 17 00:00:00 2001 From: Joram Wilander Date: Wed, 27 Jun 2018 05:08:40 -0400 Subject: Lock bulk importing to master database node (#9012) --- app/import.go | 3 +++ 1 file changed, 3 insertions(+) (limited to 'app') diff --git a/app/import.go b/app/import.go index 04e71b64c..64e53fe93 100644 --- a/app/import.go +++ b/app/import.go @@ -209,6 +209,9 @@ func (a *App) BulkImport(fileReader io.Reader, dryRun bool, workers int) (*model scanner := bufio.NewScanner(fileReader) lineNumber := 0 + a.Srv.Store.LockToMaster() + defer a.Srv.Store.UnlockFromMaster() + errorsChan := make(chan LineImportWorkerError, (2*workers)+1) // size chosen to ensure it never gets filled up completely. var wg sync.WaitGroup var linesChan chan LineImportWorkerData -- cgit v1.2.3-1-g7c22 From 9abd74c5e31625c1c11fcedafc44f8aadc4ecdb0 Mon Sep 17 00:00:00 2001 From: Sudheer Date: Wed, 27 Jun 2018 18:38:58 +0530 Subject: MM-10910 fix join and open channel commands to work with tilde (#8984) * MM-10910 fix join and open channel commands to work with tilde * Fix lint * Add basic tests for command_join --- app/command_join.go | 11 ++++-- app/command_join_test.go | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 app/command_join_test.go (limited to 'app') diff --git a/app/command_join.go b/app/command_join.go index 92084448e..61ed65ba6 100644 --- a/app/command_join.go +++ b/app/command_join.go @@ -6,6 +6,7 @@ package app import ( "github.com/mattermost/mattermost-server/model" goi18n "github.com/nicksnyder/go-i18n/i18n" + "strings" ) type JoinProvider struct { @@ -34,12 +35,18 @@ func (me *JoinProvider) GetCommand(a *App, T goi18n.TranslateFunc) *model.Comman } func (me *JoinProvider) DoCommand(a *App, args *model.CommandArgs, message string) *model.CommandResponse { - if result := <-a.Srv.Store.Channel().GetByName(args.TeamId, message, true); result.Err != nil { + channelName := message + + if strings.HasPrefix(message, "~") { + channelName = message[1:] + } + + if result := <-a.Srv.Store.Channel().GetByName(args.TeamId, channelName, true); result.Err != nil { return &model.CommandResponse{Text: args.T("api.command_join.list.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL} } else { channel := result.Data.(*model.Channel) - if channel.Name == message { + if channel.Name == channelName { allowed := false if (channel.Type == model.CHANNEL_PRIVATE && a.SessionHasPermissionToChannel(args.Session, channel.Id, model.PERMISSION_READ_CHANNEL)) || channel.Type == model.CHANNEL_OPEN { allowed = true diff --git a/app/command_join_test.go b/app/command_join_test.go new file mode 100644 index 000000000..77574217b --- /dev/null +++ b/app/command_join_test.go @@ -0,0 +1,88 @@ +// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package app + +import ( + "testing" + "github.com/mattermost/mattermost-server/model" + "github.com/nicksnyder/go-i18n/i18n" + "github.com/stretchr/testify/assert" +) + +func TestJoinCommandNoChannel(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + + if testing.Short() { + t.SkipNow() + } + + cmd := &JoinProvider{} + resp := cmd.DoCommand(th.App, &model.CommandArgs{ + T: i18n.IdentityTfunc(), + UserId: th.BasicUser2.Id, + SiteURL: "http://test.url", + TeamId: th.BasicTeam.Id, + }, "asdsad") + + assert.Equal(t, "api.command_join.list.app_error", resp.Text) +} + +func TestJoinCommandForExistingChannel(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + + if testing.Short() { + t.SkipNow() + } + + channel2, _ := th.App.CreateChannel(&model.Channel{ + DisplayName: "AA", + Name: "aa" + model.NewId() + "a", + Type: model.CHANNEL_OPEN, + TeamId: th.BasicTeam.Id, + CreatorId: th.BasicUser.Id, + }, false) + + + cmd := &JoinProvider{} + resp := cmd.DoCommand(th.App, &model.CommandArgs{ + T: i18n.IdentityTfunc(), + UserId: th.BasicUser2.Id, + SiteURL: "http://test.url", + TeamId: th.BasicTeam.Id, + }, channel2.Name) + + assert.Equal(t, "", resp.Text) + assert.Equal(t, "http://test.url/"+th.BasicTeam.Name+"/channels/"+channel2.Name, resp.GotoLocation) +} + +func TestJoinCommandWithTilde(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + + if testing.Short() { + t.SkipNow() + } + + channel2, _ := th.App.CreateChannel(&model.Channel{ + DisplayName: "AA", + Name: "aa" + model.NewId() + "a", + Type: model.CHANNEL_OPEN, + TeamId: th.BasicTeam.Id, + CreatorId: th.BasicUser.Id, + }, false) + + + cmd := &JoinProvider{} + resp := cmd.DoCommand(th.App, &model.CommandArgs{ + T: i18n.IdentityTfunc(), + UserId: th.BasicUser2.Id, + SiteURL: "http://test.url", + TeamId: th.BasicTeam.Id, + }, "~"+channel2.Name) + + assert.Equal(t, "", resp.Text) + assert.Equal(t, "http://test.url/"+th.BasicTeam.Name+"/channels/"+channel2.Name, resp.GotoLocation) +} -- cgit v1.2.3-1-g7c22