MM-34002: Improve AddUserToChannel (#17174)

* MM-34002: Improve AddUserToChannel

When we would add a user to a channel, we would
check whether the user is removed from that team or not.

During LDAP sync, this check is not required because the
team member would have just been created. Hence, we
pass a boolean flag to bypass the check.

And with that done, we can freely query the replica.

https://mattermost.atlassian.net/browse/MM-34002

```release-note
NONE
```

* Refactor code

* Rename a struct field

* fix double negative
Этот коммит содержится в:
Agniva De Sarker
2021-04-02 14:33:23 +05:30
коммит произвёл GitHub
родитель 4f0cfbe329
Коммит db01f2a91b
30 изменённых файлов: 169 добавлений и 152 удалений

Просмотреть файл

@@ -380,14 +380,14 @@ func (th *TestHelper) InitBasic() *TestHelper {
th.BasicPost = th.CreatePost() th.BasicPost = th.CreatePost()
th.LinkUserToTeam(th.BasicUser, th.BasicTeam) th.LinkUserToTeam(th.BasicUser, th.BasicTeam)
th.LinkUserToTeam(th.BasicUser2, th.BasicTeam) th.LinkUserToTeam(th.BasicUser2, th.BasicTeam)
th.App.AddUserToChannel(th.BasicUser, th.BasicChannel) th.App.AddUserToChannel(th.BasicUser, th.BasicChannel, false)
th.App.AddUserToChannel(th.BasicUser2, th.BasicChannel) th.App.AddUserToChannel(th.BasicUser2, th.BasicChannel, false)
th.App.AddUserToChannel(th.BasicUser, th.BasicChannel2) th.App.AddUserToChannel(th.BasicUser, th.BasicChannel2, false)
th.App.AddUserToChannel(th.BasicUser2, th.BasicChannel2) th.App.AddUserToChannel(th.BasicUser2, th.BasicChannel2, false)
th.App.AddUserToChannel(th.BasicUser, th.BasicPrivateChannel) th.App.AddUserToChannel(th.BasicUser, th.BasicPrivateChannel, false)
th.App.AddUserToChannel(th.BasicUser2, th.BasicPrivateChannel) th.App.AddUserToChannel(th.BasicUser2, th.BasicPrivateChannel, false)
th.App.AddUserToChannel(th.BasicUser, th.BasicDeletedChannel) th.App.AddUserToChannel(th.BasicUser, th.BasicDeletedChannel, false)
th.App.AddUserToChannel(th.BasicUser2, th.BasicDeletedChannel) th.App.AddUserToChannel(th.BasicUser2, th.BasicDeletedChannel, false)
th.App.UpdateUserRoles(th.BasicUser.Id, model.SYSTEM_USER_ROLE_ID, false) th.App.UpdateUserRoles(th.BasicUser.Id, model.SYSTEM_USER_ROLE_ID, false)
th.Client.DeleteChannel(th.BasicDeletedChannel.Id) th.Client.DeleteChannel(th.BasicDeletedChannel.Id)
th.LoginBasic() th.LoginBasic()
@@ -792,7 +792,7 @@ func (th *TestHelper) LinkUserToTeam(user *model.User, team *model.Team) {
func (th *TestHelper) AddUserToChannel(user *model.User, channel *model.Channel) *model.ChannelMember { func (th *TestHelper) AddUserToChannel(user *model.User, channel *model.Channel) *model.ChannelMember {
utils.DisableDebugLogForTest() utils.DisableDebugLogForTest()
member, err := th.App.AddUserToChannel(user, channel) member, err := th.App.AddUserToChannel(user, channel, false)
if err != nil { if err != nil {
panic(err) panic(err)
} }

Просмотреть файл

@@ -1540,7 +1540,10 @@ func addChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
} }
} }
cm, err := c.App.AddChannelMember(member.UserId, channel, c.App.Session().UserId, postRootId) cm, err := c.App.AddChannelMember(member.UserId, channel, app.ChannelMemberOpts{
UserRequestorID: c.App.Session().UserId,
PostRootID: postRootId,
})
if err != nil { if err != nil {
c.Err = err c.Err = err
return return

Просмотреть файл

@@ -107,7 +107,7 @@ func localAddChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
} }
} }
cm, err := c.App.AddUserToChannel(user, channel) cm, err := c.App.AddUserToChannel(user, channel, false)
if err != nil { if err != nil {
c.Err = err c.Err = err
return return

Просмотреть файл

@@ -16,6 +16,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/v5/app"
"github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/plugin/plugintest/mock" "github.com/mattermost/mattermost-server/v5/plugin/plugintest/mock"
"github.com/mattermost/mattermost-server/v5/store/storetest/mocks" "github.com/mattermost/mattermost-server/v5/store/storetest/mocks"
@@ -1497,8 +1498,8 @@ func TestDeleteChannel(t *testing.T) {
// successful delete of channel with multiple members // successful delete of channel with multiple members
publicChannel3 := th.CreatePublicChannel() publicChannel3 := th.CreatePublicChannel()
th.App.AddUserToChannel(user, publicChannel3) th.App.AddUserToChannel(user, publicChannel3, false)
th.App.AddUserToChannel(user2, publicChannel3) th.App.AddUserToChannel(user2, publicChannel3, false)
_, resp = client.DeleteChannel(publicChannel3.Id) _, resp = client.DeleteChannel(publicChannel3.Id)
CheckNoError(t, resp) CheckNoError(t, resp)
@@ -1574,9 +1575,9 @@ func TestDeleteChannel2(t *testing.T) {
// channels created by SystemAdmin // channels created by SystemAdmin
publicChannel6 := th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_OPEN) publicChannel6 := th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_OPEN)
privateChannel7 := th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_PRIVATE) privateChannel7 := th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_PRIVATE)
th.App.AddUserToChannel(user, publicChannel6) th.App.AddUserToChannel(user, publicChannel6, false)
th.App.AddUserToChannel(user, privateChannel7) th.App.AddUserToChannel(user, privateChannel7, false)
th.App.AddUserToChannel(user, privateChannel7) th.App.AddUserToChannel(user, privateChannel7, false)
// successful delete by user // successful delete by user
_, resp := Client.DeleteChannel(publicChannel6.Id) _, resp := Client.DeleteChannel(publicChannel6.Id)
@@ -1594,9 +1595,9 @@ func TestDeleteChannel2(t *testing.T) {
// channels created by SystemAdmin // channels created by SystemAdmin
publicChannel6 = th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_OPEN) publicChannel6 = th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_OPEN)
privateChannel7 = th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_PRIVATE) privateChannel7 = th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_PRIVATE)
th.App.AddUserToChannel(user, publicChannel6) th.App.AddUserToChannel(user, publicChannel6, false)
th.App.AddUserToChannel(user, privateChannel7) th.App.AddUserToChannel(user, privateChannel7, false)
th.App.AddUserToChannel(user, privateChannel7) th.App.AddUserToChannel(user, privateChannel7, false)
// cannot delete by user // cannot delete by user
_, resp = Client.DeleteChannel(publicChannel6.Id) _, resp = Client.DeleteChannel(publicChannel6.Id)
@@ -2295,7 +2296,7 @@ func TestUpdateChannelRoles(t *testing.T) {
channel := th.CreatePublicChannel() channel := th.CreatePublicChannel()
// Adds User 2 to the channel, making them a channel member by default. // Adds User 2 to the channel, making them a channel member by default.
th.App.AddUserToChannel(th.BasicUser2, channel) th.App.AddUserToChannel(th.BasicUser2, channel, false)
// User 1 promotes User 2 // User 1 promotes User 2
pass, resp := Client.UpdateChannelRoles(channel.Id, th.BasicUser2.Id, ChannelAdmin) pass, resp := Client.UpdateChannelRoles(channel.Id, th.BasicUser2.Id, ChannelAdmin)
@@ -2803,9 +2804,9 @@ func TestRemoveChannelMember(t *testing.T) {
t.Run("success", func(t *testing.T) { t.Run("success", func(t *testing.T) {
// Setup the system administrator to listen for websocket events from the channels. // Setup the system administrator to listen for websocket events from the channels.
th.LinkUserToTeam(th.SystemAdminUser, th.BasicTeam) th.LinkUserToTeam(th.SystemAdminUser, th.BasicTeam)
_, err := th.App.AddUserToChannel(th.SystemAdminUser, th.BasicChannel) _, err := th.App.AddUserToChannel(th.SystemAdminUser, th.BasicChannel, false)
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(th.SystemAdminUser, th.BasicChannel2) _, err = th.App.AddUserToChannel(th.SystemAdminUser, th.BasicChannel2, false)
require.Nil(t, err) require.Nil(t, err)
props := map[string]string{} props := map[string]string{}
props[model.DESKTOP_NOTIFY_PROP] = model.CHANNEL_NOTIFY_ALL props[model.DESKTOP_NOTIFY_PROP] = model.CHANNEL_NOTIFY_ALL
@@ -2847,7 +2848,7 @@ func TestRemoveChannelMember(t *testing.T) {
} }
} }
th.App.AddUserToChannel(th.BasicUser2, th.BasicChannel) th.App.AddUserToChannel(th.BasicUser2, th.BasicChannel, false)
_, resp = Client.RemoveUserFromChannel(th.BasicChannel.Id, th.BasicUser2.Id) _, resp = Client.RemoveUserFromChannel(th.BasicChannel.Id, th.BasicUser2.Id)
CheckNoError(t, resp) CheckNoError(t, resp)
@@ -2878,8 +2879,8 @@ func TestRemoveChannelMember(t *testing.T) {
// Leave deleted channel // Leave deleted channel
th.LoginBasic() th.LoginBasic()
deletedChannel := th.CreatePublicChannel() deletedChannel := th.CreatePublicChannel()
th.App.AddUserToChannel(th.BasicUser, deletedChannel) th.App.AddUserToChannel(th.BasicUser, deletedChannel, false)
th.App.AddUserToChannel(th.BasicUser2, deletedChannel) th.App.AddUserToChannel(th.BasicUser2, deletedChannel, false)
deletedChannel.DeleteAt = 1 deletedChannel.DeleteAt = 1
th.App.UpdateChannel(deletedChannel) th.App.UpdateChannel(deletedChannel)
@@ -2889,7 +2890,7 @@ func TestRemoveChannelMember(t *testing.T) {
th.LoginBasic() th.LoginBasic()
private := th.CreatePrivateChannel() private := th.CreatePrivateChannel()
th.App.AddUserToChannel(th.BasicUser2, private) th.App.AddUserToChannel(th.BasicUser2, private, false)
_, resp = Client.RemoveUserFromChannel(private.Id, th.BasicUser2.Id) _, resp = Client.RemoveUserFromChannel(private.Id, th.BasicUser2.Id)
CheckNoError(t, resp) CheckNoError(t, resp)
@@ -2899,7 +2900,7 @@ func TestRemoveChannelMember(t *testing.T) {
CheckForbiddenStatus(t, resp) CheckForbiddenStatus(t, resp)
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) { th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
th.App.AddUserToChannel(th.BasicUser, private) th.App.AddUserToChannel(th.BasicUser, private, false)
_, resp = client.RemoveUserFromChannel(private.Id, th.BasicUser.Id) _, resp = client.RemoveUserFromChannel(private.Id, th.BasicUser.Id)
CheckNoError(t, resp) CheckNoError(t, resp)
}) })
@@ -3436,9 +3437,9 @@ func TestChannelMembersMinusGroupMembers(t *testing.T) {
channel := th.CreatePrivateChannel() channel := th.CreatePrivateChannel()
_, err := th.App.AddChannelMember(user1.Id, channel, "", "") _, err := th.App.AddChannelMember(user1.Id, channel, app.ChannelMemberOpts{})
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddChannelMember(user2.Id, channel, "", "") _, err = th.App.AddChannelMember(user2.Id, channel, app.ChannelMemberOpts{})
require.Nil(t, err) require.Nil(t, err)
channel.GroupConstrained = model.NewBool(true) channel.GroupConstrained = model.NewBool(true)

Просмотреть файл

@@ -540,7 +540,7 @@ func TestCreatePostSendOutOfChannelMentions(t *testing.T) {
inChannelUser := th.CreateUser() inChannelUser := th.CreateUser()
th.LinkUserToTeam(inChannelUser, th.BasicTeam) th.LinkUserToTeam(inChannelUser, th.BasicTeam)
th.App.AddUserToChannel(inChannelUser, th.BasicChannel) th.App.AddUserToChannel(inChannelUser, th.BasicChannel, false)
post1 := &model.Post{ChannelId: th.BasicChannel.Id, Message: "@" + inChannelUser.Username} post1 := &model.Post{ChannelId: th.BasicChannel.Id, Message: "@" + inChannelUser.Username}
_, resp := Client.CreatePost(post1) _, resp := Client.CreatePost(post1)
@@ -1997,7 +1997,7 @@ func TestDeletePost(t *testing.T) {
func TestDeletePostMessage(t *testing.T) { func TestDeletePostMessage(t *testing.T) {
th := Setup(t).InitBasic() th := Setup(t).InitBasic()
th.LinkUserToTeam(th.SystemAdminUser, th.BasicTeam) th.LinkUserToTeam(th.SystemAdminUser, th.BasicTeam)
th.App.AddUserToChannel(th.SystemAdminUser, th.BasicChannel) th.App.AddUserToChannel(th.SystemAdminUser, th.BasicChannel, false)
defer th.TearDown() defer th.TearDown()
@@ -2312,8 +2312,8 @@ func TestSearchPostsFromUser(t *testing.T) {
th.LoginTeamAdmin() th.LoginTeamAdmin()
user := th.CreateUser() user := th.CreateUser()
th.LinkUserToTeam(user, th.BasicTeam) th.LinkUserToTeam(user, th.BasicTeam)
th.App.AddUserToChannel(user, th.BasicChannel) th.App.AddUserToChannel(user, th.BasicChannel, false)
th.App.AddUserToChannel(user, th.BasicChannel2) th.App.AddUserToChannel(user, th.BasicChannel2, false)
message := "sgtitlereview with space" message := "sgtitlereview with space"
_ = th.CreateMessagePost(message) _ = th.CreateMessagePost(message)

Просмотреть файл

@@ -381,7 +381,7 @@ func TestCreateUserWebSocketEvent(t *testing.T) {
_, _, err = th.App.AddUserToTeam(th.BasicTeam.Id, guest.Id, "") _, _, err = th.App.AddUserToTeam(th.BasicTeam.Id, guest.Id, "")
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(guest, th.BasicChannel) _, err = th.App.AddUserToChannel(guest, th.BasicChannel, false)
require.Nil(t, err) require.Nil(t, err)
guestClient := th.CreateClient() guestClient := th.CreateClient()
@@ -5151,11 +5151,11 @@ func TestGetKnownUsers(t *testing.T) {
th.LinkUserToTeam(u3, t2) th.LinkUserToTeam(u3, t2)
th.LinkUserToTeam(u4, t3) th.LinkUserToTeam(u4, t3)
th.App.AddUserToChannel(u1, c1) th.App.AddUserToChannel(u1, c1, false)
th.App.AddUserToChannel(u1, c2) th.App.AddUserToChannel(u1, c2, false)
th.App.AddUserToChannel(u2, c1) th.App.AddUserToChannel(u2, c1, false)
th.App.AddUserToChannel(u3, c2) th.App.AddUserToChannel(u3, c2, false)
th.App.AddUserToChannel(u4, c3) th.App.AddUserToChannel(u4, c3, false)
t.Run("get know users sharing no channels", func(t *testing.T) { t.Run("get know users sharing no channels", func(t *testing.T) {
_, _ = th.Client.Login(u4.Email, u4.Password) _, _ = th.Client.Login(u4.Email, u4.Password)

Просмотреть файл

@@ -42,12 +42,16 @@ type AppIface interface {
ListAutocompleteCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError) ListAutocompleteCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError)
// @openTracingParams teamID, skipSlackParsing // @openTracingParams teamID, skipSlackParsing
CreateCommandPost(post *model.Post, teamID string, response *model.CommandResponse, skipSlackParsing bool) (*model.Post, *model.AppError) CreateCommandPost(post *model.Post, teamID string, response *model.CommandResponse, skipSlackParsing bool) (*model.Post, *model.AppError)
// AddChannelMember adds a user to a channel. It is a wrapper over AddUserToChannel.
AddChannelMember(userID string, channel *model.Channel, opts ChannelMemberOpts) (*model.ChannelMember, *model.AppError)
// AddCursorIdsForPostList adds NextPostId and PrevPostId as cursor to the PostList. // AddCursorIdsForPostList adds NextPostId and PrevPostId as cursor to the PostList.
// The conditional blocks ensure that it sets those cursor IDs immediately as afterPost, beforePost or empty, // The conditional blocks ensure that it sets those cursor IDs immediately as afterPost, beforePost or empty,
// and only query to database whenever necessary. // and only query to database whenever necessary.
AddCursorIdsForPostList(originalList *model.PostList, afterPost, beforePost string, since int64, page, perPage int, collapsedThreads bool) AddCursorIdsForPostList(originalList *model.PostList, afterPost, beforePost string, since int64, page, perPage int, collapsedThreads bool)
// AddPublicKey will add plugin public key to the config. Overwrites the previous file // AddPublicKey will add plugin public key to the config. Overwrites the previous file
AddPublicKey(name string, key io.Reader) *model.AppError AddPublicKey(name string, key io.Reader) *model.AppError
// AddUserToChannel adds a user to a given channel.
AddUserToChannel(user *model.User, channel *model.Channel, skipTeamMemberIntegrityCheck bool) (*model.ChannelMember, *model.AppError)
// Caller must close the first return value // Caller must close the first return value
FileReader(path string) (filestore.ReadCloseSeeker, *model.AppError) FileReader(path string) (filestore.ReadCloseSeeker, *model.AppError)
// ChannelMembersMinusGroupMembers returns the set of users in the given channel minus the set of users in the given // ChannelMembersMinusGroupMembers returns the set of users in the given channel minus the set of users in the given
@@ -359,7 +363,6 @@ type AppIface interface {
AcceptLanguage() string AcceptLanguage() string
AccountMigration() einterfaces.AccountMigrationInterface AccountMigration() einterfaces.AccountMigrationInterface
ActivateMfa(userID, token string) *model.AppError ActivateMfa(userID, token string) *model.AppError
AddChannelMember(userID string, channel *model.Channel, userRequestorId string, postRootId string) (*model.ChannelMember, *model.AppError)
AddConfigListener(listener func(*model.Config, *model.Config)) string AddConfigListener(listener func(*model.Config, *model.Config)) string
AddDirectChannels(teamID string, user *model.User) *model.AppError AddDirectChannels(teamID string, user *model.User) *model.AppError
AddLdapPrivateCertificate(fileData *multipart.FileHeader) *model.AppError AddLdapPrivateCertificate(fileData *multipart.FileHeader) *model.AppError
@@ -375,7 +378,6 @@ type AppIface interface {
AddTeamMemberByInviteId(inviteId, userID string) (*model.TeamMember, *model.AppError) AddTeamMemberByInviteId(inviteId, userID string) (*model.TeamMember, *model.AppError)
AddTeamMemberByToken(userID, tokenID string) (*model.TeamMember, *model.AppError) AddTeamMemberByToken(userID, tokenID string) (*model.TeamMember, *model.AppError)
AddTeamMembers(teamID string, userIDs []string, userRequestorId string, graceful bool) ([]*model.TeamMemberWithError, *model.AppError) AddTeamMembers(teamID string, userIDs []string, userRequestorId string, graceful bool) ([]*model.TeamMemberWithError, *model.AppError)
AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelMember, *model.AppError)
AddUserToTeam(teamID string, userID string, userRequestorId string) (*model.Team, *model.TeamMember, *model.AppError) AddUserToTeam(teamID string, userID string, userRequestorId string) (*model.Team, *model.TeamMember, *model.AppError)
AddUserToTeamByInviteId(inviteId string, userID string) (*model.Team, *model.TeamMember, *model.AppError) AddUserToTeamByInviteId(inviteId string, userID string) (*model.Team, *model.TeamMember, *model.AppError)
AddUserToTeamByTeamId(teamID string, user *model.User) *model.AppError AddUserToTeamByTeamId(teamID string, user *model.User) *model.AppError

Просмотреть файл

@@ -15,7 +15,6 @@ import (
"github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/mattermost/mattermost-server/v5/shared/i18n"
"github.com/mattermost/mattermost-server/v5/shared/mlog" "github.com/mattermost/mattermost-server/v5/shared/mlog"
"github.com/mattermost/mattermost-server/v5/store" "github.com/mattermost/mattermost-server/v5/store"
"github.com/mattermost/mattermost-server/v5/store/sqlstore"
"github.com/mattermost/mattermost-server/v5/utils" "github.com/mattermost/mattermost-server/v5/utils"
) )
@@ -1372,24 +1371,23 @@ func (a *App) addUserToChannel(user *model.User, channel *model.Channel) (*model
return newMember, nil return newMember, nil
} }
func (a *App) AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelMember, *model.AppError) { // AddUserToChannel adds a user to a given channel.
// We have to query master here because this is called during LDAP sync from: func (a *App) AddUserToChannel(user *model.User, channel *model.Channel, skipTeamMemberIntegrityCheck bool) (*model.ChannelMember, *model.AppError) {
// a.createDefaultChannelMemberships -> a.AddTeamMember -> a.AddChannelMember if !skipTeamMemberIntegrityCheck {
// So we get a teamMember right after adding a team member which leads to a failure. teamMember, nErr := a.Srv().Store.Team().GetMember(context.Background(), channel.TeamId, user.Id)
// TODO: pass the team member to this method. if nErr != nil {
teamMember, nErr := a.Srv().Store.Team().GetMember(sqlstore.WithMaster(context.Background()), channel.TeamId, user.Id) var nfErr *store.ErrNotFound
if nErr != nil { switch {
var nfErr *store.ErrNotFound case errors.As(nErr, &nfErr):
switch { return nil, model.NewAppError("AddUserToChannel", "app.team.get_member.missing.app_error", nil, nfErr.Error(), http.StatusNotFound)
case errors.As(nErr, &nfErr): default:
return nil, model.NewAppError("AddUserToChannel", "app.team.get_member.missing.app_error", nil, nfErr.Error(), http.StatusNotFound) return nil, model.NewAppError("AddUserToChannel", "app.team.get_member.app_error", nil, nErr.Error(), http.StatusInternalServerError)
default: }
return nil, model.NewAppError("AddUserToChannel", "app.team.get_member.app_error", nil, nErr.Error(), http.StatusInternalServerError)
} }
}
if teamMember.DeleteAt > 0 { if teamMember.DeleteAt > 0 {
return nil, model.NewAppError("AddUserToChannel", "api.channel.add_user.to.channel.failed.deleted.app_error", nil, "", http.StatusBadRequest) return nil, model.NewAppError("AddUserToChannel", "api.channel.add_user.to.channel.failed.deleted.app_error", nil, "", http.StatusBadRequest)
}
} }
newMember, err := a.addUserToChannel(user, channel) newMember, err := a.addUserToChannel(user, channel)
@@ -1405,7 +1403,18 @@ func (a *App) AddUserToChannel(user *model.User, channel *model.Channel) (*model
return newMember, nil return newMember, nil
} }
func (a *App) AddChannelMember(userID string, channel *model.Channel, userRequestorId string, postRootId string) (*model.ChannelMember, *model.AppError) { type ChannelMemberOpts struct {
UserRequestorID string
PostRootID string
// SkipTeamMemberIntegrityCheck is used to indicate whether it should be checked
// that a user has already been removed from that team or not.
// This is useful to avoid in scenarios when we just added the team member,
// and thereby know that there is no need to check this.
SkipTeamMemberIntegrityCheck bool
}
// AddChannelMember adds a user to a channel. It is a wrapper over AddUserToChannel.
func (a *App) AddChannelMember(userID string, channel *model.Channel, opts ChannelMemberOpts) (*model.ChannelMember, *model.AppError) {
if member, err := a.Srv().Store.Channel().GetMember(context.Background(), channel.Id, userID); err != nil { if member, err := a.Srv().Store.Channel().GetMember(context.Background(), channel.Id, userID); err != nil {
var nfErr *store.ErrNotFound var nfErr *store.ErrNotFound
if !errors.As(err, &nfErr) { if !errors.As(err, &nfErr) {
@@ -1423,13 +1432,13 @@ func (a *App) AddChannelMember(userID string, channel *model.Channel, userReques
} }
var userRequestor *model.User var userRequestor *model.User
if userRequestorId != "" { if opts.UserRequestorID != "" {
if userRequestor, err = a.GetUser(userRequestorId); err != nil { if userRequestor, err = a.GetUser(opts.UserRequestorID); err != nil {
return nil, err return nil, err
} }
} }
cm, err := a.AddUserToChannel(user, channel) cm, err := a.AddUserToChannel(user, channel, opts.SkipTeamMemberIntegrityCheck)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -1444,11 +1453,11 @@ func (a *App) AddChannelMember(userID string, channel *model.Channel, userReques
}) })
} }
if userRequestorId == "" || userID == userRequestorId { if opts.UserRequestorID == "" || userID == opts.UserRequestorID {
a.postJoinChannelMessage(user, channel) a.postJoinChannelMessage(user, channel)
} else { } else {
a.Srv().Go(func() { a.Srv().Go(func() {
a.PostAddToChannelMessage(userRequestor, user, channel, postRootId) a.PostAddToChannelMessage(userRequestor, user, channel, opts.PostRootID)
}) })
} }
@@ -1938,7 +1947,7 @@ func (a *App) JoinChannel(channel *model.Channel, userID string) *model.AppError
return model.NewAppError("JoinChannel", "api.channel.join_channel.permissions.app_error", nil, "", http.StatusBadRequest) return model.NewAppError("JoinChannel", "api.channel.join_channel.permissions.app_error", nil, "", http.StatusBadRequest)
} }
cm, err := a.AddUserToChannel(user, channel) cm, err := a.AddUserToChannel(user, channel, false)
if err != nil { if err != nil {
return err return err
} }

Просмотреть файл

@@ -87,7 +87,7 @@ func TestRemoveAllDeactivatedMembersFromChannel(t *testing.T) {
deacivatedUser := th.CreateUser() deacivatedUser := th.CreateUser()
_, _, err = th.App.AddUserToTeam(team.Id, deacivatedUser.Id, "") _, _, err = th.App.AddUserToTeam(team.Id, deacivatedUser.Id, "")
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(deacivatedUser, channel) _, err = th.App.AddUserToChannel(deacivatedUser, channel, false)
require.Nil(t, err) require.Nil(t, err)
channelMembers, err := th.App.GetChannelMembersPage(channel.Id, 0, 10000000) channelMembers, err := th.App.GetChannelMembersPage(channel.Id, 0, 10000000)
require.Nil(t, err) require.Nil(t, err)
@@ -127,10 +127,10 @@ func TestMoveChannel(t *testing.T) {
_, _, err = th.App.AddUserToTeam(targetTeam.Id, th.BasicUser.Id, "") _, _, err = th.App.AddUserToTeam(targetTeam.Id, th.BasicUser.Id, "")
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(th.BasicUser, channel1) _, err = th.App.AddUserToChannel(th.BasicUser, channel1, false)
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(th.BasicUser2, channel1) _, err = th.App.AddUserToChannel(th.BasicUser2, channel1, false)
require.Nil(t, err) require.Nil(t, err)
err = th.App.MoveChannel(targetTeam, channel1, th.BasicUser) err = th.App.MoveChannel(targetTeam, channel1, th.BasicUser)
@@ -150,10 +150,10 @@ func TestMoveChannel(t *testing.T) {
_, _, err = th.App.AddUserToTeam(sourceTeam.Id, deacivatedUser.Id, "") _, _, err = th.App.AddUserToTeam(sourceTeam.Id, deacivatedUser.Id, "")
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(th.BasicUser, channel2) _, err = th.App.AddUserToChannel(th.BasicUser, channel2, false)
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(deacivatedUser, channel2) _, err = th.App.AddUserToChannel(deacivatedUser, channel2, false)
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.UpdateActive(deacivatedUser, false) _, err = th.App.UpdateActive(deacivatedUser, false)
@@ -241,9 +241,9 @@ func TestRemoveUsersFromChannelNotMemberOfTeam(t *testing.T) {
_, _, err = th.App.AddUserToTeam(team.Id, th.BasicUser2.Id, "") _, _, err = th.App.AddUserToTeam(team.Id, th.BasicUser2.Id, "")
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(th.BasicUser, channel1) _, err = th.App.AddUserToChannel(th.BasicUser, channel1, false)
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(th.BasicUser2, channel1) _, err = th.App.AddUserToChannel(th.BasicUser2, channel1, false)
require.Nil(t, err) require.Nil(t, err)
err = th.App.RemoveUsersFromChannelNotMemberOfTeam(th.SystemAdminUser, channel1, team2) err = th.App.RemoveUsersFromChannelNotMemberOfTeam(th.SystemAdminUser, channel1, team2)
@@ -495,7 +495,7 @@ func TestAddUserToChannelCreatesChannelMemberHistoryRecord(t *testing.T) {
channel := th.createChannel(th.BasicTeam, model.CHANNEL_OPEN) channel := th.createChannel(th.BasicTeam, model.CHANNEL_OPEN)
_, err = th.App.AddUserToChannel(user, channel) _, err = th.App.AddUserToChannel(user, channel, false)
require.Nil(t, err, "Failed to add user to channel.") require.Nil(t, err, "Failed to add user to channel.")
// there should be a ChannelMemberHistory record for the user // there should be a ChannelMemberHistory record for the user
@@ -581,9 +581,8 @@ func TestAddChannelMemberNoUserRequestor(t *testing.T) {
groupUserIds = append(groupUserIds, user.Id) groupUserIds = append(groupUserIds, user.Id)
channel := th.createChannel(th.BasicTeam, model.CHANNEL_OPEN) channel := th.createChannel(th.BasicTeam, model.CHANNEL_OPEN)
userRequestorId := ""
postRootId := "" _, err = th.App.AddChannelMember(user.Id, channel, ChannelMemberOpts{})
_, err = th.App.AddChannelMember(user.Id, channel, userRequestorId, postRootId)
require.Nil(t, err, "Failed to add user to channel.") require.Nil(t, err, "Failed to add user to channel.")
// there should be a ChannelMemberHistory record for the user // there should be a ChannelMemberHistory record for the user
@@ -952,9 +951,7 @@ func TestGetChannelMembersTimezones(t *testing.T) {
th := Setup(t).InitBasic() th := Setup(t).InitBasic()
defer th.TearDown() defer th.TearDown()
userRequestorId := "" _, err := th.App.AddChannelMember(th.BasicUser2.Id, th.BasicChannel, ChannelMemberOpts{})
postRootId := ""
_, err := th.App.AddChannelMember(th.BasicUser2.Id, th.BasicChannel, userRequestorId, postRootId)
require.Nil(t, err, "Failed to add user to channel.") require.Nil(t, err, "Failed to add user to channel.")
user := th.BasicUser user := th.BasicUser
@@ -968,14 +965,14 @@ func TestGetChannelMembersTimezones(t *testing.T) {
user3 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} user3 := 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(&user3) ruser, _ := th.App.CreateUser(&user3)
th.App.AddUserToChannel(ruser, th.BasicChannel) th.App.AddUserToChannel(ruser, th.BasicChannel, false)
ruser.Timezone["automaticTimezone"] = "NoWhere/Island" ruser.Timezone["automaticTimezone"] = "NoWhere/Island"
th.App.UpdateUser(ruser, false) th.App.UpdateUser(ruser, false)
user4 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} user4 := 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(&user4) ruser, _ = th.App.CreateUser(&user4)
th.App.AddUserToChannel(ruser, th.BasicChannel) th.App.AddUserToChannel(ruser, th.BasicChannel, false)
timezones, err := th.App.GetChannelMembersTimezones(th.BasicChannel.Id) timezones, err := th.App.GetChannelMembersTimezones(th.BasicChannel.Id)
require.Nil(t, err, "Failed to get the timezones for a channel.") require.Nil(t, err, "Failed to get the timezones for a channel.")
@@ -1101,7 +1098,7 @@ func TestUpdateChannelMemberRolesChangingGuest(t *testing.T) {
_, _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, "") _, _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, "")
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(ruser, th.BasicChannel) _, err = th.App.AddUserToChannel(ruser, th.BasicChannel, false)
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.UpdateChannelMemberRoles(th.BasicChannel.Id, ruser.Id, "channel_user") _, err = th.App.UpdateChannelMemberRoles(th.BasicChannel.Id, ruser.Id, "channel_user")
@@ -1115,7 +1112,7 @@ func TestUpdateChannelMemberRolesChangingGuest(t *testing.T) {
_, _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, "") _, _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, "")
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(ruser, th.BasicChannel) _, err = th.App.AddUserToChannel(ruser, th.BasicChannel, false)
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.UpdateChannelMemberRoles(th.BasicChannel.Id, ruser.Id, "channel_guest") _, err = th.App.UpdateChannelMemberRoles(th.BasicChannel.Id, ruser.Id, "channel_guest")
@@ -1129,7 +1126,7 @@ func TestUpdateChannelMemberRolesChangingGuest(t *testing.T) {
_, _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, "") _, _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, "")
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(ruser, th.BasicChannel) _, err = th.App.AddUserToChannel(ruser, th.BasicChannel, false)
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.UpdateChannelMemberRoles(th.BasicChannel.Id, ruser.Id, "channel_user channel_admin") _, err = th.App.UpdateChannelMemberRoles(th.BasicChannel.Id, ruser.Id, "channel_user channel_admin")
@@ -1143,7 +1140,7 @@ func TestUpdateChannelMemberRolesChangingGuest(t *testing.T) {
_, _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, "") _, _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, "")
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(ruser, th.BasicChannel) _, err = th.App.AddUserToChannel(ruser, th.BasicChannel, false)
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.CreateRole(&model.Role{Name: "custom", DisplayName: "custom", Description: "custom"}) _, err = th.App.CreateRole(&model.Role{Name: "custom", DisplayName: "custom", Description: "custom"})
@@ -1160,7 +1157,7 @@ func TestUpdateChannelMemberRolesChangingGuest(t *testing.T) {
_, _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, "") _, _, err := th.App.AddUserToTeam(th.BasicTeam.Id, ruser.Id, "")
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(ruser, th.BasicChannel) _, err = th.App.AddUserToChannel(ruser, th.BasicChannel, false)
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.UpdateChannelMemberRoles(th.BasicChannel.Id, ruser.Id, "channel_guest channel_user") _, err = th.App.UpdateChannelMemberRoles(th.BasicChannel.Id, ruser.Id, "channel_guest channel_user")
@@ -1205,9 +1202,9 @@ func TestSearchChannelsForUser(t *testing.T) {
}() }()
// add user to test-dev-1 and dev3 // add user to test-dev-1 and dev3
_, err = th.App.AddUserToChannel(th.BasicUser, c1) _, err = th.App.AddUserToChannel(th.BasicUser, c1, false)
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(th.BasicUser, c3) _, err = th.App.AddUserToChannel(th.BasicUser, c3, false)
require.Nil(t, err) require.Nil(t, err)
searchAndCheck := func(t *testing.T, term string, expectedDisplayNames []string) { searchAndCheck := func(t *testing.T, term string, expectedDisplayNames []string) {
@@ -1231,7 +1228,7 @@ func TestSearchChannelsForUser(t *testing.T) {
}) })
t.Run("After adding user to test-dev-2, search for dev, the three channels should be returned", func(t *testing.T) { t.Run("After adding user to test-dev-2, search for dev, the three channels should be returned", func(t *testing.T) {
_, err = th.App.AddUserToChannel(th.BasicUser, c2) _, err = th.App.AddUserToChannel(th.BasicUser, c2, false)
require.Nil(t, err) require.Nil(t, err)
searchAndCheck(t, "dev", []string{"test-dev-1", "test-dev-2", "dev-3"}) searchAndCheck(t, "dev", []string{"test-dev-1", "test-dev-2", "dev-3"})
@@ -1332,7 +1329,7 @@ func TestMarkChannelAsUnreadFromPost(t *testing.T) {
t.Run("Unread with mentions", func(t *testing.T) { t.Run("Unread with mentions", func(t *testing.T) {
c2 := th.CreateChannel(th.BasicTeam) c2 := th.CreateChannel(th.BasicTeam)
_, err := th.App.AddUserToChannel(u2, c2) _, err := th.App.AddUserToChannel(u2, c2, false)
require.Nil(t, err) require.Nil(t, err)
p4, err := th.App.CreatePost(&model.Post{ p4, err := th.App.CreatePost(&model.Post{
@@ -1445,7 +1442,7 @@ func TestAddUserToChannel(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
// Should allow a bot to be added to a public group synced channel // Should allow a bot to be added to a public group synced channel
_, err = th.App.AddUserToChannel(botUser, th.BasicChannel) _, err = th.App.AddUserToChannel(botUser, th.BasicChannel, false)
require.Nil(t, err) require.Nil(t, err)
// verify user was added as an admin // verify user was added as an admin
@@ -1466,11 +1463,11 @@ func TestAddUserToChannel(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
// Should allow a group synced user to be added to a group synced private channel // Should allow a group synced user to be added to a group synced private channel
_, err = th.App.AddUserToChannel(ruser1, privateChannel) _, err = th.App.AddUserToChannel(ruser1, privateChannel, false)
require.Nil(t, err) require.Nil(t, err)
// Should allow a bot to be added to a private group synced channel // Should allow a bot to be added to a private group synced channel
_, err = th.App.AddUserToChannel(botUser, privateChannel) _, err = th.App.AddUserToChannel(botUser, privateChannel, false)
require.Nil(t, err) require.Nil(t, err)
} }
@@ -1491,9 +1488,9 @@ func TestRemoveUserFromChannel(t *testing.T) {
privateChannel := th.CreatePrivateChannel(th.BasicTeam) privateChannel := th.CreatePrivateChannel(th.BasicTeam)
_, err := th.App.AddUserToChannel(ruser, privateChannel) _, err := th.App.AddUserToChannel(ruser, privateChannel, false)
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddUserToChannel(botUser, privateChannel) _, err = th.App.AddUserToChannel(botUser, privateChannel, false)
require.Nil(t, err) require.Nil(t, err)
group := th.CreateGroup() group := th.CreateGroup()

Просмотреть файл

@@ -422,7 +422,7 @@ func (th *TestHelper) RemoveUserFromTeam(user *model.User, team *model.Team) {
func (th *TestHelper) AddUserToChannel(user *model.User, channel *model.Channel) *model.ChannelMember { func (th *TestHelper) AddUserToChannel(user *model.User, channel *model.Channel) *model.ChannelMember {
utils.DisableDebugLogForTest() utils.DisableDebugLogForTest()
member, err := th.App.AddUserToChannel(user, channel) member, err := th.App.AddUserToChannel(user, channel, false)
if err != nil { if err != nil {
panic(err) panic(err)
} }

Просмотреть файл

@@ -19,7 +19,7 @@ func TestSendNotifications(t *testing.T) {
th := Setup(t).InitBasic() th := Setup(t).InitBasic()
defer th.TearDown() defer th.TearDown()
th.App.AddUserToChannel(th.BasicUser2, th.BasicChannel) th.App.AddUserToChannel(th.BasicUser2, th.BasicChannel, false)
post1, appErr := th.App.CreatePostMissingChannel(&model.Post{ post1, appErr := th.App.CreatePostMissingChannel(&model.Post{
UserId: th.BasicUser.Id, UserId: th.BasicUser.Id,
@@ -126,7 +126,7 @@ func TestSendNotificationsWithManyUsers(t *testing.T) {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
user := th.CreateUser() user := th.CreateUser()
th.LinkUserToTeam(user, th.BasicTeam) th.LinkUserToTeam(user, th.BasicTeam)
th.App.AddUserToChannel(user, th.BasicChannel) th.App.AddUserToChannel(user, th.BasicChannel, false)
users = append(users, user) users = append(users, user)
} }
@@ -217,9 +217,9 @@ func TestFilterOutOfChannelMentions(t *testing.T) {
th.LinkUserToTeam(user3, th.BasicTeam) th.LinkUserToTeam(user3, th.BasicTeam)
th.LinkUserToTeam(user4, th.BasicTeam) th.LinkUserToTeam(user4, th.BasicTeam)
th.LinkUserToTeam(guest, th.BasicTeam) th.LinkUserToTeam(guest, th.BasicTeam)
th.App.AddUserToChannel(guest, channel) th.App.AddUserToChannel(guest, channel, false)
th.App.AddUserToChannel(user4, guestAndUser4Channel) th.App.AddUserToChannel(user4, guestAndUser4Channel, false)
th.App.AddUserToChannel(guest, guestAndUser4Channel) th.App.AddUserToChannel(guest, guestAndUser4Channel, false)
t.Run("should return users not in the channel", func(t *testing.T) { t.Run("should return users not in the channel", func(t *testing.T) {
post := &model.Post{} post := &model.Post{}
@@ -2420,13 +2420,13 @@ func TestInsertGroupMentions(t *testing.T) {
groupChannelMember := th.CreateUser() groupChannelMember := th.CreateUser()
th.LinkUserToTeam(groupChannelMember, team) th.LinkUserToTeam(groupChannelMember, team)
th.App.AddUserToChannel(groupChannelMember, channel) th.App.AddUserToChannel(groupChannelMember, channel, false)
_, err = th.App.UpsertGroupMember(group.Id, groupChannelMember.Id) _, err = th.App.UpsertGroupMember(group.Id, groupChannelMember.Id)
require.Nil(t, err) require.Nil(t, err)
nonGroupChannelMember := th.CreateUser() nonGroupChannelMember := th.CreateUser()
th.LinkUserToTeam(nonGroupChannelMember, team) th.LinkUserToTeam(nonGroupChannelMember, team)
th.App.AddUserToChannel(nonGroupChannelMember, channel) th.App.AddUserToChannel(nonGroupChannelMember, channel, false)
nonChannelGroupMember := th.CreateUser() nonChannelGroupMember := th.CreateUser()
th.LinkUserToTeam(nonChannelGroupMember, team) th.LinkUserToTeam(nonChannelGroupMember, team)

Просмотреть файл

@@ -94,7 +94,7 @@ func (a *OpenTracingAppLayer) ActivateMfa(userID string, token string) *model.Ap
return resultVar0 return resultVar0
} }
func (a *OpenTracingAppLayer) AddChannelMember(userID string, channel *model.Channel, userRequestorId string, postRootId string) (*model.ChannelMember, *model.AppError) { func (a *OpenTracingAppLayer) AddChannelMember(userID string, channel *model.Channel, opts app.ChannelMemberOpts) (*model.ChannelMember, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AddChannelMember") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AddChannelMember")
@@ -106,7 +106,7 @@ func (a *OpenTracingAppLayer) AddChannelMember(userID string, channel *model.Cha
}() }()
defer span.Finish() defer span.Finish()
resultVar0, resultVar1 := a.app.AddChannelMember(userID, channel, userRequestorId, postRootId) resultVar0, resultVar1 := a.app.AddChannelMember(userID, channel, opts)
if resultVar1 != nil { if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1)) span.LogFields(spanlog.Error(resultVar1))
@@ -457,7 +457,7 @@ func (a *OpenTracingAppLayer) AddTeamMembers(teamID string, userIDs []string, us
return resultVar0, resultVar1 return resultVar0, resultVar1
} }
func (a *OpenTracingAppLayer) AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelMember, *model.AppError) { func (a *OpenTracingAppLayer) AddUserToChannel(user *model.User, channel *model.Channel, skipTeamMemberIntegrityCheck bool) (*model.ChannelMember, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AddUserToChannel") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AddUserToChannel")
@@ -469,7 +469,7 @@ func (a *OpenTracingAppLayer) AddUserToChannel(user *model.User, channel *model.
}() }()
defer span.Finish() defer span.Finish()
resultVar0, resultVar1 := a.app.AddUserToChannel(user, channel) resultVar0, resultVar1 := a.app.AddUserToChannel(user, channel, skipTeamMemberIntegrityCheck)
if resultVar1 != nil { if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1)) span.LogFields(spanlog.Error(resultVar1))

Просмотреть файл

@@ -478,27 +478,27 @@ func (api *PluginAPI) SearchPostsInTeamForUser(teamID string, userID string, sea
} }
func (api *PluginAPI) AddChannelMember(channelID, userID string) (*model.ChannelMember, *model.AppError) { func (api *PluginAPI) AddChannelMember(channelID, userID string) (*model.ChannelMember, *model.AppError) {
// For now, don't allow overriding these via the plugin API.
userRequestorId := ""
postRootId := ""
channel, err := api.GetChannel(channelID) channel, err := api.GetChannel(channelID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return api.app.AddChannelMember(userID, channel, userRequestorId, postRootId) return api.app.AddChannelMember(userID, channel, ChannelMemberOpts{
// For now, don't allow overriding these via the plugin API.
UserRequestorID: "",
PostRootID: "",
})
} }
func (api *PluginAPI) AddUserToChannel(channelID, userID, asUserId string) (*model.ChannelMember, *model.AppError) { func (api *PluginAPI) AddUserToChannel(channelID, userID, asUserID string) (*model.ChannelMember, *model.AppError) {
postRootId := ""
channel, err := api.GetChannel(channelID) channel, err := api.GetChannel(channelID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return api.app.AddChannelMember(userID, channel, asUserId, postRootId) return api.app.AddChannelMember(userID, channel, ChannelMemberOpts{
UserRequestorID: asUserID,
})
} }
func (api *PluginAPI) GetChannelMember(channelID, userID string) (*model.ChannelMember, *model.AppError) { func (api *PluginAPI) GetChannelMember(channelID, userID string) (*model.ChannelMember, *model.AppError) {

Просмотреть файл

@@ -338,7 +338,7 @@ func TestPostReplyToPostWhereRootPosterLeftChannel(t *testing.T) {
userNotInChannel := th.BasicUser userNotInChannel := th.BasicUser
rootPost := th.BasicPost rootPost := th.BasicPost
_, err := th.App.AddUserToChannel(userInChannel, channel) _, err := th.App.AddUserToChannel(userInChannel, channel, false)
require.Nil(t, err) require.Nil(t, err)
err = th.App.RemoveUserFromChannel(userNotInChannel.Id, "", channel) err = th.App.RemoveUserFromChannel(userNotInChannel.Id, "", channel)
@@ -421,7 +421,7 @@ func TestPostChannelMentions(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
defer th.App.PermanentDeleteChannel(channelToMention) defer th.App.PermanentDeleteChannel(channelToMention)
_, err = th.App.AddUserToChannel(user, channel) _, err = th.App.AddUserToChannel(user, channel, false)
require.Nil(t, err) require.Nil(t, err)
post := &model.Post{ post := &model.Post{

Просмотреть файл

@@ -140,7 +140,9 @@ func (*InviteProvider) DoCommand(a *app.App, args *model.CommandArgs, message st
} }
} }
if _, err := a.AddChannelMember(userProfile.Id, channelToJoin, args.UserId, ""); err != nil { if _, err := a.AddChannelMember(userProfile.Id, channelToJoin, app.ChannelMemberOpts{
UserRequestorID: args.UserId,
}); err != nil {
var text string var text string
if err.Id == "api.channel.add_members.user_denied" { if err.Id == "api.channel.add_members.user_denied" {
text = args.T("api.command_invite.group_constrained_user_denied") text = args.T("api.command_invite.group_constrained_user_denied")

Просмотреть файл

@@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/v5/app"
"github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/model"
) )
@@ -72,7 +73,7 @@ func TestInviteProvider(t *testing.T) {
deactivatedUserPublicChannel := "@" + deactivatedUser.Username + " ~" + channel.Name deactivatedUserPublicChannel := "@" + deactivatedUser.Username + " ~" + channel.Name
groupChannel := th.createChannel(th.BasicTeam, model.CHANNEL_PRIVATE) groupChannel := th.createChannel(th.BasicTeam, model.CHANNEL_PRIVATE)
_, err = th.App.AddChannelMember(th.BasicUser.Id, groupChannel, "", "") _, err = th.App.AddChannelMember(th.BasicUser.Id, groupChannel, app.ChannelMemberOpts{})
require.Nil(t, err) require.Nil(t, err)
groupChannel.GroupConstrained = model.NewBool(true) groupChannel.GroupConstrained = model.NewBool(true)
groupChannel, _ = th.App.UpdateChannel(groupChannel) groupChannel, _ = th.App.UpdateChannel(groupChannel)

Просмотреть файл

@@ -41,11 +41,11 @@ func TestLeaveProviderDoCommand(t *testing.T) {
guest := th.createGuest() guest := th.createGuest()
th.App.AddUserToTeam(th.BasicTeam.Id, th.BasicUser.Id, th.BasicUser.Id) th.App.AddUserToTeam(th.BasicTeam.Id, th.BasicUser.Id, th.BasicUser.Id)
th.App.AddUserToChannel(th.BasicUser, publicChannel) th.App.AddUserToChannel(th.BasicUser, publicChannel, false)
th.App.AddUserToChannel(th.BasicUser, privateChannel) th.App.AddUserToChannel(th.BasicUser, privateChannel, false)
th.App.AddUserToTeam(th.BasicTeam.Id, guest.Id, guest.Id) th.App.AddUserToTeam(th.BasicTeam.Id, guest.Id, guest.Id)
th.App.AddUserToChannel(guest, publicChannel) th.App.AddUserToChannel(guest, publicChannel, false)
th.App.AddUserToChannel(guest, defaultChannel) th.App.AddUserToChannel(guest, defaultChannel, false)
t.Run("Should error when no Channel ID in args", func(t *testing.T) { t.Run("Should error when no Channel ID in args", func(t *testing.T) {
args := &model.CommandArgs{ args := &model.CommandArgs{

Просмотреть файл

@@ -35,8 +35,8 @@ func TestRemoveProviderDoCommand(t *testing.T) {
targetUser := th.createUser() targetUser := th.createUser()
th.App.AddUserToTeam(th.BasicTeam.Id, targetUser.Id, targetUser.Id) th.App.AddUserToTeam(th.BasicTeam.Id, targetUser.Id, targetUser.Id)
th.App.AddUserToChannel(targetUser, publicChannel) th.App.AddUserToChannel(targetUser, publicChannel, false)
th.App.AddUserToChannel(targetUser, privateChannel) th.App.AddUserToChannel(targetUser, privateChannel, false)
// Try a public channel *without* permission. // Try a public channel *without* permission.
args := &model.CommandArgs{ args := &model.CommandArgs{
@@ -49,7 +49,7 @@ func TestRemoveProviderDoCommand(t *testing.T) {
assert.Equal(t, "api.command_remove.permission.app_error", actual) assert.Equal(t, "api.command_remove.permission.app_error", actual)
// Try a public channel *with* permission. // Try a public channel *with* permission.
th.App.AddUserToChannel(th.BasicUser, publicChannel) th.App.AddUserToChannel(th.BasicUser, publicChannel, false)
args = &model.CommandArgs{ args = &model.CommandArgs{
T: func(s string, args ...interface{}) string { return s }, T: func(s string, args ...interface{}) string { return s },
ChannelId: publicChannel.Id, ChannelId: publicChannel.Id,
@@ -70,7 +70,7 @@ func TestRemoveProviderDoCommand(t *testing.T) {
assert.Equal(t, "api.command_remove.permission.app_error", actual) assert.Equal(t, "api.command_remove.permission.app_error", actual)
// Try a private channel *with* permission. // Try a private channel *with* permission.
th.App.AddUserToChannel(th.BasicUser, privateChannel) th.App.AddUserToChannel(th.BasicUser, privateChannel, false)
args = &model.CommandArgs{ args = &model.CommandArgs{
T: func(s string, args ...interface{}) string { return s }, T: func(s string, args ...interface{}) string { return s },
ChannelId: privateChannel.Id, ChannelId: privateChannel.Id,
@@ -110,7 +110,7 @@ func TestRemoveProviderDoCommand(t *testing.T) {
// Try a public channel with a deactivated user. // Try a public channel with a deactivated user.
deactivatedUser := th.createUser() deactivatedUser := th.createUser()
th.App.AddUserToTeam(th.BasicTeam.Id, deactivatedUser.Id, deactivatedUser.Id) th.App.AddUserToTeam(th.BasicTeam.Id, deactivatedUser.Id, deactivatedUser.Id)
th.App.AddUserToChannel(deactivatedUser, publicChannel) th.App.AddUserToChannel(deactivatedUser, publicChannel, false)
th.App.UpdateActive(deactivatedUser, false) th.App.UpdateActive(deactivatedUser, false)
args = &model.CommandArgs{ args = &model.CommandArgs{

Просмотреть файл

@@ -358,7 +358,7 @@ func (th *TestHelper) linkUserToTeam(user *model.User, team *model.Team) {
func (th *TestHelper) addUserToChannel(user *model.User, channel *model.Channel) *model.ChannelMember { func (th *TestHelper) addUserToChannel(user *model.User, channel *model.Channel) *model.ChannelMember {
utils.DisableDebugLogForTest() utils.DisableDebugLogForTest()
member, err := th.App.AddUserToChannel(user, channel) member, err := th.App.AddUserToChannel(user, channel, false)
if err != nil { if err != nil {
panic(err) panic(err)
} }

Просмотреть файл

@@ -52,7 +52,9 @@ func (a *App) createDefaultChannelMemberships(since int64, channelID *string) er
) )
} }
_, err = a.AddChannelMember(userChannel.UserID, channel, "", "") _, err = a.AddChannelMember(userChannel.UserID, channel, ChannelMemberOpts{
SkipTeamMemberIntegrityCheck: true,
})
if err != nil { if err != nil {
if err.Id == "api.channel.add_user.to.channel.failed.deleted.app_error" { if err.Id == "api.channel.add_user.to.channel.failed.deleted.app_error" {
a.Log().Info("Not adding user to channel because they have already left the team", a.Log().Info("Not adding user to channel because they have already left the team",

Просмотреть файл

@@ -262,7 +262,7 @@ func TestCreateDefaultMemberships(t *testing.T) {
} }
// Ensure members are in channel // Ensure members are in channel
_, err = th.App.AddChannelMember(scientist1.Id, experimentsChannel, "", "") _, err = th.App.AddChannelMember(scientist1.Id, experimentsChannel, ChannelMemberOpts{})
if err != nil { if err != nil {
t.Errorf("unable to add user to channel: %s", err.Error()) t.Errorf("unable to add user to channel: %s", err.Error())
} }
@@ -272,7 +272,7 @@ func TestCreateDefaultMemberships(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("unable to add user to team: %s", err.Error()) t.Errorf("unable to add user to team: %s", err.Error())
} }
_, err = th.App.AddChannelMember(singer1.Id, experimentsChannel, "", "") _, err = th.App.AddChannelMember(singer1.Id, experimentsChannel, ChannelMemberOpts{})
if err != nil { if err != nil {
t.Errorf("unable to add user to channel: %s", err.Error()) t.Errorf("unable to add user to channel: %s", err.Error())
} }
@@ -388,7 +388,7 @@ func TestDeleteGroupMemberships(t *testing.T) {
_, err = th.App.AddTeamMember(th.BasicTeam.Id, userID) _, err = th.App.AddTeamMember(th.BasicTeam.Id, userID)
require.Nil(t, err) require.Nil(t, err)
_, err = th.App.AddChannelMember(userID, th.BasicChannel, "", "") _, err = th.App.AddChannelMember(userID, th.BasicChannel, ChannelMemberOpts{})
require.Nil(t, err) require.Nil(t, err)
} }

Просмотреть файл

@@ -623,7 +623,7 @@ func (a *App) AddUserToTeamByToken(userID string, tokenID string) (*model.Team,
} }
for _, channel := range channels { for _, channel := range channels {
_, err := a.AddUserToChannel(user, channel) _, err := a.AddUserToChannel(user, channel, false)
if err != nil { if err != nil {
mlog.Warn("Error adding user to channel", mlog.Err(err)) mlog.Warn("Error adding user to channel", mlog.Err(err))
} }

Просмотреть файл

@@ -104,7 +104,7 @@ func (a *App) CreateUserWithToken(user *model.User, token *model.Token) (*model.
if token.Type == TokenTypeGuestInvitation { if token.Type == TokenTypeGuestInvitation {
for _, channel := range channels { for _, channel := range channels {
_, err := a.AddChannelMember(ruser.Id, channel, "", "") _, err := a.AddChannelMember(ruser.Id, channel, ChannelMemberOpts{})
if err != nil { if err != nil {
mlog.Warn("Failed to add channel member", mlog.Err(err)) mlog.Warn("Failed to add channel member", mlog.Err(err))
} }

Просмотреть файл

@@ -993,9 +993,9 @@ func TestGetViewUsersRestrictions(t *testing.T) {
team2townsquare, err := th.App.GetChannelByName("town-square", team2.Id, false) team2townsquare, err := th.App.GetChannelByName("town-square", team2.Id, false)
require.Nil(t, err) require.Nil(t, err)
th.App.AddUserToChannel(user1, team1channel1) th.App.AddUserToChannel(user1, team1channel1, false)
th.App.AddUserToChannel(user1, team1channel2) th.App.AddUserToChannel(user1, team1channel2, false)
th.App.AddUserToChannel(user1, team2channel1) th.App.AddUserToChannel(user1, team2channel1, false)
addPermission := func(role *model.Role, permission string) *model.AppError { addPermission := func(role *model.Role, permission string) *model.AppError {
newPermissions := append(role.Permissions, permission) newPermissions := append(role.Permissions, permission)

Просмотреть файл

@@ -311,7 +311,7 @@ func addUserToChannel(a *app.App, channel *model.Channel, user *model.User, user
CommandPrintErrorln("Can't find user '" + userArg + "'") CommandPrintErrorln("Can't find user '" + userArg + "'")
return return
} }
if _, err := a.AddUserToChannel(user, channel); err != nil { if _, err := a.AddUserToChannel(user, channel, false); err != nil {
CommandPrintErrorln("Unable to add '" + userArg + "' from " + channel.Name + ". Error: " + err.Error()) CommandPrintErrorln("Unable to add '" + userArg + "' from " + channel.Name + ". Error: " + err.Error())
return return
} }

Просмотреть файл

@@ -217,7 +217,7 @@ func (th *TestHelper) LinkUserToTeam(user *model.User, team *model.Team) {
func (th *TestHelper) AddUserToChannel(user *model.User, channel *model.Channel) *model.ChannelMember { func (th *TestHelper) AddUserToChannel(user *model.User, channel *model.Channel) *model.ChannelMember {
utils.DisableDebugLogForTest() utils.DisableDebugLogForTest()
member, err := th.App.AddUserToChannel(user, channel) member, err := th.App.AddUserToChannel(user, channel, false)
if err != nil { if err != nil {
panic(err) panic(err)
} }

Просмотреть файл

@@ -16,13 +16,13 @@ type MockAppIface struct {
mock.Mock mock.Mock
} }
// AddUserToChannel provides a mock function with given fields: user, channel // AddUserToChannel provides a mock function with given fields: user, channel, skipTeamMemberIntegrityCheck
func (_m *MockAppIface) AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelMember, *model.AppError) { func (_m *MockAppIface) AddUserToChannel(user *model.User, channel *model.Channel, skipTeamMemberIntegrityCheck bool) (*model.ChannelMember, *model.AppError) {
ret := _m.Called(user, channel) ret := _m.Called(user, channel, skipTeamMemberIntegrityCheck)
var r0 *model.ChannelMember var r0 *model.ChannelMember
if rf, ok := ret.Get(0).(func(*model.User, *model.Channel) *model.ChannelMember); ok { if rf, ok := ret.Get(0).(func(*model.User, *model.Channel, bool) *model.ChannelMember); ok {
r0 = rf(user, channel) r0 = rf(user, channel, skipTeamMemberIntegrityCheck)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.ChannelMember) r0 = ret.Get(0).(*model.ChannelMember)
@@ -30,8 +30,8 @@ func (_m *MockAppIface) AddUserToChannel(user *model.User, channel *model.Channe
} }
var r1 *model.AppError var r1 *model.AppError
if rf, ok := ret.Get(1).(func(*model.User, *model.Channel) *model.AppError); ok { if rf, ok := ret.Get(1).(func(*model.User, *model.Channel, bool) *model.AppError); ok {
r1 = rf(user, channel) r1 = rf(user, channel, skipTeamMemberIntegrityCheck)
} else { } else {
if ret.Get(1) != nil { if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError) r1 = ret.Get(1).(*model.AppError)

Просмотреть файл

@@ -42,7 +42,7 @@ type AppIface interface {
SendEphemeralPost(userId string, post *model.Post) *model.Post SendEphemeralPost(userId string, post *model.Post) *model.Post
CreateChannelWithUser(channel *model.Channel, userId string) (*model.Channel, *model.AppError) CreateChannelWithUser(channel *model.Channel, userId string) (*model.Channel, *model.AppError)
GetOrCreateDirectChannel(userId, otherUserId string, channelOptions ...model.ChannelOption) (*model.Channel, *model.AppError) GetOrCreateDirectChannel(userId, otherUserId string, channelOptions ...model.ChannelOption) (*model.Channel, *model.AppError)
AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelMember, *model.AppError) AddUserToChannel(user *model.User, channel *model.Channel, skipTeamMemberIntegrityCheck bool) (*model.ChannelMember, *model.AppError)
AddUserToTeamByTeamId(teamId string, user *model.User) *model.AppError AddUserToTeamByTeamId(teamId string, user *model.User) *model.AppError
PermanentDeleteChannel(channel *model.Channel) *model.AppError PermanentDeleteChannel(channel *model.Channel) *model.AppError
CreatePost(post *model.Post, channel *model.Channel, triggerWebhooks bool, setOnline bool) (savedPost *model.Post, err *model.AppError) CreatePost(post *model.Post, channel *model.Channel, triggerWebhooks bool, setOnline bool) (savedPost *model.Post, err *model.AppError)

Просмотреть файл

@@ -222,7 +222,7 @@ func (scs *Service) upsertSyncUser(user *model.User, channel *model.Channel, rc
} }
// add user to channel // add user to channel
if _, err := scs.app.AddUserToChannel(userSaved, channel); err != nil { if _, err := scs.app.AddUserToChannel(userSaved, channel, false); err != nil {
return nil, fmt.Errorf("error adding sync user to ChannelMembers: %w", err) return nil, fmt.Errorf("error adding sync user to ChannelMembers: %w", err)
} }
return userSaved, nil return userSaved, nil

Просмотреть файл

@@ -83,7 +83,7 @@ type slackComment struct {
// Actions provides the actions that needs to be used for import slack data // Actions provides the actions that needs to be used for import slack data
type Actions struct { type Actions struct {
UpdateActive func(*model.User, bool) (*model.User, *model.AppError) UpdateActive func(*model.User, bool) (*model.User, *model.AppError)
AddUserToChannel func(*model.User, *model.Channel) (*model.ChannelMember, *model.AppError) AddUserToChannel func(*model.User, *model.Channel, bool) (*model.ChannelMember, *model.AppError)
JoinUserToTeam func(*model.Team, *model.User, string) (*model.TeamMember, *model.AppError) JoinUserToTeam func(*model.Team, *model.User, string) (*model.TeamMember, *model.AppError)
CreateDirectChannel func(string, string, ...model.ChannelOption) (*model.Channel, *model.AppError) CreateDirectChannel func(string, string, ...model.ChannelOption) (*model.Channel, *model.AppError)
CreateGroupChannel func([]string) (*model.Channel, *model.AppError) CreateGroupChannel func([]string) (*model.Channel, *model.AppError)
@@ -535,7 +535,7 @@ func (si *SlackImporter) addSlackUsersToChannel(members []string, users map[stri
log.WriteString(i18n.T("api.slackimport.slack_add_channels.failed_to_add_user", map[string]interface{}{"Username": "?"})) log.WriteString(i18n.T("api.slackimport.slack_add_channels.failed_to_add_user", map[string]interface{}{"Username": "?"}))
continue continue
} }
if _, err := si.actions.AddUserToChannel(user, channel); err != nil { if _, err := si.actions.AddUserToChannel(user, channel, false); err != nil {
log.WriteString(i18n.T("api.slackimport.slack_add_channels.failed_to_add_user", map[string]interface{}{"Username": user.Username})) log.WriteString(i18n.T("api.slackimport.slack_add_channels.failed_to_add_user", map[string]interface{}{"Username": user.Username}))
} }
} }