Merge remote-tracking branch 'upstream/release-5.1' into release-5.1-daily-merge-20180710
Этот коммит содержится в:
@@ -17,6 +17,7 @@ import (
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/throttled/throttled"
|
||||
|
||||
"github.com/mattermost/mattermost-server/einterfaces"
|
||||
ejobs "github.com/mattermost/mattermost-server/einterfaces/jobs"
|
||||
@@ -46,7 +47,8 @@ type App struct {
|
||||
IsPluginSandboxSupported bool
|
||||
pluginStatuses map[string]*model.PluginStatus
|
||||
|
||||
EmailBatching *EmailBatchingJob
|
||||
EmailBatching *EmailBatchingJob
|
||||
EmailRateLimiter *throttled.GCRARateLimiter
|
||||
|
||||
Hubs []*Hub
|
||||
HubsStopCheckingForDeadlock chan bool
|
||||
@@ -185,6 +187,10 @@ func New(options ...Option) (outApp *App, outErr error) {
|
||||
|
||||
})
|
||||
|
||||
if err := app.SetupInviteEmailRateLimiting(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mlog.Info("Server is initializing...")
|
||||
|
||||
app.initEnterprise()
|
||||
|
||||
@@ -206,6 +206,10 @@ func (me *TestHelper) CreateChannel(team *model.Team) *model.Channel {
|
||||
return me.createChannel(team, model.CHANNEL_OPEN)
|
||||
}
|
||||
|
||||
func (me *TestHelper) CreatePrivateChannel(team *model.Team) *model.Channel {
|
||||
return me.createChannel(team, model.CHANNEL_PRIVATE)
|
||||
}
|
||||
|
||||
func (me *TestHelper) createChannel(team *model.Team, channelType string) *model.Channel {
|
||||
id := model.NewId()
|
||||
|
||||
@@ -266,6 +270,20 @@ func (me *TestHelper) CreateDmChannel(user *model.User) *model.Channel {
|
||||
return channel
|
||||
}
|
||||
|
||||
func (me *TestHelper) CreateGroupChannel(user1 *model.User, user2 *model.User) *model.Channel {
|
||||
utils.DisableDebugLogForTest()
|
||||
var err *model.AppError
|
||||
var channel *model.Channel
|
||||
if channel, err = me.App.CreateGroupChannel([]string{me.BasicUser.Id, user1.Id, user2.Id}, me.BasicUser.Id); err != nil {
|
||||
mlog.Error(err.Error())
|
||||
|
||||
time.Sleep(time.Second)
|
||||
panic(err)
|
||||
}
|
||||
utils.EnableDebugLogForTest()
|
||||
return channel
|
||||
}
|
||||
|
||||
func (me *TestHelper) CreatePost(channel *model.Channel) *model.Post {
|
||||
id := model.NewId()
|
||||
|
||||
|
||||
@@ -340,6 +340,30 @@ func (a *App) createGroupChannel(userIds []string, creatorId string) (*model.Cha
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) GetGroupChannel(userIds []string) (*model.Channel, *model.AppError) {
|
||||
if len(userIds) > model.CHANNEL_GROUP_MAX_USERS || len(userIds) < model.CHANNEL_GROUP_MIN_USERS {
|
||||
return nil, model.NewAppError("GetGroupChannel", "api.channel.create_group.bad_size.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
var users []*model.User
|
||||
if result := <-a.Srv.Store.User().GetProfileByIds(userIds, true); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
users = result.Data.([]*model.User)
|
||||
}
|
||||
|
||||
if len(users) != len(userIds) {
|
||||
return nil, model.NewAppError("GetGroupChannel", "api.channel.create_group.bad_user.app_error", nil, "user_ids="+model.ArrayToJson(userIds), http.StatusBadRequest)
|
||||
}
|
||||
|
||||
channel, err := a.GetChannelByName(model.GetGroupNameFromUserIds(userIds), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return channel, nil
|
||||
}
|
||||
|
||||
func (a *App) UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppError) {
|
||||
if result := <-a.Srv.Store.Channel().Update(channel); result.Err != nil {
|
||||
return nil, result.Err
|
||||
|
||||
@@ -40,11 +40,25 @@ func (me *HeaderProvider) DoCommand(a *App, args *model.CommandArgs, message str
|
||||
return &model.CommandResponse{Text: args.T("api.command_channel_header.channel.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
if channel.Type == model.CHANNEL_OPEN && !a.SessionHasPermissionToChannel(args.Session, args.ChannelId, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES) {
|
||||
return &model.CommandResponse{Text: args.T("api.command_channel_header.permission.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
switch channel.Type {
|
||||
case model.CHANNEL_OPEN:
|
||||
if !a.SessionHasPermissionToChannel(args.Session, args.ChannelId, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES) {
|
||||
return &model.CommandResponse{Text: args.T("api.command_channel_header.permission.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
if channel.Type == model.CHANNEL_PRIVATE && !a.SessionHasPermissionToChannel(args.Session, args.ChannelId, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES) {
|
||||
case model.CHANNEL_PRIVATE:
|
||||
if !a.SessionHasPermissionToChannel(args.Session, args.ChannelId, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES) {
|
||||
return &model.CommandResponse{Text: args.T("api.command_channel_header.permission.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
case model.CHANNEL_GROUP, model.CHANNEL_DIRECT:
|
||||
// Modifying the header is not linked to any specific permission for group/dm channels, so just check for membership.
|
||||
channelMember, err := a.GetChannelMember(args.ChannelId, args.Session.UserId)
|
||||
if err != nil || channelMember == nil {
|
||||
return &model.CommandResponse{Text: args.T("api.command_channel_header.permission.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
default:
|
||||
return &model.CommandResponse{Text: args.T("api.command_channel_header.permission.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ func TestHeaderProviderDoCommand(t *testing.T) {
|
||||
defer th.TearDown()
|
||||
|
||||
hp := HeaderProvider{}
|
||||
|
||||
// Try a public channel *with* permission.
|
||||
args := &model.CommandArgs{
|
||||
T: func(s string, args ...interface{}) string { return s },
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
@@ -25,4 +27,84 @@ func TestHeaderProviderDoCommand(t *testing.T) {
|
||||
actual := hp.DoCommand(th.App, args, msg).Text
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
// Try a public channel *without* permission.
|
||||
args = &model.CommandArgs{
|
||||
T: func(s string, args ...interface{}) string { return s },
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}},
|
||||
}
|
||||
|
||||
actual := hp.DoCommand(th.App, args, "hello").Text
|
||||
assert.Equal(t, "api.command_channel_header.permission.app_error", actual)
|
||||
|
||||
// Try a private channel *with* permission.
|
||||
privateChannel := th.CreatePrivateChannel(th.BasicTeam)
|
||||
|
||||
args = &model.CommandArgs{
|
||||
T: func(s string, args ...interface{}) string { return s },
|
||||
ChannelId: privateChannel.Id,
|
||||
Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: model.TEAM_USER_ROLE_ID}}},
|
||||
}
|
||||
|
||||
actual = hp.DoCommand(th.App, args, "hello").Text
|
||||
assert.Equal(t, "", actual)
|
||||
|
||||
// Try a private channel *without* permission.
|
||||
args = &model.CommandArgs{
|
||||
T: func(s string, args ...interface{}) string { return s },
|
||||
ChannelId: privateChannel.Id,
|
||||
Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}},
|
||||
}
|
||||
|
||||
actual = hp.DoCommand(th.App, args, "hello").Text
|
||||
assert.Equal(t, "api.command_channel_header.permission.app_error", actual)
|
||||
|
||||
// Try a group channel *with* being a member.
|
||||
user1 := th.CreateUser()
|
||||
user2 := th.CreateUser()
|
||||
user3 := th.CreateUser()
|
||||
|
||||
groupChannel := th.CreateGroupChannel(user1, user2)
|
||||
|
||||
args = &model.CommandArgs{
|
||||
T: func(s string, args ...interface{}) string { return s },
|
||||
ChannelId: groupChannel.Id,
|
||||
Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}},
|
||||
}
|
||||
|
||||
actual = hp.DoCommand(th.App, args, "hello").Text
|
||||
assert.Equal(t, "", actual)
|
||||
|
||||
// Try a group channel *without* being a member.
|
||||
args = &model.CommandArgs{
|
||||
T: func(s string, args ...interface{}) string { return s },
|
||||
ChannelId: groupChannel.Id,
|
||||
Session: model.Session{UserId: user3.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}},
|
||||
}
|
||||
|
||||
actual = hp.DoCommand(th.App, args, "hello").Text
|
||||
assert.Equal(t, "api.command_channel_header.permission.app_error", actual)
|
||||
|
||||
// Try a direct channel *with* being a member.
|
||||
directChannel := th.CreateDmChannel(user1)
|
||||
|
||||
args = &model.CommandArgs{
|
||||
T: func(s string, args ...interface{}) string { return s },
|
||||
ChannelId: directChannel.Id,
|
||||
Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}},
|
||||
}
|
||||
|
||||
actual = hp.DoCommand(th.App, args, "hello").Text
|
||||
assert.Equal(t, "", actual)
|
||||
|
||||
// Try a direct channel *without* being a member.
|
||||
args = &model.CommandArgs{
|
||||
T: func(s string, args ...interface{}) string { return s },
|
||||
ChannelId: directChannel.Id,
|
||||
Session: model.Session{UserId: user2.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}},
|
||||
}
|
||||
|
||||
actual = hp.DoCommand(th.App, args, "hello").Text
|
||||
assert.Equal(t, "api.command_channel_header.permission.app_error", actual)
|
||||
}
|
||||
|
||||
@@ -93,10 +93,20 @@ func (me *groupmsgProvider) DoCommand(a *App, args *model.CommandArgs, message s
|
||||
}
|
||||
}
|
||||
|
||||
groupChannel, channelErr := a.CreateGroupChannel(targetUsersSlice, args.UserId)
|
||||
if channelErr != nil {
|
||||
mlog.Error(channelErr.Error())
|
||||
return &model.CommandResponse{Text: args.T("api.command_groupmsg.group_fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
var groupChannel *model.Channel
|
||||
var channelErr *model.AppError
|
||||
|
||||
if a.SessionHasPermissionTo(args.Session, model.PERMISSION_CREATE_GROUP_CHANNEL) {
|
||||
groupChannel, channelErr = a.CreateGroupChannel(targetUsersSlice, args.UserId)
|
||||
if channelErr != nil {
|
||||
mlog.Error(channelErr.Error())
|
||||
return &model.CommandResponse{Text: args.T("api.command_groupmsg.group_fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
} else {
|
||||
groupChannel, channelErr = a.GetGroupChannel(targetUsersSlice)
|
||||
if channelErr != nil {
|
||||
return &model.CommandResponse{Text: args.T("api.command_groupmsg.permission.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
}
|
||||
|
||||
if len(parsedMessage) > 0 {
|
||||
|
||||
@@ -2,6 +2,11 @@ package app
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nicksnyder/go-i18n/i18n"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
)
|
||||
|
||||
func TestGroupMsgUsernames(t *testing.T) {
|
||||
@@ -35,3 +40,58 @@ func TestGroupMsgUsernames(t *testing.T) {
|
||||
t.Fatal("error parsing different types of users")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupMsgProvider(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
user3 := th.CreateUser()
|
||||
targetUsers := "@" + th.BasicUser2.Username + ",@" + user3.Username + " "
|
||||
|
||||
team := th.CreateTeam()
|
||||
th.LinkUserToTeam(th.BasicUser, team)
|
||||
cmd := &groupmsgProvider{}
|
||||
|
||||
// Check without permission to create a GM channel.
|
||||
resp := cmd.DoCommand(th.App, &model.CommandArgs{
|
||||
T: i18n.IdentityTfunc(),
|
||||
SiteURL: "http://test.url",
|
||||
TeamId: team.Id,
|
||||
UserId: th.BasicUser.Id,
|
||||
Session: model.Session{
|
||||
Roles: "",
|
||||
},
|
||||
}, targetUsers+"hello")
|
||||
|
||||
channelName := model.GetGroupNameFromUserIds([]string{th.BasicUser.Id, th.BasicUser2.Id, user3.Id})
|
||||
assert.Equal(t, "api.command_groupmsg.permission.app_error", resp.Text)
|
||||
assert.Equal(t, "", resp.GotoLocation)
|
||||
|
||||
// Check with permission to create a GM channel.
|
||||
resp = cmd.DoCommand(th.App, &model.CommandArgs{
|
||||
T: i18n.IdentityTfunc(),
|
||||
SiteURL: "http://test.url",
|
||||
TeamId: team.Id,
|
||||
UserId: th.BasicUser.Id,
|
||||
Session: model.Session{
|
||||
Roles: model.SYSTEM_USER_ROLE_ID,
|
||||
},
|
||||
}, targetUsers+"hello")
|
||||
|
||||
assert.Equal(t, "", resp.Text)
|
||||
assert.Equal(t, "http://test.url/"+team.Name+"/channels/"+channelName, resp.GotoLocation)
|
||||
|
||||
// Check without permission to post to an existing GM channel.
|
||||
resp = cmd.DoCommand(th.App, &model.CommandArgs{
|
||||
T: i18n.IdentityTfunc(),
|
||||
SiteURL: "http://test.url",
|
||||
TeamId: team.Id,
|
||||
UserId: th.BasicUser.Id,
|
||||
Session: model.Session{
|
||||
Roles: "",
|
||||
},
|
||||
}, targetUsers+"hello")
|
||||
|
||||
assert.Equal(t, "", resp.Text)
|
||||
assert.Equal(t, "http://test.url/"+team.Name+"/channels/"+channelName, resp.GotoLocation)
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func (me *InvitePeopleProvider) GetTrigger() string {
|
||||
|
||||
func (me *InvitePeopleProvider) GetCommand(a *App, T goi18n.TranslateFunc) *model.Command {
|
||||
autoComplete := true
|
||||
if !a.Config().EmailSettings.SendEmailNotifications || !*a.Config().TeamSettings.EnableUserCreation {
|
||||
if !a.Config().EmailSettings.SendEmailNotifications || !*a.Config().TeamSettings.EnableUserCreation || !*a.Config().ServiceSettings.EnableEmailInvitations {
|
||||
autoComplete = false
|
||||
}
|
||||
return &model.Command{
|
||||
@@ -41,6 +41,14 @@ func (me *InvitePeopleProvider) GetCommand(a *App, T goi18n.TranslateFunc) *mode
|
||||
}
|
||||
|
||||
func (me *InvitePeopleProvider) DoCommand(a *App, args *model.CommandArgs, message string) *model.CommandResponse {
|
||||
if !a.SessionHasPermissionToTeam(args.Session, args.TeamId, model.PERMISSION_INVITE_USER) {
|
||||
return &model.CommandResponse{Text: args.T("api.command_invite_people.permission.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
if !a.SessionHasPermissionToTeam(args.Session, args.TeamId, model.PERMISSION_ADD_USER_TO_TEAM) {
|
||||
return &model.CommandResponse{Text: args.T("api.command_invite_people.permission.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
if !a.Config().EmailSettings.SendEmailNotifications {
|
||||
return &model.CommandResponse{ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL, Text: args.T("api.command.invite_people.email_off")}
|
||||
}
|
||||
@@ -49,6 +57,10 @@ func (me *InvitePeopleProvider) DoCommand(a *App, args *model.CommandArgs, messa
|
||||
return &model.CommandResponse{ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL, Text: args.T("api.command.invite_people.invite_off")}
|
||||
}
|
||||
|
||||
if !*a.Config().ServiceSettings.EnableEmailInvitations {
|
||||
return &model.CommandResponse{ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL, Text: args.T("api.command.invite_people.email_invitations_off")}
|
||||
}
|
||||
|
||||
emailList := strings.Fields(message)
|
||||
|
||||
for i := len(emailList) - 1; i >= 0; i-- {
|
||||
|
||||
42
app/command_invite_people_test.go
Обычный файл
42
app/command_invite_people_test.go
Обычный файл
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
)
|
||||
|
||||
func TestInvitePeopleProvider(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
enableEmailInvitations := *th.App.Config().ServiceSettings.EnableEmailInvitations
|
||||
defer func() {
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableEmailInvitations = &enableEmailInvitations })
|
||||
}()
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableEmailInvitations = true })
|
||||
|
||||
cmd := InvitePeopleProvider{}
|
||||
|
||||
// Test without required permissions
|
||||
args := &model.CommandArgs{
|
||||
T: func(s string, args ...interface{}) string { return s },
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
TeamId: th.BasicTeam.Id,
|
||||
UserId: th.BasicUser.Id,
|
||||
Session: model.Session{UserId: th.BasicUser.Id, TeamMembers: []*model.TeamMember{{TeamId: th.BasicTeam.Id, Roles: ""}}},
|
||||
}
|
||||
|
||||
actual := cmd.DoCommand(th.App, args, model.NewId()+"@simulator.amazonses.com")
|
||||
assert.Equal(t, "api.command_invite_people.permission.app_error", actual.Text)
|
||||
|
||||
// Test with required permissions.
|
||||
args.Session.TeamMembers[0].Roles = model.TEAM_USER_ROLE_ID
|
||||
actual = cmd.DoCommand(th.App, args, model.NewId()+"@simulator.amazonses.com")
|
||||
assert.Equal(t, "api.command.invite_people.sent", actual.Text)
|
||||
}
|
||||
@@ -66,6 +66,10 @@ func (me *msgProvider) DoCommand(a *App, args *model.CommandArgs, message string
|
||||
targetChannelId := ""
|
||||
if channel := <-a.Srv.Store.Channel().GetByName(args.TeamId, channelName, true); channel.Err != nil {
|
||||
if channel.Err.Id == "store.sql_channel.get_by_name.missing.app_error" {
|
||||
if !a.SessionHasPermissionTo(args.Session, model.PERMISSION_CREATE_DIRECT_CHANNEL) {
|
||||
return &model.CommandResponse{Text: args.T("api.command_msg.permission.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
if directChannel, err := a.CreateDirectChannel(args.UserId, userProfile.Id); err != nil {
|
||||
mlog.Error(err.Error())
|
||||
return &model.CommandResponse{Text: args.T("api.command_msg.dm_fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
|
||||
@@ -19,13 +19,47 @@ func TestMsgProvider(t *testing.T) {
|
||||
team := th.CreateTeam()
|
||||
th.LinkUserToTeam(th.BasicUser, team)
|
||||
cmd := &msgProvider{}
|
||||
|
||||
// Check without permission to create a DM channel.
|
||||
resp := cmd.DoCommand(th.App, &model.CommandArgs{
|
||||
T: i18n.IdentityTfunc(),
|
||||
SiteURL: "http://test.url",
|
||||
TeamId: team.Id,
|
||||
UserId: th.BasicUser.Id,
|
||||
Session: model.Session{
|
||||
Roles: "",
|
||||
},
|
||||
}, "@"+th.BasicUser2.Username+" hello")
|
||||
|
||||
channelName := model.GetDMNameFromIds(th.BasicUser.Id, th.BasicUser2.Id)
|
||||
assert.Equal(t, "api.command_msg.permission.app_error", resp.Text)
|
||||
assert.Equal(t, "", resp.GotoLocation)
|
||||
|
||||
// Check with permission to create a DM channel.
|
||||
resp = cmd.DoCommand(th.App, &model.CommandArgs{
|
||||
T: i18n.IdentityTfunc(),
|
||||
SiteURL: "http://test.url",
|
||||
TeamId: team.Id,
|
||||
UserId: th.BasicUser.Id,
|
||||
Session: model.Session{
|
||||
Roles: model.SYSTEM_USER_ROLE_ID,
|
||||
},
|
||||
}, "@"+th.BasicUser2.Username+" hello")
|
||||
|
||||
assert.Equal(t, "", resp.Text)
|
||||
assert.Equal(t, "http://test.url/"+team.Name+"/channels/"+channelName, resp.GotoLocation)
|
||||
|
||||
// Check without permission to post to an existing DM channel.
|
||||
resp = cmd.DoCommand(th.App, &model.CommandArgs{
|
||||
T: i18n.IdentityTfunc(),
|
||||
SiteURL: "http://test.url",
|
||||
TeamId: team.Id,
|
||||
UserId: th.BasicUser.Id,
|
||||
Session: model.Session{
|
||||
Roles: "",
|
||||
},
|
||||
}, "@"+th.BasicUser2.Username+" hello")
|
||||
|
||||
assert.Equal(t, "", resp.Text)
|
||||
assert.Equal(t, "http://test.url/"+team.Name+"/channels/"+channelName, resp.GotoLocation)
|
||||
}
|
||||
|
||||
48
app/email.go
48
app/email.go
@@ -10,12 +10,41 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/nicksnyder/go-i18n/i18n"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/throttled/throttled"
|
||||
"github.com/throttled/throttled/store/memstore"
|
||||
|
||||
"github.com/mattermost/mattermost-server/mlog"
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/mattermost/mattermost-server/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
emailRateLimitingMemstoreSize = 65536
|
||||
emailRateLimitingPerHour = 20
|
||||
emailRateLimitingMaxBurst = 20
|
||||
)
|
||||
|
||||
func (a *App) SetupInviteEmailRateLimiting() error {
|
||||
store, err := memstore.New(emailRateLimitingMemstoreSize)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Unable to setup email rate limiting memstore.")
|
||||
}
|
||||
|
||||
quota := throttled.RateQuota{
|
||||
MaxRate: throttled.PerHour(emailRateLimitingPerHour),
|
||||
MaxBurst: emailRateLimitingMaxBurst,
|
||||
}
|
||||
|
||||
rateLimiter, err := throttled.NewGCRARateLimiter(store, quota)
|
||||
if err != nil || rateLimiter == nil {
|
||||
return errors.Wrap(err, "Unable to setup email rate limiting GCRA rate limiter.")
|
||||
}
|
||||
|
||||
a.EmailRateLimiter = rateLimiter
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) SendChangeUsernameEmail(oldUsername, newUsername, email, locale, siteURL string) *model.AppError {
|
||||
T := utils.GetUserTranslations(locale)
|
||||
|
||||
@@ -247,7 +276,24 @@ func (a *App) SendMfaChangeEmail(email string, activated bool, locale, siteURL s
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) SendInviteEmails(team *model.Team, senderName string, invites []string, siteURL string) {
|
||||
func (a *App) SendInviteEmails(team *model.Team, senderName string, senderUserId string, invites []string, siteURL string) {
|
||||
if a.EmailRateLimiter == nil {
|
||||
a.Log.Error("Email invite not sent, rate limiting could not be setup.", mlog.String("user_id", senderUserId), mlog.String("team_id", team.Id))
|
||||
return
|
||||
}
|
||||
rateLimited, result, err := a.EmailRateLimiter.RateLimit(senderUserId, len(invites))
|
||||
if rateLimited {
|
||||
a.Log.Error("Invite emails rate limited.",
|
||||
mlog.String("user_id", senderUserId),
|
||||
mlog.String("team_id", team.Id),
|
||||
mlog.String("retry_after", result.RetryAfter.String()),
|
||||
mlog.Err(err))
|
||||
return
|
||||
} else if err != nil {
|
||||
a.Log.Error("Error rate limiting invite email.", mlog.String("user_id", senderUserId), mlog.String("team_id", team.Id), mlog.Err(err))
|
||||
return
|
||||
}
|
||||
|
||||
for _, invite := range invites {
|
||||
if len(invite) > 0 {
|
||||
senderRole := utils.T("api.team.invite_members.member")
|
||||
|
||||
@@ -805,6 +805,10 @@ func (a *App) postRemoveFromTeamMessage(user *model.User, channel *model.Channel
|
||||
}
|
||||
|
||||
func (a *App) InviteNewUsersToTeam(emailList []string, teamId, senderId string) *model.AppError {
|
||||
if !*a.Config().ServiceSettings.EnableEmailInvitations {
|
||||
return model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if len(emailList) == 0 {
|
||||
err := model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.no_one.app_error", nil, "", http.StatusBadRequest)
|
||||
return err
|
||||
@@ -842,7 +846,7 @@ func (a *App) InviteNewUsersToTeam(emailList []string, teamId, senderId string)
|
||||
}
|
||||
|
||||
nameFormat := *a.Config().TeamSettings.TeammateNameDisplay
|
||||
a.SendInviteEmails(team, user.GetDisplayName(nameFormat), emailList, a.GetSiteURL())
|
||||
a.SendInviteEmails(team, user.GetDisplayName(nameFormat), user.Id, emailList, a.GetSiteURL())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user