github.com/wgh-/mattermost-server@v4.8.0-rc2+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, _ := json.Marshal(o) 25 return string(b) 26 } 27 28 var searchFlags = [...]string{"from", "channel", "in"} 29 30 func splitWords(text string) []string { 31 words := []string{} 32 33 foundQuote := false 34 location := 0 35 for i, char := range text { 36 if char == '"' { 37 if foundQuote { 38 // Grab the quoted section 39 word := text[location : i+1] 40 words = append(words, word) 41 foundQuote = false 42 location = i + 1 43 } else { 44 words = append(words, strings.Fields(text[location:i])...) 45 foundQuote = true 46 location = i 47 } 48 } 49 } 50 51 words = append(words, strings.Fields(text[location:])...) 52 53 return words 54 } 55 56 func parseSearchFlags(input []string) ([]string, [][2]string) { 57 words := []string{} 58 flags := [][2]string{} 59 60 skipNextWord := false 61 for i, word := range input { 62 if skipNextWord { 63 skipNextWord = false 64 continue 65 } 66 67 isFlag := false 68 69 if colon := strings.Index(word, ":"); colon != -1 { 70 flag := word[:colon] 71 value := word[colon+1:] 72 73 for _, searchFlag := range searchFlags { 74 // check for case insensitive equality 75 if strings.EqualFold(flag, searchFlag) { 76 if value != "" { 77 flags = append(flags, [2]string{searchFlag, value}) 78 isFlag = true 79 } else if i < len(input)-1 { 80 flags = append(flags, [2]string{searchFlag, input[i+1]}) 81 skipNextWord = true 82 isFlag = true 83 } 84 85 if isFlag { 86 break 87 } 88 } 89 } 90 } 91 92 if !isFlag { 93 // trim off surrounding punctuation (note that we leave trailing asterisks to allow wildcards) 94 word = searchTermPuncStart.ReplaceAllString(word, "") 95 word = searchTermPuncEnd.ReplaceAllString(word, "") 96 97 // and remove extra pound #s 98 word = hashtagStart.ReplaceAllString(word, "#") 99 100 if len(word) != 0 { 101 words = append(words, word) 102 } 103 } 104 } 105 106 return words, flags 107 } 108 109 func ParseSearchParams(text string) []*SearchParams { 110 words, flags := parseSearchFlags(splitWords(text)) 111 112 hashtagTermList := []string{} 113 plainTermList := []string{} 114 115 for _, word := range words { 116 if validHashtag.MatchString(word) { 117 hashtagTermList = append(hashtagTermList, word) 118 } else { 119 plainTermList = append(plainTermList, word) 120 } 121 } 122 123 hashtagTerms := strings.Join(hashtagTermList, " ") 124 plainTerms := strings.Join(plainTermList, " ") 125 126 inChannels := []string{} 127 fromUsers := []string{} 128 129 for _, flagPair := range flags { 130 flag := flagPair[0] 131 value := flagPair[1] 132 133 if flag == "in" || flag == "channel" { 134 inChannels = append(inChannels, value) 135 } else if flag == "from" { 136 fromUsers = append(fromUsers, value) 137 } 138 } 139 140 paramsList := []*SearchParams{} 141 142 if len(plainTerms) > 0 { 143 paramsList = append(paramsList, &SearchParams{ 144 Terms: plainTerms, 145 IsHashtag: false, 146 InChannels: inChannels, 147 FromUsers: fromUsers, 148 }) 149 } 150 151 if len(hashtagTerms) > 0 { 152 paramsList = append(paramsList, &SearchParams{ 153 Terms: hashtagTerms, 154 IsHashtag: true, 155 InChannels: inChannels, 156 FromUsers: fromUsers, 157 }) 158 } 159 160 // special case for when no terms are specified but we still have a filter 161 if len(plainTerms) == 0 && len(hashtagTerms) == 0 && (len(inChannels) != 0 || len(fromUsers) != 0) { 162 paramsList = append(paramsList, &SearchParams{ 163 Terms: "", 164 IsHashtag: false, 165 InChannels: inChannels, 166 FromUsers: fromUsers, 167 }) 168 } 169 170 return paramsList 171 }