diff options
author | JoramWilander <jwawilander@gmail.com> | 2018-06-27 16:56:50 -0400 |
---|---|---|
committer | JoramWilander <jwawilander@gmail.com> | 2018-06-27 16:56:50 -0400 |
commit | 88c5e469ca869d9e8ceadb0f2b03e86005102f24 (patch) | |
tree | bbb1b4cc1312879476f222940651e4d3e763da9e /app | |
parent | d7976549a0b45a42c04ac043a15677b7ca1228e9 (diff) | |
parent | 437f9f5b64ddb4e1f84e6c4e993120d074001777 (diff) | |
download | chat-88c5e469ca869d9e8ceadb0f2b03e86005102f24.tar.gz chat-88c5e469ca869d9e8ceadb0f2b03e86005102f24.tar.bz2 chat-88c5e469ca869d9e8ceadb0f2b03e86005102f24.zip |
Merge branch 'master' into plugins-2
Diffstat (limited to 'app')
-rw-r--r-- | app/app.go | 3 | ||||
-rw-r--r-- | app/channel.go | 72 | ||||
-rw-r--r-- | app/channel_test.go | 206 | ||||
-rw-r--r-- | app/command_join.go | 11 | ||||
-rw-r--r-- | app/command_join_test.go | 88 | ||||
-rw-r--r-- | app/diagnostics.go | 7 | ||||
-rw-r--r-- | app/file.go | 2 | ||||
-rw-r--r-- | app/import.go | 3 | ||||
-rw-r--r-- | app/oauth.go | 8 |
9 files changed, 392 insertions, 8 deletions
diff --git a/app/app.go b/app/app.go index 51aa1374e..6bf4c9f68 100644 --- a/app/app.go +++ b/app/app.go @@ -206,6 +206,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 { diff --git a/app/channel.go b/app/channel.go index 7637e9d21..eee27a6de 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{ @@ -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) + } + }) + } + }) +} 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) +} diff --git a/app/diagnostics.go b/app/diagnostics.go index c37d7d339..966cdb5be 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), }) 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) { 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 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 { |