github.com/psyb0t/mattermost-server@v4.6.1-0.20180125161845-5503a1351abf+incompatible/model/search_params.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package model 5 6 import ( 7 "encoding/json" 8 "regexp" 9 "strings" 10 ) 11 12 var searchTermPuncStart = regexp.MustCompile(`^[^\pL\d\s#"]+`) 13 var searchTermPuncEnd = regexp.MustCompile(`[^\pL\d\s*"]+$`) 14 15 type SearchParams struct { 16 Terms string 17 IsHashtag bool 18 InChannels []string 19 FromUsers []string 20 OrTerms bool 21 } 22 23 func (o *SearchParams) ToJson() string { 24 b, err := json.Marshal(o) 25 if err != nil { 26 return "" 27 } else { 28 return string(b) 29 } 30 } 31 32 var searchFlags = [...]string{"from", "channel", "in"} 33 34 func splitWords(text string) []string { 35 words := []string{} 36 37 foundQuote := false 38 location := 0 39 for i, char := range text { 40 if char == '"' { 41 if foundQuote { 42 // Grab the quoted section 43 word := text[location : i+1] 44 words = append(words, word) 45 foundQuote = false 46 location = i + 1 47 } else { 48 words = append(words, strings.Fields(text[location:i])...) 49 foundQuote = true 50 location = i 51 } 52 } 53 } 54 55 words = append(words, strings.Fields(text[location:])...) 56 57 return words 58 } 59 60 func parseSearchFlags(input []string) ([]string, [][2]string) { 61 words := []string{} 62 flags := [][2]string{} 63 64 skipNextWord := false 65 for i, word := range input { 66 if skipNextWord { 67 skipNextWord = false 68 continue 69 } 70 71 isFlag := false 72 73 if colon := strings.Index(word, ":"); colon != -1 { 74 flag := word[:colon] 75 value := word[colon+1:] 76 77 for _, searchFlag := range searchFlags { 78 // check for case insensitive equality 79 if strings.EqualFold(flag, searchFlag) { 80 if value != "" { 81 flags = append(flags, [2]string{searchFlag, value}) 82 isFlag = true 83 } else if i < len(input)-1 { 84 flags = append(flags, [2]string{searchFlag, input[i+1]}) 85 skipNextWord = true 86 isFlag = true 87 } 88 89 if isFlag { 90 break 91 } 92 } 93 } 94 } 95 96 if !isFlag { 97 // trim off surrounding punctuation (note that we leave trailing asterisks to allow wildcards) 98 word = searchTermPuncStart.ReplaceAllString(word, "") 99 word = searchTermPuncEnd.ReplaceAllString(word, "") 100 101 // and remove extra pound #s 102 word = hashtagStart.ReplaceAllString(word, "#") 103 104 if len(word) != 0 { 105 words = append(words, word) 106 } 107 } 108 } 109 110 return words, flags 111 } 112 113 func ParseSearchParams(text string) []*SearchParams { 114 words, flags := parseSearchFlags(splitWords(text)) 115 116 hashtagTermList := []string{} 117 plainTermList := []string{} 118 119 for _, word := range words { 120 if validHashtag.MatchString(word) { 121 hashtagTermList = append(hashtagTermList, word) 122 } else { 123 plainTermList = append(plainTermList, word) 124 } 125 } 126 127 hashtagTerms := strings.Join(hashtagTermList, " ") 128 plainTerms := strings.Join(plainTermList, " ") 129 130 inChannels := []string{} 131 fromUsers := []string{} 132 133 for _, flagPair := range flags { 134 flag := flagPair[0] 135 value := flagPair[1] 136 137 if flag == "in" || flag == "channel" { 138 inChannels = append(inChannels, value) 139 } else if flag == "from" { 140 fromUsers = append(fromUsers, value) 141 } 142 } 143 144 paramsList := []*SearchParams{} 145 146 if len(plainTerms) > 0 { 147 paramsList = append(paramsList, &SearchParams{ 148 Terms: plainTerms, 149 IsHashtag: false, 150 InChannels: inChannels, 151 FromUsers: fromUsers, 152 }) 153 } 154 155 if len(hashtagTerms) > 0 { 156 paramsList = append(paramsList, &SearchParams{ 157 Terms: hashtagTerms, 158 IsHashtag: true, 159 InChannels: inChannels, 160 FromUsers: fromUsers, 161 }) 162 } 163 164 // special case for when no terms are specified but we still have a filter 165 if len(plainTerms) == 0 && len(hashtagTerms) == 0 && (len(inChannels) != 0 || len(fromUsers) != 0) { 166 paramsList = append(paramsList, &SearchParams{ 167 Terms: "", 168 IsHashtag: false, 169 InChannels: inChannels, 170 FromUsers: fromUsers, 171 }) 172 } 173 174 return paramsList 175 }