diff options
author | Joram Wilander <jwawilander@gmail.com> | 2015-10-20 08:00:21 -0400 |
---|---|---|
committer | Joram Wilander <jwawilander@gmail.com> | 2015-10-20 08:00:21 -0400 |
commit | 460a82878a93ef040d2c9a1221992ed7aa808d86 (patch) | |
tree | 1a50fabf167714d614d58b1625813b34686d5fd5 /model | |
parent | 7d8e08ccf6211d3df78eb6cfd4a198df77072540 (diff) | |
parent | 995c5a276bb27f50332047684b4d8f4cfc02243b (diff) | |
download | chat-460a82878a93ef040d2c9a1221992ed7aa808d86.tar.gz chat-460a82878a93ef040d2c9a1221992ed7aa808d86.tar.bz2 chat-460a82878a93ef040d2c9a1221992ed7aa808d86.zip |
Merge pull request #1113 from hmhealey/plt716
PLT-716/717 Added from:, in:, and channel: search filters
Diffstat (limited to 'model')
-rw-r--r-- | model/search_params.go | 130 | ||||
-rw-r--r-- | model/search_params_test.go | 70 | ||||
-rw-r--r-- | model/utils.go | 4 |
3 files changed, 202 insertions, 2 deletions
diff --git a/model/search_params.go b/model/search_params.go new file mode 100644 index 000000000..7eeeed10f --- /dev/null +++ b/model/search_params.go @@ -0,0 +1,130 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "strings" +) + +type SearchParams struct { + Terms string + IsHashtag bool + InChannel string + FromUser string +} + +var searchFlags = [...]string{"from", "channel", "in"} + +func splitWords(text string) []string { + words := []string{} + + for _, word := range strings.Fields(text) { + word = puncStart.ReplaceAllString(word, "") + word = puncEnd.ReplaceAllString(word, "") + + if len(word) != 0 { + words = append(words, word) + } + } + + return words +} + +func parseSearchFlags(input []string) ([]string, map[string]string) { + words := []string{} + flags := make(map[string]string) + + skipNextWord := false + for i, word := range input { + if skipNextWord { + skipNextWord = false + continue + } + + isFlag := false + + if colon := strings.Index(word, ":"); colon != -1 { + flag := word[:colon] + value := word[colon+1:] + + for _, searchFlag := range searchFlags { + // check for case insensitive equality + if strings.EqualFold(flag, searchFlag) { + if value != "" { + flags[searchFlag] = value + isFlag = true + } else if i < len(input)-1 { + flags[searchFlag] = input[i+1] + skipNextWord = true + isFlag = true + } + + if isFlag { + break + } + } + } + } + + if !isFlag { + words = append(words, word) + } + } + + return words, flags +} + +func ParseSearchParams(text string) (*SearchParams, *SearchParams) { + words, flags := parseSearchFlags(splitWords(text)) + + hashtagTerms := []string{} + plainTerms := []string{} + + for _, word := range words { + if validHashtag.MatchString(word) { + hashtagTerms = append(hashtagTerms, word) + } else { + plainTerms = append(plainTerms, word) + } + } + + inChannel := flags["channel"] + if inChannel == "" { + inChannel = flags["in"] + } + + fromUser := flags["from"] + + var plainParams *SearchParams + if len(plainTerms) > 0 { + plainParams = &SearchParams{ + Terms: strings.Join(plainTerms, " "), + IsHashtag: false, + InChannel: inChannel, + FromUser: fromUser, + } + } + + var hashtagParams *SearchParams + if len(hashtagTerms) > 0 { + hashtagParams = &SearchParams{ + Terms: strings.Join(hashtagTerms, " "), + IsHashtag: true, + InChannel: inChannel, + FromUser: fromUser, + } + } + + // 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, + } + } + + return plainParams, hashtagParams +} diff --git a/model/search_params_test.go b/model/search_params_test.go new file mode 100644 index 000000000..2eba20f4c --- /dev/null +++ b/model/search_params_test.go @@ -0,0 +1,70 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "testing" +) + +func TestParseSearchFlags(t *testing.T) { + if words, flags := parseSearchFlags(splitWords("")); len(words) != 0 { + t.Fatal("got words from empty input") + } else if len(flags) != 0 { + t.Fatal("got flags from empty input") + } + + if words, flags := parseSearchFlags(splitWords("word")); len(words) != 1 || words[0] != "word" { + t.Fatalf("got incorrect words %v", words) + } else if len(flags) != 0 { + t.Fatalf("got incorrect flags %v", flags) + } + + if words, flags := parseSearchFlags(splitWords("apple banana cherry")); len(words) != 3 || words[0] != "apple" || words[1] != "banana" || words[2] != "cherry" { + t.Fatalf("got incorrect words %v", words) + } else if len(flags) != 0 { + 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" { + 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" { + 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" { + 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" { + t.Fatalf("got incorrect flags %v", flags) + } + + if words, flags := parseSearchFlags(splitWords("fruit: cherry")); len(words) != 2 || words[0] != "fruit:" || words[1] != "cherry" { + t.Fatalf("got incorrect words %v", words) + } else if len(flags) != 0 { + t.Fatalf("got incorrect flags %v", flags) + } + + if words, flags := parseSearchFlags(splitWords("channel:")); len(words) != 1 || words[0] != "channel:" { + t.Fatalf("got incorrect words %v", words) + } else if len(flags) != 0 { + t.Fatalf("got incorrect flags %v", flags) + } + + 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" { + t.Fatalf("got incorrect flags %v", flags) + } +} diff --git a/model/utils.go b/model/utils.go index 269144afc..bb0669df7 100644 --- a/model/utils.go +++ b/model/utils.go @@ -242,10 +242,10 @@ func Etag(parts ...interface{}) string { var validHashtag = regexp.MustCompile(`^(#[A-Za-z]+[A-Za-z0-9_\-]*[A-Za-z0-9])$`) var puncStart = regexp.MustCompile(`^[.,()&$!\[\]{}"':;\\]+`) -var puncEnd = regexp.MustCompile(`[.,()&$#!\[\]{}"':;\\]+$`) +var puncEnd = regexp.MustCompile(`[.,()&$#!\[\]{}"';\\]+$`) func ParseHashtags(text string) (string, string) { - words := strings.Split(strings.Replace(text, "\n", " ", -1), " ") + words := strings.Fields(text) hashtagString := "" plainString := "" |