diff options
-rw-r--r-- | api/file.go | 22 | ||||
-rw-r--r-- | api/post.go | 42 | ||||
-rw-r--r-- | api/post_test.go | 40 | ||||
-rw-r--r-- | api/user.go | 12 | ||||
-rw-r--r-- | model/post_list.go | 9 | ||||
-rw-r--r-- | model/post_list_test.go | 34 | ||||
-rw-r--r-- | model/search_params.go | 88 | ||||
-rw-r--r-- | model/search_params_test.go | 17 | ||||
-rw-r--r-- | store/sql_post_store.go | 52 | ||||
-rw-r--r-- | web/react/components/create_post.jsx | 10 | ||||
-rw-r--r-- | web/react/components/error_bar.jsx | 12 | ||||
-rw-r--r-- | web/react/components/user_settings/user_settings_general.jsx | 2 | ||||
-rw-r--r-- | web/react/stores/socket_store.jsx | 2 | ||||
-rw-r--r-- | web/react/utils/async_client.jsx | 4 | ||||
-rw-r--r-- | web/react/utils/constants.jsx | 1 |
15 files changed, 237 insertions, 110 deletions
diff --git a/api/file.go b/api/file.go index 94eea516a..f65be145d 100644 --- a/api/file.go +++ b/api/file.go @@ -52,6 +52,8 @@ const ( RotatedCCW = 6 RotatedCCWMirrored = 7 RotatedCW = 8 + + MaxImageSize = 4096 * 2160 // 4k resolution ) var fileInfoCache *utils.Cache = utils.NewLru(1000) @@ -125,6 +127,21 @@ func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) { uid := model.NewId() + if model.IsFileExtImage(filepath.Ext(files[i].Filename)) { + imageNameList = append(imageNameList, uid+"/"+filename) + imageDataList = append(imageDataList, buf.Bytes()) + + // Decode image config first to check dimensions before loading the whole thing into memory later on + config, _, err := image.DecodeConfig(bytes.NewReader(buf.Bytes())) + if err != nil { + c.Err = model.NewAppError("uploadFile", "Unable to upload image file.", err.Error()) + return + } else if config.Width*config.Height > MaxImageSize { + c.Err = model.NewAppError("uploadFile", "Unable to upload image file. File is too large.", err.Error()) + return + } + } + path := "teams/" + c.Session.TeamId + "/channels/" + channelId + "/users/" + c.Session.UserId + "/" + uid + "/" + filename if err := writeFile(buf.Bytes(), path); err != nil { @@ -132,11 +149,6 @@ func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) { return } - if model.IsFileExtImage(filepath.Ext(files[i].Filename)) { - imageNameList = append(imageNameList, uid+"/"+filename) - imageDataList = append(imageDataList, buf.Bytes()) - } - encName := utils.UrlEncode(filename) fileUrl := "/" + channelId + "/" + c.Session.UserId + "/" + uid + "/" + encName diff --git a/api/post.go b/api/post.go index 79f84e04d..b8588fe6a 100644 --- a/api/post.go +++ b/api/post.go @@ -820,45 +820,23 @@ func searchPosts(c *Context, w http.ResponseWriter, r *http.Request) { return } - plainSearchParams, hashtagSearchParams := model.ParseSearchParams(terms) + paramsList := model.ParseSearchParams(terms) + channels := []store.StoreChannel{} - var hchan store.StoreChannel - if hashtagSearchParams != nil { - hchan = Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, hashtagSearchParams) + for _, params := range paramsList { + channels = append(channels, Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, params)) } - var pchan store.StoreChannel - if plainSearchParams != nil { - pchan = Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, plainSearchParams) - } - - mainList := &model.PostList{} - if hchan != nil { - if result := <-hchan; result.Err != nil { + posts := &model.PostList{} + for _, channel := range channels { + if result := <-channel; result.Err != nil { c.Err = result.Err return } else { - mainList = result.Data.(*model.PostList) + data := result.Data.(*model.PostList) + posts.Extend(data) } } - plainList := &model.PostList{} - if pchan != nil { - if result := <-pchan; result.Err != nil { - c.Err = result.Err - return - } else { - plainList = result.Data.(*model.PostList) - } - } - - for _, postId := range plainList.Order { - if _, ok := mainList.Posts[postId]; !ok { - mainList.AddPost(plainList.Posts[postId]) - mainList.AddOrder(postId) - } - - } - - w.Write([]byte(mainList.ToJson())) + w.Write([]byte(posts.ToJson())) } diff --git a/api/post_test.go b/api/post_test.go index ac9d5668b..e54e9ef0c 100644 --- a/api/post_test.go +++ b/api/post_test.go @@ -427,12 +427,18 @@ func TestSearchPostsInChannel(t *testing.T) { channel2 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id} channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel) + channel3 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id} + channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel) + post2 := &model.Post{ChannelId: channel2.Id, Message: "sgtitlereview\n with return"} post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post) post3 := &model.Post{ChannelId: channel2.Id, Message: "other message with no return"} post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post) + post4 := &model.Post{ChannelId: channel3.Id, Message: "other message with no return"} + post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post) + if result := Client.Must(Client.SearchPosts("channel:")).Data.(*model.PostList); len(result.Order) != 0 { t.Fatalf("wrong number of posts returned %v", len(result.Order)) } @@ -476,6 +482,10 @@ func TestSearchPostsInChannel(t *testing.T) { if result := Client.Must(Client.SearchPosts("sgtitlereview channel: " + channel2.Name)).Data.(*model.PostList); len(result.Order) != 1 { t.Fatalf("wrong number of posts returned %v", len(result.Order)) } + + if result := Client.Must(Client.SearchPosts("channel: " + channel2.Name + " channel: " + channel3.Name)).Data.(*model.PostList); len(result.Order) != 3 { + t.Fatalf("wrong number of posts returned :) %v :) %v", result.Posts, result.Order) + } } func TestSearchPostsFromUser(t *testing.T) { @@ -510,11 +520,12 @@ func TestSearchPostsFromUser(t *testing.T) { post2 := &model.Post{ChannelId: channel2.Id, Message: "sgtitlereview\n with return"} post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post) + // includes "X has joined the channel" messages for both user2 and user3 + if result := Client.Must(Client.SearchPosts("from: " + user1.Username)).Data.(*model.PostList); len(result.Order) != 1 { t.Fatalf("wrong number of posts returned %v", len(result.Order)) } - // note that this includes the "User2 has joined the channel" system messages if result := Client.Must(Client.SearchPosts("from: " + user2.Username)).Data.(*model.PostList); len(result.Order) != 3 { t.Fatalf("wrong number of posts returned %v", len(result.Order)) } @@ -526,6 +537,33 @@ func TestSearchPostsFromUser(t *testing.T) { if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " in:" + channel1.Name)).Data.(*model.PostList); len(result.Order) != 1 { t.Fatalf("wrong number of posts returned %v", len(result.Order)) } + + user3 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"} + user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User) + store.Must(Srv.Store.User().VerifyEmail(user3.Id)) + + Client.LoginByEmail(team.Name, user3.Email, "pwd") + Client.Must(Client.JoinChannel(channel1.Id)) + Client.Must(Client.JoinChannel(channel2.Id)) + + // wait for the join/leave messages to be created for user3 since they're done asynchronously + time.Sleep(100 * time.Millisecond) + + if result := Client.Must(Client.SearchPosts("from: " + user2.Username)).Data.(*model.PostList); len(result.Order) != 3 { + t.Fatalf("wrong number of posts returned %v", len(result.Order)) + } + + if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " from: " + user3.Username)).Data.(*model.PostList); len(result.Order) != 5 { + t.Fatalf("wrong number of posts returned %v", len(result.Order)) + } + + if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " from: " + user3.Username + " in:" + channel2.Name)).Data.(*model.PostList); len(result.Order) != 3 { + t.Fatalf("wrong number of posts returned %v", len(result.Order)) + } + + if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " from: " + user3.Username + " in:" + channel2.Name + " joined")).Data.(*model.PostList); len(result.Order) != 2 { + t.Fatalf("wrong number of posts returned %v", len(result.Order)) + } } func TestGetPostsCache(t *testing.T) { diff --git a/api/user.go b/api/user.go index 06e5336f1..3796a50ee 100644 --- a/api/user.go +++ b/api/user.go @@ -855,6 +855,18 @@ func uploadProfileImage(c *Context, w http.ResponseWriter, r *http.Request) { return } + // Decode image config first to check dimensions before loading the whole thing into memory later on + config, _, err := image.DecodeConfig(file) + if err != nil { + c.Err = model.NewAppError("uploadProfileFile", "Could not decode profile image config.", err.Error()) + return + } else if config.Width*config.Height > MaxImageSize { + c.Err = model.NewAppError("uploadProfileFile", "Unable to upload profile image. File is too large.", err.Error()) + return + } + + file.Seek(0, 0) + // Decode image into Image object img, _, err := image.Decode(file) if err != nil { diff --git a/model/post_list.go b/model/post_list.go index 862673ef3..4c0f5408e 100644 --- a/model/post_list.go +++ b/model/post_list.go @@ -54,6 +54,15 @@ func (o *PostList) AddPost(post *Post) { o.Posts[post.Id] = post } +func (o *PostList) Extend(other *PostList) { + for _, postId := range other.Order { + if _, ok := o.Posts[postId]; !ok { + o.AddPost(other.Posts[postId]) + o.AddOrder(postId) + } + } +} + func (o *PostList) Etag() string { id := "0" diff --git a/model/post_list_test.go b/model/post_list_test.go index 8a34327ce..9ce6447e1 100644 --- a/model/post_list_test.go +++ b/model/post_list_test.go @@ -34,3 +34,37 @@ func TestPostListJson(t *testing.T) { t.Fatal("failed to serialize") } } + +func TestPostListExtend(t *testing.T) { + l1 := PostList{} + + p1 := &Post{Id: NewId(), Message: NewId()} + l1.AddPost(p1) + l1.AddOrder(p1.Id) + + p2 := &Post{Id: NewId(), Message: NewId()} + l1.AddPost(p2) + l1.AddOrder(p2.Id) + + l2 := PostList{} + + p3 := &Post{Id: NewId(), Message: NewId()} + l2.AddPost(p3) + l2.AddOrder(p3.Id) + + l2.Extend(&l1) + + if len(l1.Posts) != 2 || len(l1.Order) != 2 { + t.Fatal("extending l2 changed l1") + } else if len(l2.Posts) != 3 { + t.Fatal("failed to extend posts l2") + } else if l2.Order[0] != p3.Id || l2.Order[1] != p1.Id || l2.Order[2] != p2.Id { + t.Fatal("failed to extend order of l2") + } + + if len(l1.Posts) != 2 || len(l1.Order) != 2 { + t.Fatal("extending l2 again changed l1") + } else if len(l2.Posts) != 3 || len(l2.Order) != 3 { + t.Fatal("extending l2 again changed l2") + } +} diff --git a/model/search_params.go b/model/search_params.go index 7eeeed10f..144e8e461 100644 --- a/model/search_params.go +++ b/model/search_params.go @@ -8,10 +8,10 @@ import ( ) type SearchParams struct { - Terms string - IsHashtag bool - InChannel string - FromUser string + Terms string + IsHashtag bool + InChannels []string + FromUsers []string } var searchFlags = [...]string{"from", "channel", "in"} @@ -31,9 +31,9 @@ func splitWords(text string) []string { return words } -func parseSearchFlags(input []string) ([]string, map[string]string) { +func parseSearchFlags(input []string) ([]string, [][2]string) { words := []string{} - flags := make(map[string]string) + flags := [][2]string{} skipNextWord := false for i, word := range input { @@ -52,10 +52,10 @@ func parseSearchFlags(input []string) ([]string, map[string]string) { // check for case insensitive equality if strings.EqualFold(flag, searchFlag) { if value != "" { - flags[searchFlag] = value + flags = append(flags, [2]string{searchFlag, value}) isFlag = true } else if i < len(input)-1 { - flags[searchFlag] = input[i+1] + flags = append(flags, [2]string{searchFlag, input[i+1]}) skipNextWord = true isFlag = true } @@ -75,56 +75,66 @@ func parseSearchFlags(input []string) ([]string, map[string]string) { return words, flags } -func ParseSearchParams(text string) (*SearchParams, *SearchParams) { +func ParseSearchParams(text string) []*SearchParams { words, flags := parseSearchFlags(splitWords(text)) - hashtagTerms := []string{} - plainTerms := []string{} + hashtagTermList := []string{} + plainTermList := []string{} for _, word := range words { if validHashtag.MatchString(word) { - hashtagTerms = append(hashtagTerms, word) + hashtagTermList = append(hashtagTermList, word) } else { - plainTerms = append(plainTerms, word) + plainTermList = append(plainTermList, word) } } - inChannel := flags["channel"] - if inChannel == "" { - inChannel = flags["in"] + hashtagTerms := strings.Join(hashtagTermList, " ") + plainTerms := strings.Join(plainTermList, " ") + + inChannels := []string{} + fromUsers := []string{} + + for _, flagPair := range flags { + flag := flagPair[0] + value := flagPair[1] + + if flag == "in" || flag == "channel" { + inChannels = append(inChannels, value) + } else if flag == "from" { + fromUsers = append(fromUsers, value) + } } - fromUser := flags["from"] + paramsList := []*SearchParams{} - var plainParams *SearchParams if len(plainTerms) > 0 { - plainParams = &SearchParams{ - Terms: strings.Join(plainTerms, " "), - IsHashtag: false, - InChannel: inChannel, - FromUser: fromUser, - } + paramsList = append(paramsList, &SearchParams{ + Terms: plainTerms, + IsHashtag: false, + InChannels: inChannels, + FromUsers: fromUsers, + }) } - var hashtagParams *SearchParams if len(hashtagTerms) > 0 { - hashtagParams = &SearchParams{ - Terms: strings.Join(hashtagTerms, " "), - IsHashtag: true, - InChannel: inChannel, - FromUser: fromUser, - } + paramsList = append(paramsList, &SearchParams{ + Terms: hashtagTerms, + IsHashtag: true, + InChannels: inChannels, + FromUsers: fromUsers, + }) } // special case for when no terms are specified but we still have a filter - if plainParams == nil && hashtagParams == nil && (inChannel != "" || fromUser != "") { - plainParams = &SearchParams{ - Terms: "", - IsHashtag: false, - InChannel: inChannel, - FromUser: fromUser, - } + if len(plainTerms) == 0 && len(hashtagTerms) == 0 { + paramsList = append(paramsList, &SearchParams{ + Terms: "", + IsHashtag: true, + InChannels: inChannels, + FromUsers: fromUsers, + }) } - return plainParams, hashtagParams + return paramsList } diff --git a/model/search_params_test.go b/model/search_params_test.go index 2eba20f4c..e03e82c5a 100644 --- a/model/search_params_test.go +++ b/model/search_params_test.go @@ -28,25 +28,25 @@ func TestParseSearchFlags(t *testing.T) { if words, flags := parseSearchFlags(splitWords("apple banana from:chan")); len(words) != 2 || words[0] != "apple" || words[1] != "banana" { t.Fatalf("got incorrect words %v", words) - } else if len(flags) != 1 || flags["from"] != "chan" { + } else if len(flags) != 1 || flags[0][0] != "from" || flags[0][1] != "chan" { t.Fatalf("got incorrect flags %v", flags) } if words, flags := parseSearchFlags(splitWords("apple banana from: chan")); len(words) != 2 || words[0] != "apple" || words[1] != "banana" { t.Fatalf("got incorrect words %v", words) - } else if len(flags) != 1 || flags["from"] != "chan" { + } else if len(flags) != 1 || flags[0][0] != "from" || flags[0][1] != "chan" { t.Fatalf("got incorrect flags %v", flags) } if words, flags := parseSearchFlags(splitWords("apple banana in: chan")); len(words) != 2 || words[0] != "apple" || words[1] != "banana" { t.Fatalf("got incorrect words %v", words) - } else if len(flags) != 1 || flags["in"] != "chan" { + } else if len(flags) != 1 || flags[0][0] != "in" || flags[0][1] != "chan" { t.Fatalf("got incorrect flags %v", flags) } if words, flags := parseSearchFlags(splitWords("apple banana channel:chan")); len(words) != 2 || words[0] != "apple" || words[1] != "banana" { t.Fatalf("got incorrect words %v", words) - } else if len(flags) != 1 || flags["channel"] != "chan" { + } else if len(flags) != 1 || flags[0][0] != "channel" || flags[0][1] != "chan" { t.Fatalf("got incorrect flags %v", flags) } @@ -64,7 +64,14 @@ func TestParseSearchFlags(t *testing.T) { if words, flags := parseSearchFlags(splitWords("channel: first in: second from:")); len(words) != 1 || words[0] != "from:" { t.Fatalf("got incorrect words %v", words) - } else if len(flags) != 2 || flags["channel"] != "first" || flags["in"] != "second" { + } else if len(flags) != 2 || flags[0][0] != "channel" || flags[0][1] != "first" || flags[1][0] != "in" || flags[1][1] != "second" { + t.Fatalf("got incorrect flags %v", flags) + } + + if words, flags := parseSearchFlags(splitWords("channel: first channel: second from: third from: fourth")); len(words) != 0 { + t.Fatalf("got incorrect words %v", words) + } else if len(flags) != 4 || flags[0][0] != "channel" || flags[0][1] != "first" || flags[1][0] != "channel" || flags[1][1] != "second" || + flags[2][0] != "from" || flags[2][1] != "third" || flags[3][0] != "from" || flags[3][1] != "fourth" { t.Fatalf("got incorrect flags %v", flags) } } diff --git a/store/sql_post_store.go b/store/sql_post_store.go index 6971de9d7..ea913ab6a 100644 --- a/store/sql_post_store.go +++ b/store/sql_post_store.go @@ -6,6 +6,7 @@ package store import ( "fmt" "regexp" + "strconv" "strings" "github.com/mattermost/platform/model" @@ -413,10 +414,15 @@ func (s SqlPostStore) Search(teamId string, userId string, params *model.SearchP go func() { result := StoreResult{} + queryParams := map[string]interface{}{ + "TeamId": teamId, + "UserId": userId, + } + termMap := map[string]bool{} terms := params.Terms - if terms == "" && params.InChannel == "" && params.FromUser == "" { + if terms == "" && len(params.InChannels) == 0 && len(params.FromUsers) == 0 { result.Data = []*model.Post{} storeChannel <- result return @@ -468,13 +474,45 @@ func (s SqlPostStore) Search(teamId string, userId string, params *model.SearchP ORDER BY CreateAt DESC LIMIT 100` - if params.InChannel != "" { + if len(params.InChannels) > 1 { + inClause := ":InChannel0" + queryParams["InChannel0"] = params.InChannels[0] + + for i := 1; i < len(params.InChannels); i++ { + paramName := "InChannel" + strconv.FormatInt(int64(i), 10) + inClause += ", :" + paramName + queryParams[paramName] = params.InChannels[i] + } + + searchQuery = strings.Replace(searchQuery, "CHANNEL_FILTER", "AND Name IN ("+inClause+")", 1) + } else if len(params.InChannels) == 1 { + queryParams["InChannel"] = params.InChannels[0] searchQuery = strings.Replace(searchQuery, "CHANNEL_FILTER", "AND Name = :InChannel", 1) } else { searchQuery = strings.Replace(searchQuery, "CHANNEL_FILTER", "", 1) } - if params.FromUser != "" { + if len(params.FromUsers) > 1 { + inClause := ":FromUser0" + queryParams["FromUser0"] = params.FromUsers[0] + + for i := 1; i < len(params.FromUsers); i++ { + paramName := "FromUser" + strconv.FormatInt(int64(i), 10) + inClause += ", :" + paramName + queryParams[paramName] = params.FromUsers[i] + } + + searchQuery = strings.Replace(searchQuery, "POST_FILTER", ` + AND UserId IN ( + SELECT + Id + FROM + Users + WHERE + TeamId = :TeamId + AND Username IN (`+inClause+`))`, 1) + } else if len(params.FromUsers) == 1 { + queryParams["FromUser"] = params.FromUsers[0] searchQuery = strings.Replace(searchQuery, "POST_FILTER", ` AND UserId IN ( SELECT @@ -506,13 +544,7 @@ func (s SqlPostStore) Search(teamId string, userId string, params *model.SearchP searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", searchClause, 1) } - queryParams := map[string]interface{}{ - "TeamId": teamId, - "UserId": userId, - "Terms": terms, - "InChannel": params.InChannel, - "FromUser": params.FromUser, - } + queryParams["Terms"] = terms _, err := s.GetReplica().Select(&posts, searchQuery, queryParams) if err != nil { diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index b74f1871c..32ee31efe 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -253,8 +253,14 @@ export default class CreatePost extends React.Component { this.setState({uploadsInProgress: draft.uploadsInProgress, previews: draft.previews}); } handleUploadError(err, clientId) { + let message = err; + if (message && typeof message !== 'string') { + // err is an AppError from the server + message = err.message; + } + if (clientId === -1) { - this.setState({serverError: err}); + this.setState({serverError: message}); } else { const draft = PostStore.getDraft(this.state.channelId); @@ -265,7 +271,7 @@ export default class CreatePost extends React.Component { PostStore.storeDraft(this.state.channelId, draft); - this.setState({uploadsInProgress: draft.uploadsInProgress, serverError: err}); + this.setState({uploadsInProgress: draft.uploadsInProgress, serverError: message}); } } handleTextDrop(text) { diff --git a/web/react/components/error_bar.jsx b/web/react/components/error_bar.jsx index 6311d9460..f098384aa 100644 --- a/web/react/components/error_bar.jsx +++ b/web/react/components/error_bar.jsx @@ -9,12 +9,8 @@ export default class ErrorBar extends React.Component { this.onErrorChange = this.onErrorChange.bind(this); this.handleClose = this.handleClose.bind(this); - this.prevTimer = null; this.state = ErrorStore.getLastError(); - if (this.isValidError(this.state)) { - this.prevTimer = setTimeout(this.handleClose, 10000); - } } isValidError(s) { @@ -56,16 +52,8 @@ export default class ErrorBar extends React.Component { onErrorChange() { var newState = ErrorStore.getLastError(); - if (this.prevTimer != null) { - clearInterval(this.prevTimer); - this.prevTimer = null; - } - if (newState) { this.setState(newState); - if (!this.isConnectionError(newState)) { - this.prevTimer = setTimeout(this.handleClose, 10000); - } } else { this.setState({message: null}); } diff --git a/web/react/components/user_settings/user_settings_general.jsx b/web/react/components/user_settings/user_settings_general.jsx index 70e559c30..1c8ce3c79 100644 --- a/web/react/components/user_settings/user_settings_general.jsx +++ b/web/react/components/user_settings/user_settings_general.jsx @@ -171,7 +171,7 @@ export default class UserSettingsGeneralTab extends React.Component { }.bind(this), function imageUploadFailure(err) { var state = this.setupInitialState(this.props); - state.serverError = err; + state.serverError = err.message; this.setState(state); }.bind(this) ); diff --git a/web/react/stores/socket_store.jsx b/web/react/stores/socket_store.jsx index 9410c1e9c..d4b0e62db 100644 --- a/web/react/stores/socket_store.jsx +++ b/web/react/stores/socket_store.jsx @@ -160,7 +160,7 @@ function handleNewPostEvent(msg) { if (window.isActive) { AsyncClient.updateLastViewedAt(true); } - } else { + } else if (UserStore.getCurrentId() !== msg.user_id || post.type !== Constants.POST_TYPE_JOIN_LEAVE) { AsyncClient.getChannel(msg.channel_id); } diff --git a/web/react/utils/async_client.jsx b/web/react/utils/async_client.jsx index b1bc71d54..75dd35e3f 100644 --- a/web/react/utils/async_client.jsx +++ b/web/react/utils/async_client.jsx @@ -132,7 +132,7 @@ export function getChannel(id) { callTracker['getChannel' + id] = utils.getTimestamp(); client.getChannel(id, - function getChannelSuccess(data, textStatus, xhr) { + (data, textStatus, xhr) => { callTracker['getChannel' + id] = 0; if (xhr.status === 304 || !data) { @@ -145,7 +145,7 @@ export function getChannel(id) { member: data.member }); }, - function getChannelFailure(err) { + (err) => { callTracker['getChannel' + id] = 0; dispatchError(err, 'getChannel'); } diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index cda04bf04..0e89b9470 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -98,6 +98,7 @@ module.exports = { POST_LOADING: 'loading', POST_FAILED: 'failed', POST_DELETED: 'deleted', + POST_TYPE_JOIN_LEAVE: 'join_leave', RESERVED_TEAM_NAMES: [ 'www', 'web', |