diff options
-rw-r--r-- | doc/help/Search.md | 12 | ||||
-rw-r--r-- | model/channel.go | 7 | ||||
-rw-r--r-- | model/oauth.go | 3 | ||||
-rw-r--r-- | model/post.go | 7 | ||||
-rw-r--r-- | model/preference.go | 3 | ||||
-rw-r--r-- | model/team.go | 3 | ||||
-rw-r--r-- | model/user.go | 7 | ||||
-rw-r--r-- | web/react/components/sidebar.jsx | 5 | ||||
-rw-r--r-- | web/react/utils/constants.jsx | 3 | ||||
-rw-r--r-- | web/templates/head.html | 2 |
10 files changed, 33 insertions, 19 deletions
diff --git a/doc/help/Search.md b/doc/help/Search.md index 02ecf7d40..51095aac6 100644 --- a/doc/help/Search.md +++ b/doc/help/Search.md @@ -2,14 +2,16 @@ The search box in Mattermost brings back results from any channel of which you’re a member. No results are returned from channels where you are not a member - even if they are open channels. -Some things to know about search: +#### Some things to know about search: - Multiple search terms are connected with “OR” by default. Typing in `Mattermost website` returns results containing “Mattermost” or “website” -- You can use quotes to return search results for exact terms, like `"Mattermost website"` will only return messages containing the entire phrase `"Mattermost website"` and not return messages with only `Mattermost` or `website` -- You can use the `*` character for wildcard searches that match within words. For example: Searching for `rea*` brings back messages containing `reach`, `reason` and other words starting with `rea`. +- Use `from:` to find posts from specific users and `in:` to find posts in specific channels. For example: Searching `Mattermost in:town-square` only returns messages in Town Square that contain `Mattermost` +- Use quotes to return search results for exact terms. For example: Searching `"Mattermost website"` returns messages containing the entire phrase `"Mattermost website"` and not messages containing only `Mattermost` or `website` +- Use the `*` character for wildcard searches that match within words. For example: Searching for `rea*` brings back messages containing `reach`, `reason` and other words starting with `rea`. -#### Limitations +#### Limitations: - Search in Mattermost uses the full text search features included in either a MySQL or Postgres database, which has some limitations - Special cases that are not supported in default full text search, such as searching for IP addresses like `10.100.200.101`, can be added in future as the search feature evolves - - Searches with fewer than three characters will return no results, so for searching in Chinese try adding * to the end of queries + - Two letter searches and common words like "this", "a" and "is" won't appear in search results + - For searching in Chinese try adding * to the end of queries diff --git a/model/channel.go b/model/channel.go index ac54a7e44..0ce09f4bc 100644 --- a/model/channel.go +++ b/model/channel.go @@ -6,6 +6,7 @@ package model import ( "encoding/json" "io" + "unicode/utf8" ) const ( @@ -74,7 +75,7 @@ func (o *Channel) IsValid() *AppError { return NewAppError("Channel.IsValid", "Update at must be a valid time", "id="+o.Id) } - if len(o.DisplayName) > 64 { + if utf8.RuneCountInString(o.DisplayName) > 64 { return NewAppError("Channel.IsValid", "Invalid display name", "id="+o.Id) } @@ -90,11 +91,11 @@ func (o *Channel) IsValid() *AppError { return NewAppError("Channel.IsValid", "Invalid type", "id="+o.Id) } - if len(o.Header) > 1024 { + if utf8.RuneCountInString(o.Header) > 1024 { return NewAppError("Channel.IsValid", "Invalid header", "id="+o.Id) } - if len(o.Purpose) > 128 { + if utf8.RuneCountInString(o.Purpose) > 128 { return NewAppError("Channel.IsValid", "Invalid purpose", "id="+o.Id) } diff --git a/model/oauth.go b/model/oauth.go index 0320e7ec7..67825dd97 100644 --- a/model/oauth.go +++ b/model/oauth.go @@ -7,6 +7,7 @@ import ( "encoding/json" "fmt" "io" + "unicode/utf8" ) type OAuthApp struct { @@ -57,7 +58,7 @@ func (a *OAuthApp) IsValid() *AppError { return NewAppError("OAuthApp.IsValid", "Invalid homepage", "app_id="+a.Id) } - if len(a.Description) > 512 { + if utf8.RuneCountInString(a.Description) > 512 { return NewAppError("OAuthApp.IsValid", "Invalid description", "app_id="+a.Id) } diff --git a/model/post.go b/model/post.go index 11f3ad0d5..e0074b348 100644 --- a/model/post.go +++ b/model/post.go @@ -6,6 +6,7 @@ package model import ( "encoding/json" "io" + "unicode/utf8" ) const ( @@ -94,11 +95,11 @@ func (o *Post) IsValid() *AppError { return NewAppError("Post.IsValid", "Invalid original id", "") } - if len(o.Message) > 4000 { + if utf8.RuneCountInString(o.Message) > 4000 { return NewAppError("Post.IsValid", "Invalid message", "id="+o.Id) } - if len(o.Hashtags) > 1000 { + if utf8.RuneCountInString(o.Hashtags) > 1000 { return NewAppError("Post.IsValid", "Invalid hashtags", "id="+o.Id) } @@ -106,7 +107,7 @@ func (o *Post) IsValid() *AppError { return NewAppError("Post.IsValid", "Invalid type", "id="+o.Type) } - if len(ArrayToJson(o.Filenames)) > 4000 { + if utf8.RuneCountInString(ArrayToJson(o.Filenames)) > 4000 { return NewAppError("Post.IsValid", "Invalid filenames", "id="+o.Id) } diff --git a/model/preference.go b/model/preference.go index 44279f71a..bcd0237f1 100644 --- a/model/preference.go +++ b/model/preference.go @@ -6,6 +6,7 @@ package model import ( "encoding/json" "io" + "unicode/utf8" ) const ( @@ -52,7 +53,7 @@ func (o *Preference) IsValid() *AppError { return NewAppError("Preference.IsValid", "Invalid name", "name="+o.Name) } - if len(o.Value) > 128 { + if utf8.RuneCountInString(o.Value) > 128 { return NewAppError("Preference.IsValid", "Value is too long", "value="+o.Value) } diff --git a/model/team.go b/model/team.go index 5c9cf5a26..e7dde4766 100644 --- a/model/team.go +++ b/model/team.go @@ -9,6 +9,7 @@ import ( "io" "regexp" "strings" + "unicode/utf8" ) const ( @@ -122,7 +123,7 @@ func (o *Team) IsValid(restrictTeamNames bool) *AppError { return NewAppError("Team.IsValid", "Invalid email", "id="+o.Id) } - if len(o.DisplayName) == 0 || len(o.DisplayName) > 64 { + if utf8.RuneCountInString(o.DisplayName) == 0 || utf8.RuneCountInString(o.DisplayName) > 64 { return NewAppError("Team.IsValid", "Invalid name", "id="+o.Id) } diff --git a/model/user.go b/model/user.go index 15016f8dc..871d1bf2d 100644 --- a/model/user.go +++ b/model/user.go @@ -10,6 +10,7 @@ import ( "io" "regexp" "strings" + "unicode/utf8" ) const ( @@ -80,15 +81,15 @@ func (u *User) IsValid() *AppError { return NewAppError("User.IsValid", "Invalid email", "user_id="+u.Id) } - if len(u.Nickname) > 64 { + if utf8.RuneCountInString(u.Nickname) > 64 { return NewAppError("User.IsValid", "Invalid nickname", "user_id="+u.Id) } - if len(u.FirstName) > 64 { + if utf8.RuneCountInString(u.FirstName) > 64 { return NewAppError("User.IsValid", "Invalid first name", "user_id="+u.Id) } - if len(u.LastName) > 64 { + if utf8.RuneCountInString(u.LastName) > 64 { return NewAppError("User.IsValid", "Invalid last name", "user_id="+u.Id) } diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index aab9919a4..8b5f7a381 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -20,6 +20,7 @@ const Utils = require('../utils/utils.jsx'); const Constants = require('../utils/constants.jsx'); const Preferences = Constants.Preferences; const TutorialSteps = Constants.TutorialSteps; +const NotificationPrefs = Constants.NotificationPrefs; const Tooltip = ReactBootstrap.Tooltip; const OverlayTrigger = ReactBootstrap.OverlayTrigger; @@ -76,6 +77,8 @@ export default class Sidebar extends React.Component { if (ch.type === 'D') { chMentionCount = chUnreadCount; chUnreadCount = 0; + } else if (chMember.notify_props && chMember.notify_props.mark_unread === NotificationPrefs.MENTION) { + chUnreadCount = 0; } channelUnreadCounts[ch.id] = {msgs: chUnreadCount, mentions: chMentionCount}; @@ -362,7 +365,7 @@ export default class Sidebar extends React.Component { var unread = false; if (channelMember) { msgCount = unreadCount.msgs + unreadCount.mentions; - unread = (msgCount > 0 && channelMember.notify_props.mark_unread !== 'mention') || channelMember.mention_count > 0; + unread = msgCount > 0 || channelMember.mention_count > 0; } if (unread) { diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index 7d885681a..58ee8e2d2 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -384,5 +384,8 @@ module.exports = { BOTTOM: 1, POST: 2, SIDEBAR_OPEN: 3 + }, + NotificationPrefs: { + MENTION: 'mention' } }; diff --git a/web/templates/head.html b/web/templates/head.html index 24f9862c0..a73e809a7 100644 --- a/web/templates/head.html +++ b/web/templates/head.html @@ -85,7 +85,7 @@ !function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","group","track","ready","alias","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t<analytics.methods.length;t++){var e=analytics.methods[t];analytics[e]=analytics.factory(e)}analytics.load=function(t){var e=document.createElement("script");e.type="text/javascript";e.async=!0;e.src=("https:"===document.location.protocol?"https://":"http://")+"cdn.segment.com/analytics.js/v1/"+t+"/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(e,n)};analytics.SNIPPET_VERSION="3.0.1"; analytics.load(window.mm_config.SegmentDeveloperKey); if (window.mm_user) { - analytics.identify(user.id, { + analytics.identify(window.mm_user.id, { name: window.mm_user.nickname, email: window.mm_user.email, createdAt: window.mm_user.create_at, |