diff options
-rw-r--r-- | api4/image_test.go | 5 | ||||
-rw-r--r-- | app/notification.go | 81 | ||||
-rw-r--r-- | app/notification_test.go | 45 | ||||
-rw-r--r-- | app/post.go | 20 | ||||
-rw-r--r-- | app/post_test.go | 54 | ||||
-rw-r--r-- | app/team.go | 12 | ||||
-rw-r--r-- | app/team_test.go | 89 | ||||
-rw-r--r-- | i18n/en.json | 4 | ||||
-rw-r--r-- | model/config.go | 2 |
9 files changed, 197 insertions, 115 deletions
diff --git a/api4/image_test.go b/api4/image_test.go index 236d5785d..aa3619cdd 100644 --- a/api4/image_test.go +++ b/api4/image_test.go @@ -37,7 +37,8 @@ func TestGetImage(t *testing.T) { assert.Equal(t, http.StatusNotFound, resp.StatusCode) th.App.UpdateConfig(func(cfg *model.Config) { - cfg.ServiceSettings.ImageProxyType = model.NewString("willnorris/imageproxy") + cfg.ServiceSettings.ImageProxyType = model.NewString("atmos/camo") + cfg.ServiceSettings.ImageProxyOptions = model.NewString("foo") cfg.ServiceSettings.ImageProxyURL = model.NewString("https://proxy.foo.bar") }) @@ -48,5 +49,5 @@ func TestGetImage(t *testing.T) { resp, err = th.Client.HttpClient.Do(r) require.NoError(t, err) assert.Equal(t, http.StatusFound, resp.StatusCode) - assert.Equal(t, "https://proxy.foo.bar//"+originURL, resp.Header.Get("Location")) + assert.Equal(t, "https://proxy.foo.bar/004afe2ef382eb5f30c4490f793f8a8c5b33d8a2/687474703a2f2f666f6f2e6261722f62617a2e676966", resp.Header.Get("Location")) } diff --git a/app/notification.go b/app/notification.go index 1318308f8..e158e08d5 100644 --- a/app/notification.go +++ b/app/notification.go @@ -819,44 +819,52 @@ func GetExplicitMentions(message string, keywords map[string][]string) *Explicit ret.MentionedUserIds[id] = true } } + checkForMention := func(word string) bool { + isMention := false + if word == "@here" { + ret.HereMentioned = true + } + + if word == "@channel" { + ret.ChannelMentioned = true + } + + if word == "@all" { + ret.AllMentioned = true + } + + // Non-case-sensitive check for regular keys + if ids, match := keywords[strings.ToLower(word)]; match { + addMentionedUsers(ids) + isMention = true + } + + // Case-sensitive check for first name + if ids, match := keywords[word]; match { + addMentionedUsers(ids) + isMention = true + } + + return isMention + } processText := func(text string) { for _, word := range strings.FieldsFunc(text, func(c rune) bool { // Split on any whitespace or punctuation that can't be part of an at mention or emoji pattern return !(c == ':' || c == '.' || c == '-' || c == '_' || c == '@' || unicode.IsLetter(c) || unicode.IsNumber(c)) }) { - isMention := false - // skip word with format ':word:' with an assumption that it is an emoji format only if word[0] == ':' && word[len(word)-1] == ':' { continue } - if word == "@here" { - ret.HereMentioned = true - } - - if word == "@channel" { - ret.ChannelMentioned = true - } - - if word == "@all" { - ret.AllMentioned = true - } - - // Non-case-sensitive check for regular keys - if ids, match := keywords[strings.ToLower(word)]; match { - addMentionedUsers(ids) - isMention = true - } - - // Case-sensitive check for first name - if ids, match := keywords[word]; match { - addMentionedUsers(ids) - isMention = true + if checkForMention(word) { + continue } - if isMention { + // remove trailing '.', as that is the end of a sentence + word = strings.TrimSuffix(word, ".") + if checkForMention(word) { continue } @@ -867,27 +875,10 @@ func GetExplicitMentions(message string, keywords map[string][]string) *Explicit }) for _, splitWord := range splitWords { - if splitWord == "@here" { - ret.HereMentioned = true + if checkForMention(splitWord) { + continue } - - if splitWord == "@all" { - ret.AllMentioned = true - } - - if splitWord == "@channel" { - ret.ChannelMentioned = true - } - - // Non-case-sensitive check for regular keys - if ids, match := keywords[strings.ToLower(splitWord)]; match { - addMentionedUsers(ids) - } - - // Case-sensitive check for first name - if ids, match := keywords[splitWord]; match { - addMentionedUsers(ids) - } else if _, ok := systemMentions[splitWord]; !ok && strings.HasPrefix(splitWord, "@") { + if _, ok := systemMentions[splitWord]; !ok && strings.HasPrefix(splitWord, "@") { username := splitWord[1:] ret.OtherPotentialMentions = append(ret.OtherPotentialMentions, username) } diff --git a/app/notification_test.go b/app/notification_test.go index 11f4df685..bd7da3db7 100644 --- a/app/notification_test.go +++ b/app/notification_test.go @@ -109,6 +109,33 @@ func TestGetExplicitMentions(t *testing.T) { }, }, }, + "OnePersonWithPeriodAtEndOfUsername": { + Message: "this is a message for @user.name.", + Keywords: map[string][]string{"@user.name.": {id1}}, + Expected: &ExplicitMentions{ + MentionedUserIds: map[string]bool{ + id1: true, + }, + }, + }, + "OnePersonWithPeriodAtEndOfUsernameButNotSimilarName": { + Message: "this is a message for @user.name.", + Keywords: map[string][]string{"@user.name.": {id1}, "@user.name": {id2}}, + Expected: &ExplicitMentions{ + MentionedUserIds: map[string]bool{ + id1: true, + }, + }, + }, + "OnePersonAtEndOfSentence": { + Message: "this is a message for @user.", + Keywords: map[string][]string{"@user": {id1}}, + Expected: &ExplicitMentions{ + MentionedUserIds: map[string]bool{ + id1: true, + }, + }, + }, "OnePersonWithoutAtMention": { Message: "this is a message for @user", Keywords: map[string][]string{"this": {id1}}, @@ -179,6 +206,24 @@ func TestGetExplicitMentions(t *testing.T) { }, }, }, + "AtUserWithPeriodAtEndOfSentence": { + Message: "this is a message for @user.period.", + Keywords: map[string][]string{"@user.period": {id1}}, + Expected: &ExplicitMentions{ + MentionedUserIds: map[string]bool{ + id1: true, + }, + }, + }, + "UserWithPeriodAtEndOfSentence": { + Message: "this is a message for user.period.", + Keywords: map[string][]string{"user.period": {id1}}, + Expected: &ExplicitMentions{ + MentionedUserIds: map[string]bool{ + id1: true, + }, + }, + }, "PotentialOutOfChannelUser": { Message: "this is an message for @potential and @user", Keywords: map[string][]string{"@user": {id1}}, diff --git a/app/post.go b/app/post.go index 1964bd3cf..a541797fa 100644 --- a/app/post.go +++ b/app/post.go @@ -6,8 +6,6 @@ package app import ( "crypto/hmac" "crypto/sha1" - "crypto/sha256" - "encoding/base64" "encoding/hex" "encoding/json" "fmt" @@ -950,18 +948,6 @@ func (a *App) ImageProxyAdder() func(string) string { mac.Write([]byte(url)) digest := hex.EncodeToString(mac.Sum(nil)) return proxyURL + digest + "/" + hex.EncodeToString([]byte(url)) - case "willnorris/imageproxy": - options := strings.Split(options, "|") - if len(options) > 1 { - mac := hmac.New(sha256.New, []byte(options[1])) - mac.Write([]byte(url)) - digest := base64.URLEncoding.EncodeToString(mac.Sum(nil)) - if options[0] == "" { - return proxyURL + "s" + digest + "/" + url - } - return proxyURL + options[0] + ",s" + digest + "/" + url - } - return proxyURL + options[0] + "/" + url } return url @@ -984,12 +970,6 @@ func (a *App) ImageProxyRemover() (f func(string) string) { } } } - case "willnorris/imageproxy": - if strings.HasPrefix(url, proxyURL) { - if slash := strings.IndexByte(url[len(proxyURL):], '/'); slash >= 0 { - return url[len(proxyURL)+slash+1:] - } - } } return url diff --git a/app/post_test.go b/app/post_test.go index c8ed726b1..ebe973270 100644 --- a/app/post_test.go +++ b/app/post_test.go @@ -210,38 +210,27 @@ func TestImageProxy(t *testing.T) { ImageURL: "http://mydomain.com/myimage", ProxiedImageURL: "https://127.0.0.1/f8dace906d23689e8d5b12c3cefbedbf7b9b72f5/687474703a2f2f6d79646f6d61696e2e636f6d2f6d79696d616765", }, - "willnorris/imageproxy": { - ProxyType: "willnorris/imageproxy", - ProxyURL: "https://127.0.0.1", - ProxyOptions: "x1000", - ImageURL: "http://mydomain.com/myimage", - ProxiedImageURL: "https://127.0.0.1/x1000/http://mydomain.com/myimage", - }, - "willnorris/imageproxy_SameSite": { - ProxyType: "willnorris/imageproxy", + "atmos/camo_SameSite": { + ProxyType: "atmos/camo", ProxyURL: "https://127.0.0.1", + ProxyOptions: "foo", ImageURL: "http://mymattermost.com/myimage", ProxiedImageURL: "http://mymattermost.com/myimage", }, - "willnorris/imageproxy_PathOnly": { - ProxyType: "willnorris/imageproxy", + "atmos/camo_PathOnly": { + ProxyType: "atmos/camo", ProxyURL: "https://127.0.0.1", + ProxyOptions: "foo", ImageURL: "/myimage", ProxiedImageURL: "/myimage", }, - "willnorris/imageproxy_EmptyImageURL": { - ProxyType: "willnorris/imageproxy", + "atmos/camo_EmptyImageURL": { + ProxyType: "atmos/camo", ProxyURL: "https://127.0.0.1", + ProxyOptions: "foo", ImageURL: "", ProxiedImageURL: "", }, - "willnorris/imageproxy_WithSigning": { - ProxyType: "willnorris/imageproxy", - ProxyURL: "https://127.0.0.1", - ProxyOptions: "x1000|foo", - ImageURL: "http://mydomain.com/myimage", - ProxiedImageURL: "https://127.0.0.1/x1000,sbhHVoG5d60UvnNtGh6Iy6x4PaMmnsh8JfZ7JfErKjGU=/http://mydomain.com/myimage", - }, } { t.Run(name, func(t *testing.T) { th.App.UpdateConfig(func(cfg *model.Config) { @@ -356,27 +345,4 @@ func TestMakeOpenGraphURLsAbsolute(t *testing.T) { } }) } -} - -var imageProxyBenchmarkSink *model.Post - -func BenchmarkPostWithProxyRemovedFromImageURLs(b *testing.B) { - th := Setup().InitBasic() - defer th.TearDown() - - th.App.UpdateConfig(func(cfg *model.Config) { - cfg.ServiceSettings.ImageProxyType = model.NewString("willnorris/imageproxy") - cfg.ServiceSettings.ImageProxyOptions = model.NewString("x1000|foo") - cfg.ServiceSettings.ImageProxyURL = model.NewString("https://127.0.0.1") - }) - - post := &model.Post{ - Message: "![foo](http://mydomain.com/myimage)", - } - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - imageProxyBenchmarkSink = th.App.PostWithProxyAddedToImageURLs(post) - } -} +}
\ No newline at end of file diff --git a/app/team.go b/app/team.go index 8e8c29e2a..a15c64c3f 100644 --- a/app/team.go +++ b/app/team.go @@ -302,10 +302,16 @@ func (a *App) joinUserToTeam(team *model.Team, user *model.User) (*model.TeamMem return rtm, true, nil } - if tmr := <-a.Srv.Store.Team().UpdateMember(tm); tmr.Err != nil { - return nil, false, tmr.Err + if membersCount := <-a.Srv.Store.Team().GetActiveMemberCount(tm.TeamId); membersCount.Err != nil { + return nil, false, membersCount.Err + } else if membersCount.Data.(int64) >= int64(*a.Config().TeamSettings.MaxUsersPerTeam) { + return nil, false, model.NewAppError("joinUserToTeam", "app.team.join_user_to_team.max_accounts.app_error", nil, "teamId="+tm.TeamId, http.StatusBadRequest) } else { - return tmr.Data.(*model.TeamMember), false, nil + if tmr := <-a.Srv.Store.Team().UpdateMember(tm); tmr.Err != nil { + return nil, false, tmr.Err + } else { + return tmr.Data.(*model.TeamMember), false, nil + } } } else { // Membership appears to be missing. Lets try to add. diff --git a/app/team_test.go b/app/team_test.go index 7cb20b6f6..a2bf44a57 100644 --- a/app/team_test.go +++ b/app/team_test.go @@ -460,3 +460,92 @@ func TestAddUserToTeamByHashMismatchedInviteId(t *testing.T) { assert.Nil(t, team) assert.Equal(t, "api.user.create_user.signup_link_mismatched_invite_id.app_error", err.Id) } + +func TestJoinUserToTeam(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + + id := model.NewId() + team := &model.Team{ + DisplayName: "dn_" + id, + Name: "name" + id, + Email: "success+" + id + "@simulator.amazonses.com", + Type: model.TEAM_OPEN, + } + + if _, err := th.App.CreateTeam(team); err != nil { + t.Log(err) + t.Fatal("Should create a new team") + } + + maxUsersPerTeam := th.App.Config().TeamSettings.MaxUsersPerTeam + defer func() { + th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.MaxUsersPerTeam = maxUsersPerTeam }) + th.App.SetDefaultRolesBasedOnConfig() + th.App.PermanentDeleteTeam(team) + }() + one := 1 + th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.MaxUsersPerTeam = &one }) + + t.Run("new join", func(t *testing.T) { + user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} + ruser, _ := th.App.CreateUser(&user) + defer th.App.PermanentDeleteUser(&user) + + if _, alreadyAdded, err := th.App.joinUserToTeam(team, ruser); alreadyAdded || err != nil { + t.Fatal("Should return already added equal to false and no error") + } + }) + + t.Run("join when you are a member", func(t *testing.T) { + user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} + ruser, _ := th.App.CreateUser(&user) + defer th.App.PermanentDeleteUser(&user) + + th.App.joinUserToTeam(team, ruser) + if _, alreadyAdded, err := th.App.joinUserToTeam(team, ruser); !alreadyAdded || err != nil { + t.Fatal("Should return already added and no error") + } + }) + + t.Run("re-join after leaving", func(t *testing.T) { + user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} + ruser, _ := th.App.CreateUser(&user) + defer th.App.PermanentDeleteUser(&user) + + th.App.joinUserToTeam(team, ruser) + th.App.LeaveTeam(team, ruser, ruser.Id) + if _, alreadyAdded, err := th.App.joinUserToTeam(team, ruser); alreadyAdded || err != nil { + t.Fatal("Should return already added equal to false and no error") + } + }) + + t.Run("new join with limit problem", func(t *testing.T) { + user1 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} + ruser1, _ := th.App.CreateUser(&user1) + user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} + ruser2, _ := th.App.CreateUser(&user2) + defer th.App.PermanentDeleteUser(&user1) + defer th.App.PermanentDeleteUser(&user2) + th.App.joinUserToTeam(team, ruser1) + if _, _, err := th.App.joinUserToTeam(team, ruser2); err == nil { + t.Fatal("Should fail") + } + }) + + t.Run("re-join alfter leaving with limit problem", func(t *testing.T) { + user1 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} + ruser1, _ := th.App.CreateUser(&user1) + user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} + ruser2, _ := th.App.CreateUser(&user2) + defer th.App.PermanentDeleteUser(&user1) + defer th.App.PermanentDeleteUser(&user2) + + th.App.joinUserToTeam(team, ruser1) + th.App.LeaveTeam(team, ruser1, ruser1.Id) + th.App.joinUserToTeam(team, ruser2) + if _, _, err := th.App.joinUserToTeam(team, ruser1); err == nil { + t.Fatal("Should fail") + } + }) +} diff --git a/i18n/en.json b/i18n/en.json index 41fd9d982..ffdf7e5a3 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -3127,6 +3127,10 @@ "translation": "Invalid {{.Name}} parameter" }, { + "id": "app.team.join_user_to_team.max_accounts.app_error", + "translation": "This team has reached the maximum number of allowed accounts. Contact your systems administrator to set a higher limit." + }, + { "id": "app.channel.create_channel.no_team_id.app_error", "translation": "Must specify the team ID to create a channel" }, diff --git a/model/config.go b/model/config.go index 20011f7cb..7390b4fd9 100644 --- a/model/config.go +++ b/model/config.go @@ -2085,7 +2085,7 @@ func (ss *ServiceSettings) isValid() *AppError { } switch *ss.ImageProxyType { - case "", "willnorris/imageproxy": + case "": case "atmos/camo": if *ss.ImageProxyOptions == "" { return NewAppError("Config.IsValid", "model.config.is_valid.atmos_camo_image_proxy_options.app_error", nil, "", http.StatusBadRequest) |