MM-20644: Add users to teams as a SchemeAdmin based on a new configuration field on GroupTeams and GroupChannels records. (#13361)

* MM-20644: Add users to teams as a SchemeAdmin based on a new configuration field on GroupTeams and GroupChannels records.

* MM-20644: Adds SchemeAdmin to mapping of the GroupSyncable struct fields.

* MM-2064: Adds test to ensure SchemeAdmin field value is mapped.

* MM-20644: Adds missing index creation for fresh DBs.

* MM-20644: Duplicates UpdateMembersRole across Team and Channel stores. Adds tests.

* MM-20644: Fixes some old method name references.

* MM-20644: Moves variable declaration; removes Println statement.

* MM-20644: Use a SQL query instead of two to update Team and Channel members.

* MM-20644: Fixes tests; updates query.

* MM-20644: Fix permission check for patching a group syncable.

* MM-20644: Fixes test for change of permissions verification in group patch API request.

* MM-20644: Fix for ORM select vs insert.

* MM-20644: Linting fixes.

* MM-20644: Fixes some tests.

* MM-20644: Skips changing the role of guests.

* MM-20644: Added syncableID filtering
Этот коммит содержится в:
Martin Kraft
2020-01-10 12:19:39 -05:00
коммит произвёл catalintomai
родитель 04430041a8
Коммит 605040c597
21 изменённых файлов: 1207 добавлений и 70 удалений

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

@@ -971,6 +971,16 @@ func (a *App) addUserToChannel(user *model.User, channel *model.Channel, teamMem
SchemeGuest: user.IsGuest(),
SchemeUser: !user.IsGuest(),
}
if !user.IsGuest() {
var userShouldBeAdmin bool
userShouldBeAdmin, err = a.UserIsInAdminRoleGroup(user.Id, channel.Id, model.GroupSyncableTypeChannel)
if err != nil {
return nil, err
}
newMember.SchemeAdmin = userShouldBeAdmin
}
if _, err = a.Srv.Store.Channel().SaveMember(newMember); err != nil {
mlog.Error("Failed to add member", mlog.String("user_id", user.Id), mlog.String("channel_id", channel.Id), mlog.Err(err))
return nil, model.NewAppError("AddUserToChannel", "api.channel.add_user.to.channel.failed.app_error", nil, "", http.StatusInternalServerError)

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

@@ -1161,3 +1161,55 @@ func TestMarkChannelAsUnreadFromPost(t *testing.T) {
assert.Nil(t, response)
})
}
func TestAddUserToChannel(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
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)
defer th.App.PermanentDeleteUser(&user1)
th.App.AddTeamMember(th.BasicTeam.Id, ruser1.Id)
group := th.CreateGroup()
_, err := th.App.UpsertGroupMember(group.Id, user1.Id)
require.Nil(t, err)
gs, err := th.App.UpsertGroupSyncable(&model.GroupSyncable{
AutoAdd: true,
SyncableId: th.BasicChannel.Id,
Type: model.GroupSyncableTypeChannel,
GroupId: group.Id,
SchemeAdmin: false,
})
require.Nil(t, err)
err = th.App.JoinChannel(th.BasicChannel, ruser1.Id)
require.Nil(t, err)
// verify user was added as a non-admin
cm1, err := th.App.GetChannelMember(th.BasicChannel.Id, ruser1.Id)
require.Nil(t, err)
require.False(t, cm1.SchemeAdmin)
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(&user2)
th.App.AddTeamMember(th.BasicTeam.Id, ruser2.Id)
_, err = th.App.UpsertGroupMember(group.Id, user2.Id)
require.Nil(t, err)
gs.SchemeAdmin = true
_, err = th.App.UpdateGroupSyncable(gs)
require.Nil(t, err)
err = th.App.JoinChannel(th.BasicChannel, ruser2.Id)
require.Nil(t, err)
// verify user was added as an admin
cm2, err := th.App.GetChannelMember(th.BasicChannel.Id, ruser2.Id)
require.Nil(t, err)
require.True(t, cm2.SchemeAdmin)
}

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

@@ -168,7 +168,7 @@ func (a *App) ChannelMembersToRemove() ([]*model.ChannelMember, *model.AppError)
return a.Srv.Store.Group().ChannelMembersToRemove()
}
func (a *App) GetGroupsByChannel(channelId string, opts model.GroupSearchOpts) ([]*model.Group, int, *model.AppError) {
func (a *App) GetGroupsByChannel(channelId string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, int, *model.AppError) {
groups, err := a.Srv.Store.Group().GetGroupsByChannel(channelId, opts)
if err != nil {
return nil, 0, err
@@ -182,7 +182,7 @@ func (a *App) GetGroupsByChannel(channelId string, opts model.GroupSearchOpts) (
return groups, int(count), nil
}
func (a *App) GetGroupsByTeam(teamId string, opts model.GroupSearchOpts) ([]*model.Group, int, *model.AppError) {
func (a *App) GetGroupsByTeam(teamId string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, int, *model.AppError) {
groups, err := a.Srv.Store.Group().GetGroupsByTeam(teamId, opts)
if err != nil {
return nil, 0, err
@@ -313,3 +313,18 @@ func (a *App) ChannelMembersMinusGroupMembers(channelID string, groupIDs []strin
}
return users, totalCount, nil
}
// UserIsInAdminRoleGroup returns true at least one of the user's groups are configured to set the members as
// admins in the given syncable.
func (a *App) UserIsInAdminRoleGroup(userID, syncableID string, syncableType model.GroupSyncableType) (bool, *model.AppError) {
groupIDs, err := a.Srv.Store.Group().AdminRoleGroupsForSyncableMember(userID, syncableID, syncableType)
if err != nil {
return false, err
}
if len(groupIDs) == 0 {
return false, nil
}
return true, nil
}

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

@@ -235,7 +235,8 @@ func TestGetGroupsByChannel(t *testing.T) {
groups, _, err := th.App.GetGroupsByChannel(th.BasicChannel.Id, opts)
require.Nil(t, err)
require.ElementsMatch(t, []*model.Group{group}, groups)
require.ElementsMatch(t, []*model.GroupWithSchemeAdmin{{Group: *group, SchemeAdmin: model.NewBool(false)}}, groups)
require.NotNil(t, groups[0].SchemeAdmin)
groups, _, err = th.App.GetGroupsByChannel(model.NewId(), opts)
require.Nil(t, err)
@@ -261,7 +262,8 @@ func TestGetGroupsByTeam(t *testing.T) {
groups, _, err := th.App.GetGroupsByTeam(th.BasicTeam.Id, model.GroupSearchOpts{})
require.Nil(t, err)
require.ElementsMatch(t, []*model.Group{group}, groups)
require.ElementsMatch(t, []*model.GroupWithSchemeAdmin{{Group: *group, SchemeAdmin: model.NewBool(false)}}, groups)
require.NotNil(t, groups[0].SchemeAdmin)
groups, _, err = th.App.GetGroupsByTeam(model.NewId(), model.GroupSearchOpts{})
require.Nil(t, err)
@@ -277,3 +279,55 @@ func TestGetGroups(t *testing.T) {
require.Nil(t, err)
require.ElementsMatch(t, []*model.Group{group}, groups)
}
func TestUserIsInAdminRoleGroup(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
group1 := th.CreateGroup()
group2 := th.CreateGroup()
g, err := th.App.UpsertGroupMember(group1.Id, th.BasicUser.Id)
require.Nil(t, err)
require.NotNil(t, g)
g, err = th.App.UpsertGroupMember(group2.Id, th.BasicUser.Id)
require.Nil(t, err)
require.NotNil(t, g)
_, err = th.App.UpsertGroupSyncable(&model.GroupSyncable{
GroupId: group1.Id,
AutoAdd: false,
SyncableId: th.BasicTeam.Id,
Type: model.GroupSyncableTypeTeam,
})
require.Nil(t, err)
groupSyncable2, err := th.App.UpsertGroupSyncable(&model.GroupSyncable{
GroupId: group2.Id,
AutoAdd: false,
SyncableId: th.BasicTeam.Id,
Type: model.GroupSyncableTypeTeam,
})
require.Nil(t, err)
// no syncables are set to scheme admin true, so this returns false
actual, err := th.App.UserIsInAdminRoleGroup(th.BasicUser.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
require.Nil(t, err)
require.False(t, actual)
// set a syncable to be scheme admins
groupSyncable2.SchemeAdmin = true
_, err = th.App.UpdateGroupSyncable(groupSyncable2)
require.Nil(t, err)
// a syncable is set to scheme admin true, so this returns true
actual, err = th.App.UserIsInAdminRoleGroup(th.BasicUser.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
require.Nil(t, err)
require.True(t, actual)
// delete the syncable, should be false again
th.App.DeleteGroupSyncable(group2.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
actual, err = th.App.UserIsInAdminRoleGroup(th.BasicUser.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
require.Nil(t, err)
require.False(t, actual)
}

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

@@ -543,6 +543,14 @@ func (a *App) joinUserToTeam(team *model.Team, user *model.User) (*model.TeamMem
SchemeUser: !user.IsGuest(),
}
if !user.IsGuest() {
userShouldBeAdmin, err := a.UserIsInAdminRoleGroup(user.Id, team.Id, model.GroupSyncableTypeTeam)
if err != nil {
return nil, false, err
}
tm.SchemeAdmin = userShouldBeAdmin
}
if team.Email == user.Email {
tm.SchemeAdmin = true
}

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

@@ -639,7 +639,8 @@ func TestJoinUserToTeam(t *testing.T) {
ruser, _ := th.App.CreateUser(&user)
defer th.App.PermanentDeleteUser(&user)
_, alreadyAdded, err := th.App.joinUserToTeam(team, ruser)
var alreadyAdded bool
_, alreadyAdded, err = th.App.joinUserToTeam(team, ruser)
require.False(t, alreadyAdded, "Should return already added equal to false")
require.Nil(t, err, "Should return no error")
})
@@ -651,7 +652,8 @@ func TestJoinUserToTeam(t *testing.T) {
th.App.joinUserToTeam(team, ruser)
_, alreadyAdded, err := th.App.joinUserToTeam(team, ruser)
var alreadyAdded bool
_, alreadyAdded, err = th.App.joinUserToTeam(team, ruser)
require.True(t, alreadyAdded, "Should return already added")
require.Nil(t, err, "Should return no error")
})
@@ -664,7 +666,8 @@ func TestJoinUserToTeam(t *testing.T) {
th.App.joinUserToTeam(team, ruser)
th.App.LeaveTeam(team, ruser, ruser.Id)
_, alreadyAdded, err := th.App.joinUserToTeam(team, ruser)
var alreadyAdded bool
_, alreadyAdded, err = th.App.joinUserToTeam(team, ruser)
require.False(t, alreadyAdded, "Should return already added equal to false")
require.Nil(t, err, "Should return no error")
})
@@ -679,7 +682,7 @@ func TestJoinUserToTeam(t *testing.T) {
defer th.App.PermanentDeleteUser(&user2)
th.App.joinUserToTeam(team, ruser1)
_, _, err := th.App.joinUserToTeam(team, ruser2)
_, _, err = th.App.joinUserToTeam(team, ruser2)
require.NotNil(t, err, "Should fail")
})
@@ -697,9 +700,50 @@ func TestJoinUserToTeam(t *testing.T) {
th.App.LeaveTeam(team, ruser1, ruser1.Id)
th.App.joinUserToTeam(team, ruser2)
_, _, err := th.App.joinUserToTeam(team, ruser1)
_, _, err = th.App.joinUserToTeam(team, ruser1)
require.NotNil(t, err, "Should fail")
})
t.Run("new join with correct scheme_admin value from group syncable", 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)
defer th.App.PermanentDeleteUser(&user1)
group := th.CreateGroup()
_, err = th.App.UpsertGroupMember(group.Id, user1.Id)
require.Nil(t, err)
gs, err := th.App.UpsertGroupSyncable(&model.GroupSyncable{
AutoAdd: true,
SyncableId: team.Id,
Type: model.GroupSyncableTypeTeam,
GroupId: group.Id,
SchemeAdmin: false,
})
require.Nil(t, err)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.MaxUsersPerTeam = model.NewInt(999) })
tm1, _, err := th.App.joinUserToTeam(team, ruser1)
require.Nil(t, err)
require.False(t, tm1.SchemeAdmin)
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(&user2)
_, err = th.App.UpsertGroupMember(group.Id, user2.Id)
require.Nil(t, err)
gs.SchemeAdmin = true
_, err = th.App.UpdateGroupSyncable(gs)
require.Nil(t, err)
tm2, _, err := th.App.joinUserToTeam(team, ruser2)
require.Nil(t, err)
require.True(t, tm2.SchemeAdmin)
})
}
func TestAppUpdateTeamScheme(t *testing.T) {