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  }