From 3b1b8d91146cb444595b52574bec37b0f7e6d715 Mon Sep 17 00:00:00 2001 From: Mattermost Build Date: Thu, 22 Jan 2026 07:18:51 +0200 Subject: [PATCH] Automated cherry pick of #34693 (#34972) Automatic Merge --- server/channels/api4/group_test.go | 16 +++ server/channels/api4/team.go | 6 + server/channels/api4/team_test.go | 23 +++ server/channels/app/channel.go | 30 +--- server/channels/app/channel_test.go | 76 ---------- server/channels/app/import_functions.go | 6 +- server/channels/app/team.go | 29 +--- server/channels/app/team_test.go | 178 ------------------------ 8 files changed, 55 insertions(+), 309 deletions(-) diff --git a/server/channels/api4/group_test.go b/server/channels/api4/group_test.go index 33a2c252d4..8ce584d3ee 100644 --- a/server/channels/api4/group_test.go +++ b/server/channels/api4/group_test.go @@ -2071,8 +2071,16 @@ func TestGetGroups(t *testing.T) { t.Run("not associated to channel", func(t *testing.T) { opts := baseOpts + resp, err := th.SystemAdminClient.UpdateChannelRoles(context.Background(), th.BasicChannel.Id, th.BasicUser.Id, "") + require.NoError(t, err) + CheckOKStatus(t, resp) + opts.NotAssociatedToChannel = th.BasicChannel.Id + resp, err = th.SystemAdminClient.UpdateChannelRoles(context.Background(), th.BasicChannel.Id, th.BasicUser.Id, "channel_user channel_admin") + require.NoError(t, err) + CheckOKStatus(t, resp) + groups, resp, err := th.SystemAdminClient.GetGroups(context.Background(), opts) require.NoError(t, err) CheckOKStatus(t, resp) @@ -2081,8 +2089,16 @@ func TestGetGroups(t *testing.T) { t.Run("not associated to team", func(t *testing.T) { opts := baseOpts + resp, err := th.SystemAdminClient.UpdateTeamMemberRoles(context.Background(), th.BasicTeam.Id, th.BasicUser.Id, "") + require.NoError(t, err) + CheckOKStatus(t, resp) + opts.NotAssociatedToTeam = th.BasicTeam.Id + resp, err = th.SystemAdminClient.UpdateTeamMemberRoles(context.Background(), th.BasicTeam.Id, th.BasicUser.Id, "team_user team_admin") + require.NoError(t, err) + CheckOKStatus(t, resp) + groups, resp, err := th.SystemAdminClient.GetGroups(context.Background(), opts) require.NoError(t, err) CheckOKStatus(t, resp) diff --git a/server/channels/api4/team.go b/server/channels/api4/team.go index ce7580b2bc..bbd5faebd4 100644 --- a/server/channels/api4/team.go +++ b/server/channels/api4/team.go @@ -127,6 +127,12 @@ func createTeam(c *Context, w http.ResponseWriter, r *http.Request) { } // Don't sanitize the team here since the user will be a team admin and their session won't reflect that yet + // instead check the scheme roles for the team and if the user has the permission to invite users + _, schemeUserRole, schemeAdminRole, schemeErr := c.App.GetSchemeRolesForTeam(rteam.Id) + if schemeErr != nil || !c.App.RolesGrantPermission([]string{schemeUserRole, schemeAdminRole}, model.PermissionInviteUser.Id) { + // If we can't check permissions, fail secure by hiding the invite_id because the team is already created above + rteam.InviteId = "" + } auditRec.Success() auditRec.AddEventResultState(&team) diff --git a/server/channels/api4/team_test.go b/server/channels/api4/team_test.go index d8b34049dc..35a30e5f5f 100644 --- a/server/channels/api4/team_test.go +++ b/server/channels/api4/team_test.go @@ -236,6 +236,29 @@ func TestCreateTeamSanitization(t *testing.T) { }, "system admin") } +func TestCreateTeamInviteIdHiddenWithoutInvitePermission(t *testing.T) { + th := Setup(t) + + defaultRolePermissions := th.SaveDefaultRolePermissions() + defer th.RestoreDefaultRolePermissions(defaultRolePermissions) + + // Remove PermissionInviteUser from the default team user role + th.RemovePermissionFromRole(model.PermissionInviteUser.Id, model.TeamUserRoleId) + + // Regular user creates a team - InviteId should be hidden + // since the team user role lacks invite permission + rteam, _, err := th.Client.CreateTeam(context.Background(), &model.Team{ + DisplayName: "Team Without Invite Permission", + Name: GenerateTestTeamName(), + Email: th.GenerateTestEmail(), + Type: model.TeamOpen, + AllowedDomains: "simulator.amazonses.com,localhost", + }) + require.NoError(t, err) + require.NotEmpty(t, rteam.Email, "should not have sanitized email") + require.Empty(t, rteam.InviteId, "should have hidden invite_id when user lacks invite permission") +} + func TestGetTeam(t *testing.T) { mainHelper.Parallel(t) th := Setup(t).InitBasic() diff --git a/server/channels/app/channel.go b/server/channels/app/channel.go index d93f0aacb6..c1a555f2bc 100644 --- a/server/channels/app/channel.go +++ b/server/channels/app/channel.go @@ -1251,29 +1251,14 @@ func buildChannelModerations(c request.CTX, channelType model.ChannelType, membe return channelModerations } -// UpdateChannelMemberRoles updates the roles for a channel member. -// This is the public API used by REST endpoints and plugins. -// It enforces strict validation requiring either SchemeUser or SchemeGuest to be true. -func (a *App) UpdateChannelMemberRoles(rctx request.CTX, channelID string, userID string, newRoles string) (*model.ChannelMember, *model.AppError) { - return a.updateChannelMemberRolesInternal(rctx, channelID, userID, newRoles, false) -} - -// updateChannelMemberRolesInternal is the internal implementation of UpdateChannelMemberRoles. -// The allowSchemeUserUnset parameter controls whether to enforce the requirement that members -// must have either SchemeUser or SchemeGuest set to true. -// -// When allowSchemeUserUnset is false (default for API/plugin calls), the function enforces -// that members must have a base scheme role. When true (bulk import only), this validation -// is skipped to support the two-phase import pattern where explicit roles are set first, -// then scheme roles are set via UpdateChannelMemberSchemeRoles immediately after. -func (a *App) updateChannelMemberRolesInternal(rctx request.CTX, channelID string, userID string, newRoles string, allowSchemeUserUnset bool) (*model.ChannelMember, *model.AppError) { +func (a *App) UpdateChannelMemberRoles(c request.CTX, channelID string, userID string, newRoles string) (*model.ChannelMember, *model.AppError) { var member *model.ChannelMember var err *model.AppError - if member, err = a.GetChannelMember(rctx, channelID, userID); err != nil { + if member, err = a.GetChannelMember(c, channelID, userID); err != nil { return nil, err } - schemeGuestRole, schemeUserRole, schemeAdminRole, err := a.GetSchemeRolesForChannel(rctx, channelID) + schemeGuestRole, schemeUserRole, schemeAdminRole, err := a.GetSchemeRolesForChannel(c, channelID) if err != nil { return nil, err } @@ -1320,16 +1305,9 @@ func (a *App) updateChannelMemberRolesInternal(rctx request.CTX, channelID strin return nil, model.NewAppError("UpdateChannelMemberRoles", "api.channel.update_channel_member_roles.changing_guest_role.app_error", nil, "", http.StatusBadRequest) } - // Validate that the member has a base scheme role (SchemeUser or SchemeGuest). - // This ensures members always have the minimum required permissions. - // Bulk import operations may skip this validation temporarily. - if !allowSchemeUserUnset && !member.SchemeGuest && !member.SchemeUser { - return nil, model.NewAppError("UpdateChannelMemberRoles", "api.channel.update_channel_member_roles.unset_user_scheme.app_error", nil, "", http.StatusBadRequest) - } - member.ExplicitRoles = strings.Join(newExplicitRoles, " ") - return a.updateChannelMember(rctx, member) + return a.updateChannelMember(c, member) } func (a *App) UpdateChannelMemberSchemeRoles(c request.CTX, channelID string, userID string, isSchemeGuest bool, isSchemeUser bool, isSchemeAdmin bool) (*model.ChannelMember, *model.AppError) { diff --git a/server/channels/app/channel_test.go b/server/channels/app/channel_test.go index 51da3bda3d..e3488c9760 100644 --- a/server/channels/app/channel_test.go +++ b/server/channels/app/channel_test.go @@ -1631,82 +1631,6 @@ func TestUpdateChannelMemberRolesChangingGuest(t *testing.T) { }) } -func TestUpdateChannelMemberRolesRequireUser(t *testing.T) { - mainHelper.Parallel(t) - th := Setup(t).InitBasic() - - t.Run("empty roles string requires user or guest scheme role", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, appErr := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, appErr) - - _, appErr = th.App.AddUserToChannel(th.Context, ruser, th.BasicChannel, false) - require.Nil(t, appErr) - - member, appErr := th.App.GetChannelMember(th.Context, th.BasicChannel.Id, ruser.Id) - require.Nil(t, appErr) - require.True(t, member.SchemeUser) - require.False(t, member.SchemeGuest) - - _, appErr = th.App.UpdateChannelMemberRoles(th.Context, th.BasicChannel.Id, ruser.Id, "") - require.NotNil(t, appErr) - require.Equal(t, "api.channel.update_channel_member_roles.unset_user_scheme.app_error", appErr.Id) - }) - - t.Run("admin role requires user or guest scheme role", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, appErr := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, appErr) - - _, appErr = th.App.AddUserToChannel(th.Context, ruser, th.BasicChannel, false) - require.Nil(t, appErr) - - _, appErr = th.App.UpdateChannelMemberRoles(th.Context, th.BasicChannel.Id, ruser.Id, "channel_admin") - require.NotNil(t, appErr) - require.Equal(t, "api.channel.update_channel_member_roles.unset_user_scheme.app_error", appErr.Id) - }) - - t.Run("valid user and admin roles update succeeds", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, appErr := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, appErr) - - _, appErr = th.App.AddUserToChannel(th.Context, ruser, th.BasicChannel, false) - require.Nil(t, appErr) - - updatedMember, appErr := th.App.UpdateChannelMemberRoles(th.Context, th.BasicChannel.Id, ruser.Id, "channel_user channel_admin") - require.Nil(t, appErr) - require.True(t, updatedMember.SchemeUser) - require.True(t, updatedMember.SchemeAdmin) - require.False(t, updatedMember.SchemeGuest) - }) - - t.Run("removing admin role while keeping user role succeeds", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, appErr := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, appErr) - - _, appErr = th.App.AddUserToChannel(th.Context, ruser, th.BasicChannel, false) - require.Nil(t, appErr) - - _, appErr = th.App.UpdateChannelMemberRoles(th.Context, th.BasicChannel.Id, ruser.Id, "channel_user channel_admin") - require.Nil(t, appErr) - - updatedMember, appErr := th.App.UpdateChannelMemberRoles(th.Context, th.BasicChannel.Id, ruser.Id, "channel_user") - require.Nil(t, appErr) - require.True(t, updatedMember.SchemeUser) - require.False(t, updatedMember.SchemeAdmin) - }) -} - func TestDefaultChannelNames(t *testing.T) { mainHelper.Parallel(t) th := Setup(t) diff --git a/server/channels/app/import_functions.go b/server/channels/app/import_functions.go index 7486c32fdf..19fad5e847 100644 --- a/server/channels/app/import_functions.go +++ b/server/channels/app/import_functions.go @@ -1117,8 +1117,7 @@ func (a *App) importUserTeams(rctx request.CTX, user *model.User, data *[]import for _, member := range append(newMembers, oldMembers...) { if member.ExplicitRoles != rolesByTeamID[member.TeamId] { - // Bulk import uses internal function to support two-phase role updates. - if _, appErr = a.updateTeamMemberRolesInternal(rctx, member.TeamId, user.Id, rolesByTeamID[member.TeamId], true); appErr != nil { + if _, appErr = a.UpdateTeamMemberRoles(rctx, member.TeamId, user.Id, rolesByTeamID[member.TeamId]); appErr != nil { return appErr } } @@ -1310,8 +1309,7 @@ func (a *App) importUserChannels(rctx request.CTX, user *model.User, team *model for _, member := range append(newMembers, oldMembers...) { if member.ExplicitRoles != rolesByChannelId[member.ChannelId] { - // Bulk import uses internal function to support two-phase role updates. - if _, err = a.updateChannelMemberRolesInternal(rctx, member.ChannelId, user.Id, rolesByChannelId[member.ChannelId], true); err != nil { + if _, err = a.UpdateChannelMemberRoles(rctx, member.ChannelId, user.Id, rolesByChannelId[member.ChannelId]); err != nil { return err } } diff --git a/server/channels/app/team.go b/server/channels/app/team.go index f8a5d9dad7..6f41019a63 100644 --- a/server/channels/app/team.go +++ b/server/channels/app/team.go @@ -375,6 +375,7 @@ func (a *App) sendTeamEvent(team *model.Team, event model.WebsocketEventType) *m return nil } +// GetSchemeRolesForTeam Gets the scheme roles for a team, they may be empty, default or custom permissions based on the scheme. func (a *App) GetSchemeRolesForTeam(teamID string) (string, string, string, *model.AppError) { team, err := a.GetTeam(teamID) if err != nil { @@ -392,23 +393,8 @@ func (a *App) GetSchemeRolesForTeam(teamID string) (string, string, string, *mod return model.TeamGuestRoleId, model.TeamUserRoleId, model.TeamAdminRoleId, nil } -// UpdateTeamMemberRoles updates the roles for a team member. -// This is the public API used by REST endpoints and plugins. -// It enforces strict validation requiring either SchemeUser or SchemeGuest to be true. -func (a *App) UpdateTeamMemberRoles(rctx request.CTX, teamID string, userID string, newRoles string) (*model.TeamMember, *model.AppError) { - return a.updateTeamMemberRolesInternal(rctx, teamID, userID, newRoles, false) -} - -// updateTeamMemberRolesInternal is the internal implementation of UpdateTeamMemberRoles. -// The allowSchemeUserUnset parameter controls whether to enforce the requirement that members -// must have either SchemeUser or SchemeGuest set to true. -// -// When allowSchemeUserUnset is false (default for API/plugin calls), the function enforces -// that members must have a base scheme role. When true (bulk import only), this validation -// is skipped to support the two-phase import pattern where explicit roles are set first, -// then scheme roles are set via UpdateTeamMemberSchemeRoles immediately after. -func (a *App) updateTeamMemberRolesInternal(rctx request.CTX, teamID string, userID string, newRoles string, allowSchemeUserUnset bool) (*model.TeamMember, *model.AppError) { - member, nErr := a.Srv().Store().Team().GetMember(rctx, teamID, userID) +func (a *App) UpdateTeamMemberRoles(c request.CTX, teamID string, userID string, newRoles string) (*model.TeamMember, *model.AppError) { + member, nErr := a.Srv().Store().Team().GetMember(c, teamID, userID) if nErr != nil { var nfErr *store.ErrNotFound switch { @@ -469,16 +455,9 @@ func (a *App) updateTeamMemberRolesInternal(rctx request.CTX, teamID string, use return nil, model.NewAppError("UpdateTeamMemberRoles", "api.channel.update_team_member_roles.changing_guest_role.app_error", nil, "", http.StatusBadRequest) } - // Validate that the member has a base scheme role (SchemeUser or SchemeGuest). - // This ensures members always have the minimum required permissions. - // Bulk import operations may skip this validation temporarily. - if !allowSchemeUserUnset && !member.SchemeGuest && !member.SchemeUser { - return nil, model.NewAppError("UpdateTeamMemberRoles", "api.team.update_team_member_roles.unset_user_scheme.app_error", nil, "", http.StatusBadRequest) - } - member.ExplicitRoles = strings.Join(newExplicitRoles, " ") - member, nErr = a.Srv().Store().Team().UpdateMember(rctx, member) + member, nErr = a.Srv().Store().Team().UpdateMember(c, member) if nErr != nil { var appErr *model.AppError switch { diff --git a/server/channels/app/team_test.go b/server/channels/app/team_test.go index d6af365113..47f8ee5594 100644 --- a/server/channels/app/team_test.go +++ b/server/channels/app/team_test.go @@ -1436,184 +1436,6 @@ func TestUpdateTeamMemberRolesChangingGuest(t *testing.T) { }) } -func TestUpdateTeamMemberRolesRequireUser(t *testing.T) { - mainHelper.Parallel(t) - th := Setup(t).InitBasic() - - t.Run("empty roles string requires user or guest scheme role", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, err) - - member, err := th.App.GetTeamMember(th.Context, th.BasicTeam.Id, ruser.Id) - require.Nil(t, err) - require.True(t, member.SchemeUser) - require.False(t, member.SchemeGuest) - - _, err = th.App.UpdateTeamMemberRoles(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.NotNil(t, err) - require.Equal(t, "api.team.update_team_member_roles.unset_user_scheme.app_error", err.Id) - }) - - t.Run("admin role requires user or guest scheme role", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, err) - - _, err = th.App.UpdateTeamMemberRoles(th.Context, th.BasicTeam.Id, ruser.Id, "team_admin") - require.NotNil(t, err) - require.Equal(t, "api.team.update_team_member_roles.unset_user_scheme.app_error", err.Id) - }) - - t.Run("valid user and admin roles update succeeds", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, err) - - updatedMember, err := th.App.UpdateTeamMemberRoles(th.Context, th.BasicTeam.Id, ruser.Id, "team_user team_admin") - require.Nil(t, err) - require.True(t, updatedMember.SchemeUser) - require.True(t, updatedMember.SchemeAdmin) - require.False(t, updatedMember.SchemeGuest) - }) - - t.Run("removing admin role while keeping user role succeeds", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, err) - - _, err = th.App.UpdateTeamMemberRoles(th.Context, th.BasicTeam.Id, ruser.Id, "team_user team_admin") - require.Nil(t, err) - - updatedMember, err := th.App.UpdateTeamMemberRoles(th.Context, th.BasicTeam.Id, ruser.Id, "team_user") - require.Nil(t, err) - require.True(t, updatedMember.SchemeUser) - require.False(t, updatedMember.SchemeAdmin) - }) - - t.Run("team_post_all alone should fail", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, err) - - _, err = th.App.UpdateTeamMemberRoles(th.Context, th.BasicTeam.Id, ruser.Id, "team_post_all") - require.NotNil(t, err) - require.Equal(t, "api.team.update_team_member_roles.unset_user_scheme.app_error", err.Id) - }) - - t.Run("team_post_all_public alone should fail", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, err) - - _, err = th.App.UpdateTeamMemberRoles(th.Context, th.BasicTeam.Id, ruser.Id, "team_post_all_public") - require.NotNil(t, err) - require.Equal(t, "api.team.update_team_member_roles.unset_user_scheme.app_error", err.Id) - }) - - t.Run("system_post_all alone should fail", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, err) - - _, err = th.App.UpdateTeamMemberRoles(th.Context, th.BasicTeam.Id, ruser.Id, "system_post_all") - require.NotNil(t, err) - require.Equal(t, "api.team.update_team_member_roles.unset_user_scheme.app_error", err.Id) - }) - - t.Run("system_user_manager alone should fail", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, err) - - _, err = th.App.UpdateTeamMemberRoles(th.Context, th.BasicTeam.Id, ruser.Id, "system_user_manager") - require.NotNil(t, err) - require.Equal(t, "api.team.update_team_member_roles.unset_user_scheme.app_error", err.Id) - }) - - t.Run("multiple non-scheme-managed roles without user scheme should fail", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, err) - - _, err = th.App.UpdateTeamMemberRoles(th.Context, th.BasicTeam.Id, ruser.Id, "team_post_all team_post_all_public system_post_all") - require.NotNil(t, err) - require.Equal(t, "api.team.update_team_member_roles.unset_user_scheme.app_error", err.Id) - }) - - t.Run("team_post_all with team_user should succeed", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, err) - - updatedMember, err := th.App.UpdateTeamMemberRoles(th.Context, th.BasicTeam.Id, ruser.Id, "team_user team_post_all") - require.Nil(t, err) - require.True(t, updatedMember.SchemeUser) - require.Contains(t, updatedMember.ExplicitRoles, "team_post_all") - }) - - t.Run("team_post_all_public with team_user should succeed", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, err) - - updatedMember, err := th.App.UpdateTeamMemberRoles(th.Context, th.BasicTeam.Id, ruser.Id, "team_user team_post_all_public") - require.Nil(t, err) - require.True(t, updatedMember.SchemeUser) - require.Contains(t, updatedMember.ExplicitRoles, "team_post_all_public") - }) - - t.Run("multiple explicit roles with team_user should succeed", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, err) - - updatedMember, err := th.App.UpdateTeamMemberRoles(th.Context, th.BasicTeam.Id, ruser.Id, "team_user team_post_all team_post_all_public") - require.Nil(t, err) - require.True(t, updatedMember.SchemeUser) - require.Contains(t, updatedMember.ExplicitRoles, "team_post_all") - require.Contains(t, updatedMember.ExplicitRoles, "team_post_all_public") - }) - - t.Run("explicit role with admin should succeed", func(t *testing.T) { - user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Tester", Username: "tester" + model.NewId(), Password: "passwd1", AuthService: ""} - ruser, _ := th.App.CreateUser(th.Context, &user) - - _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") - require.Nil(t, err) - - updatedMember, err := th.App.UpdateTeamMemberRoles(th.Context, th.BasicTeam.Id, ruser.Id, "team_user team_admin team_post_all") - require.Nil(t, err) - require.True(t, updatedMember.SchemeUser) - require.True(t, updatedMember.SchemeAdmin) - require.Contains(t, updatedMember.ExplicitRoles, "team_post_all") - }) -} - func TestInvalidateAllResendInviteEmailJobs(t *testing.T) { mainHelper.Parallel(t) th := Setup(t)