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  }