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