summaryrefslogtreecommitdiffstats
path: root/model
diff options
context:
space:
mode:
Diffstat (limited to 'model')
-rw-r--r--model/access.go2
-rw-r--r--model/config.go16
-rw-r--r--model/search_params.go130
-rw-r--r--model/search_params_test.go70
-rw-r--r--model/utils.go4
5 files changed, 211 insertions, 11 deletions
diff --git a/model/access.go b/model/access.go
index 89a1271c1..6c9254004 100644
--- a/model/access.go
+++ b/model/access.go
@@ -16,7 +16,7 @@ const (
type AccessData struct {
AuthCode string `json:"auth_code"`
- Token string `json"token"`
+ Token string `json:"token"`
RefreshToken string `json:"refresh_token"`
RedirectUri string `json:"redirect_uri"`
}
diff --git a/model/config.go b/model/config.go
index ef76877c2..3a39df2f1 100644
--- a/model/config.go
+++ b/model/config.go
@@ -185,8 +185,8 @@ func (o *Config) IsValid() *AppError {
return NewAppError("Config.IsValid", "Invalid maximum users per team for team settings. Must be a positive number.", "")
}
- if len(o.SqlSettings.AtRestEncryptKey) != 32 {
- return NewAppError("Config.IsValid", "Invalid at rest encrypt key for SQL settings. Must be 32 chars.", "")
+ if len(o.SqlSettings.AtRestEncryptKey) < 32 {
+ return NewAppError("Config.IsValid", "Invalid at rest encrypt key for SQL settings. Must be 32 chars or more.", "")
}
if !(o.SqlSettings.DriverName == DATABASE_DRIVER_MYSQL || o.SqlSettings.DriverName == DATABASE_DRIVER_POSTGRES) {
@@ -233,20 +233,20 @@ func (o *Config) IsValid() *AppError {
return NewAppError("Config.IsValid", "Invalid thumbnail width for file settings. Must be a positive number.", "")
}
- if len(o.FileSettings.PublicLinkSalt) != 32 {
- return NewAppError("Config.IsValid", "Invalid public link salt for file settings. Must be 32 chars.", "")
+ if len(o.FileSettings.PublicLinkSalt) < 32 {
+ return NewAppError("Config.IsValid", "Invalid public link salt for file settings. Must be 32 chars or more.", "")
}
if !(o.EmailSettings.ConnectionSecurity == CONN_SECURITY_NONE || o.EmailSettings.ConnectionSecurity == CONN_SECURITY_TLS || o.EmailSettings.ConnectionSecurity == CONN_SECURITY_STARTTLS) {
return NewAppError("Config.IsValid", "Invalid connection security for email settings. Must be '', 'TLS', or 'STARTTLS'", "")
}
- if len(o.EmailSettings.InviteSalt) != 32 {
- return NewAppError("Config.IsValid", "Invalid invite salt for email settings. Must be 32 chars.", "")
+ if len(o.EmailSettings.InviteSalt) < 32 {
+ return NewAppError("Config.IsValid", "Invalid invite salt for email settings. Must be 32 chars or more.", "")
}
- if len(o.EmailSettings.PasswordResetSalt) != 32 {
- return NewAppError("Config.IsValid", "Invalid password reset salt for email settings. Must be 32 chars.", "")
+ if len(o.EmailSettings.PasswordResetSalt) < 32 {
+ return NewAppError("Config.IsValid", "Invalid password reset salt for email settings. Must be 32 chars or more.", "")
}
if o.RateLimitSettings.MemoryStoreSize <= 0 {
diff --git a/model/search_params.go b/model/search_params.go
new file mode 100644
index 000000000..7eeeed10f
--- /dev/null
+++ b/model/search_params.go
@@ -0,0 +1,130 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+import (
+ "strings"
+)
+
+type SearchParams struct {
+ Terms string
+ IsHashtag bool
+ InChannel string
+ FromUser string
+}
+
+var searchFlags = [...]string{"from", "channel", "in"}
+
+func splitWords(text string) []string {
+ words := []string{}
+
+ for _, word := range strings.Fields(text) {
+ word = puncStart.ReplaceAllString(word, "")
+ word = puncEnd.ReplaceAllString(word, "")
+
+ if len(word) != 0 {
+ words = append(words, word)
+ }
+ }
+
+ return words
+}
+
+func parseSearchFlags(input []string) ([]string, map[string]string) {
+ words := []string{}
+ flags := make(map[string]string)
+
+ skipNextWord := false
+ for i, word := range input {
+ if skipNextWord {
+ skipNextWord = false
+ continue
+ }
+
+ isFlag := false
+
+ if colon := strings.Index(word, ":"); colon != -1 {
+ flag := word[:colon]
+ value := word[colon+1:]
+
+ for _, searchFlag := range searchFlags {
+ // check for case insensitive equality
+ if strings.EqualFold(flag, searchFlag) {
+ if value != "" {
+ flags[searchFlag] = value
+ isFlag = true
+ } else if i < len(input)-1 {
+ flags[searchFlag] = input[i+1]
+ skipNextWord = true
+ isFlag = true
+ }
+
+ if isFlag {
+ break
+ }
+ }
+ }
+ }
+
+ if !isFlag {
+ words = append(words, word)
+ }
+ }
+
+ return words, flags
+}
+
+func ParseSearchParams(text string) (*SearchParams, *SearchParams) {
+ words, flags := parseSearchFlags(splitWords(text))
+
+ hashtagTerms := []string{}
+ plainTerms := []string{}
+
+ for _, word := range words {
+ if validHashtag.MatchString(word) {
+ hashtagTerms = append(hashtagTerms, word)
+ } else {
+ plainTerms = append(plainTerms, word)
+ }
+ }
+
+ inChannel := flags["channel"]
+ if inChannel == "" {
+ inChannel = flags["in"]
+ }
+
+ fromUser := flags["from"]
+
+ var plainParams *SearchParams
+ if len(plainTerms) > 0 {
+ plainParams = &SearchParams{
+ Terms: strings.Join(plainTerms, " "),
+ IsHashtag: false,
+ InChannel: inChannel,
+ FromUser: fromUser,
+ }
+ }
+
+ var hashtagParams *SearchParams
+ if len(hashtagTerms) > 0 {
+ hashtagParams = &SearchParams{
+ Terms: strings.Join(hashtagTerms, " "),
+ IsHashtag: true,
+ InChannel: inChannel,
+ FromUser: fromUser,
+ }
+ }
+
+ // special case for when no terms are specified but we still have a filter
+ if plainParams == nil && hashtagParams == nil && (inChannel != "" || fromUser != "") {
+ plainParams = &SearchParams{
+ Terms: "",
+ IsHashtag: false,
+ InChannel: inChannel,
+ FromUser: fromUser,
+ }
+ }
+
+ return plainParams, hashtagParams
+}
diff --git a/model/search_params_test.go b/model/search_params_test.go
new file mode 100644
index 000000000..2eba20f4c
--- /dev/null
+++ b/model/search_params_test.go
@@ -0,0 +1,70 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+import (
+ "testing"
+)
+
+func TestParseSearchFlags(t *testing.T) {
+ if words, flags := parseSearchFlags(splitWords("")); len(words) != 0 {
+ t.Fatal("got words from empty input")
+ } else if len(flags) != 0 {
+ t.Fatal("got flags from empty input")
+ }
+
+ if words, flags := parseSearchFlags(splitWords("word")); len(words) != 1 || words[0] != "word" {
+ t.Fatalf("got incorrect words %v", words)
+ } else if len(flags) != 0 {
+ t.Fatalf("got incorrect flags %v", flags)
+ }
+
+ if words, flags := parseSearchFlags(splitWords("apple banana cherry")); len(words) != 3 || words[0] != "apple" || words[1] != "banana" || words[2] != "cherry" {
+ t.Fatalf("got incorrect words %v", words)
+ } else if len(flags) != 0 {
+ t.Fatalf("got incorrect flags %v", flags)
+ }
+
+ if words, flags := parseSearchFlags(splitWords("apple banana from:chan")); len(words) != 2 || words[0] != "apple" || words[1] != "banana" {
+ t.Fatalf("got incorrect words %v", words)
+ } else if len(flags) != 1 || flags["from"] != "chan" {
+ t.Fatalf("got incorrect flags %v", flags)
+ }
+
+ if words, flags := parseSearchFlags(splitWords("apple banana from: chan")); len(words) != 2 || words[0] != "apple" || words[1] != "banana" {
+ t.Fatalf("got incorrect words %v", words)
+ } else if len(flags) != 1 || flags["from"] != "chan" {
+ t.Fatalf("got incorrect flags %v", flags)
+ }
+
+ if words, flags := parseSearchFlags(splitWords("apple banana in: chan")); len(words) != 2 || words[0] != "apple" || words[1] != "banana" {
+ t.Fatalf("got incorrect words %v", words)
+ } else if len(flags) != 1 || flags["in"] != "chan" {
+ t.Fatalf("got incorrect flags %v", flags)
+ }
+
+ if words, flags := parseSearchFlags(splitWords("apple banana channel:chan")); len(words) != 2 || words[0] != "apple" || words[1] != "banana" {
+ t.Fatalf("got incorrect words %v", words)
+ } else if len(flags) != 1 || flags["channel"] != "chan" {
+ t.Fatalf("got incorrect flags %v", flags)
+ }
+
+ if words, flags := parseSearchFlags(splitWords("fruit: cherry")); len(words) != 2 || words[0] != "fruit:" || words[1] != "cherry" {
+ t.Fatalf("got incorrect words %v", words)
+ } else if len(flags) != 0 {
+ t.Fatalf("got incorrect flags %v", flags)
+ }
+
+ if words, flags := parseSearchFlags(splitWords("channel:")); len(words) != 1 || words[0] != "channel:" {
+ t.Fatalf("got incorrect words %v", words)
+ } else if len(flags) != 0 {
+ t.Fatalf("got incorrect flags %v", flags)
+ }
+
+ if words, flags := parseSearchFlags(splitWords("channel: first in: second from:")); len(words) != 1 || words[0] != "from:" {
+ t.Fatalf("got incorrect words %v", words)
+ } else if len(flags) != 2 || flags["channel"] != "first" || flags["in"] != "second" {
+ t.Fatalf("got incorrect flags %v", flags)
+ }
+}
diff --git a/model/utils.go b/model/utils.go
index 269144afc..bb0669df7 100644
--- a/model/utils.go
+++ b/model/utils.go
@@ -242,10 +242,10 @@ func Etag(parts ...interface{}) string {
var validHashtag = regexp.MustCompile(`^(#[A-Za-z]+[A-Za-z0-9_\-]*[A-Za-z0-9])$`)
var puncStart = regexp.MustCompile(`^[.,()&$!\[\]{}"':;\\]+`)
-var puncEnd = regexp.MustCompile(`[.,()&$#!\[\]{}"':;\\]+$`)
+var puncEnd = regexp.MustCompile(`[.,()&$#!\[\]{}"';\\]+$`)
func ParseHashtags(text string) (string, string) {
- words := strings.Split(strings.Replace(text, "\n", " ", -1), " ")
+ words := strings.Fields(text)
hashtagString := ""
plainString := ""