From 2383d5dd37d5ebf28c2576fd495a8a7f02f78901 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Fri, 23 Oct 2015 17:28:02 -0400 Subject: Changed post searching to allow searching by multiple users/channels --- model/post_list.go | 9 +++++ model/post_list_test.go | 34 ++++++++++++++++ model/search_params.go | 95 +++++++++++++++++++++++++++------------------ model/search_params_test.go | 17 +++++--- 4 files changed, 113 insertions(+), 42 deletions(-) (limited to 'model') 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..6b665f5a0 100644 --- a/model/search_params.go +++ b/model/search_params.go @@ -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,77 @@ 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{} - fromUser := flags["from"] + for _, flagPair := range flags { + flag := flagPair[0] + value := flagPair[1] - var plainParams *SearchParams - if len(plainTerms) > 0 { - plainParams = &SearchParams{ - Terms: strings.Join(plainTerms, " "), - IsHashtag: false, - InChannel: inChannel, - FromUser: fromUser, + if flag == "in" || flag == "channel" { + inChannels = append(inChannels, value) + } else if flag == "from" { + fromUsers = append(fromUsers, value) } } - var hashtagParams *SearchParams - if len(hashtagTerms) > 0 { - hashtagParams = &SearchParams{ - Terms: strings.Join(hashtagTerms, " "), - IsHashtag: true, - InChannel: inChannel, - FromUser: fromUser, - } + if len(inChannels) == 0 { + inChannels = append(inChannels, "") + } + if len(fromUsers) == 0 { + fromUsers = append(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, + paramsList := []*SearchParams{} + + for _, inChannel := range inChannels { + for _, fromUser := range fromUsers { + if len(plainTerms) > 0 { + paramsList = append(paramsList, &SearchParams{ + Terms: plainTerms, + IsHashtag: false, + InChannel: inChannel, + FromUser: fromUser, + }) + } + + if len(hashtagTerms) > 0 { + paramsList = append(paramsList, &SearchParams{ + Terms: hashtagTerms, + IsHashtag: true, + InChannel: inChannel, + FromUser: fromUser, + }) + } + + // special case for when no terms are specified but we still have a filter + if len(plainTerms) == 0 && len(hashtagTerms) == 0 { + paramsList = append(paramsList, &SearchParams{ + Terms: "", + IsHashtag: true, + InChannel: inChannel, + FromUser: fromUser, + }) + } } } - 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) } } -- cgit v1.2.3-1-g7c22 From c6bbebbf6f5bc6fd1b4af222e7043cee0dd24f1f Mon Sep 17 00:00:00 2001 From: Florian Orben Date: Sun, 25 Oct 2015 23:55:50 +0100 Subject: Mattermost can not send message start with slash resolves #827 --- model/command.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'model') diff --git a/model/command.go b/model/command.go index 2b26aad1c..5aec5f534 100644 --- a/model/command.go +++ b/model/command.go @@ -9,7 +9,8 @@ import ( ) const ( - RESP_EXECUTED = "executed" + RESP_EXECUTED = "executed" + RESP_NOT_IMPLEMENTED = "not implemented" ) type Command struct { -- cgit v1.2.3-1-g7c22 From 663bec814767fa9c92e7ab2c706c0fe4c0432cf1 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Mon, 26 Oct 2015 11:45:03 -0400 Subject: Moved logic for searching for posts by multiple users/channels into the sql query --- model/search_params.go | 67 +++++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 39 deletions(-) (limited to 'model') diff --git a/model/search_params.go b/model/search_params.go index 6b665f5a0..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"} @@ -106,45 +106,34 @@ func ParseSearchParams(text string) []*SearchParams { } } - if len(inChannels) == 0 { - inChannels = append(inChannels, "") - } - if len(fromUsers) == 0 { - fromUsers = append(fromUsers, "") - } - paramsList := []*SearchParams{} - for _, inChannel := range inChannels { - for _, fromUser := range fromUsers { - if len(plainTerms) > 0 { - paramsList = append(paramsList, &SearchParams{ - Terms: plainTerms, - IsHashtag: false, - InChannel: inChannel, - FromUser: fromUser, - }) - } + if len(plainTerms) > 0 { + paramsList = append(paramsList, &SearchParams{ + Terms: plainTerms, + IsHashtag: false, + InChannels: inChannels, + FromUsers: fromUsers, + }) + } - if len(hashtagTerms) > 0 { - paramsList = append(paramsList, &SearchParams{ - Terms: hashtagTerms, - IsHashtag: true, - InChannel: inChannel, - FromUser: fromUser, - }) - } + if len(hashtagTerms) > 0 { + 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 len(plainTerms) == 0 && len(hashtagTerms) == 0 { - paramsList = append(paramsList, &SearchParams{ - Terms: "", - IsHashtag: true, - InChannel: inChannel, - FromUser: fromUser, - }) - } - } + // special case for when no terms are specified but we still have a filter + if len(plainTerms) == 0 && len(hashtagTerms) == 0 { + paramsList = append(paramsList, &SearchParams{ + Terms: "", + IsHashtag: true, + InChannels: inChannels, + FromUsers: fromUsers, + }) } return paramsList -- cgit v1.2.3-1-g7c22 From c94388042b684ae3c552f97505fdb67903db20ba Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Mon, 26 Oct 2015 15:10:17 -0400 Subject: Parse incoming webhook requsets into model instead of string map --- model/incoming_webhook.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'model') diff --git a/model/incoming_webhook.go b/model/incoming_webhook.go index 9b9969b96..35861c0e0 100644 --- a/model/incoming_webhook.go +++ b/model/incoming_webhook.go @@ -23,6 +23,14 @@ type IncomingWebhook struct { TeamId string `json:"team_id"` } +type IncomingWebhookRequest struct { + Text string `json:"text"` + Username string `json:"username"` + IconURL string `json:"icon_url"` + IconEmoji string `json:"icon_emoji"` + ChannelName string `json:"channel"` +} + func (o *IncomingWebhook) ToJson() string { b, err := json.Marshal(o) if err != nil { @@ -104,3 +112,14 @@ func (o *IncomingWebhook) PreSave() { func (o *IncomingWebhook) PreUpdate() { o.UpdateAt = GetMillis() } + +func IncomingWebhookRequestFromJson(data io.Reader) *IncomingWebhookRequest { + decoder := json.NewDecoder(data) + var o IncomingWebhookRequest + err := decoder.Decode(&o) + if err == nil { + return &o + } else { + return nil + } +} -- cgit v1.2.3-1-g7c22 From 12399dd43c0ba57a879e4383f13a0fd4ed3350ae Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Mon, 26 Oct 2015 15:11:06 -0400 Subject: Remove unused iconemoji field --- model/incoming_webhook.go | 1 - 1 file changed, 1 deletion(-) (limited to 'model') diff --git a/model/incoming_webhook.go b/model/incoming_webhook.go index 35861c0e0..be1984244 100644 --- a/model/incoming_webhook.go +++ b/model/incoming_webhook.go @@ -27,7 +27,6 @@ type IncomingWebhookRequest struct { Text string `json:"text"` Username string `json:"username"` IconURL string `json:"icon_url"` - IconEmoji string `json:"icon_emoji"` ChannelName string `json:"channel"` } -- cgit v1.2.3-1-g7c22