diff --git a/app/team.go b/app/team.go index 1de3c92350..9c1d99ee6b 100644 --- a/app/team.go +++ b/app/team.go @@ -308,6 +308,8 @@ func (a *App) UpdateTeamScheme(team *model.Team) (*model.Team, *model.AppError) return nil, model.NewAppError("UpdateTeamScheme", "app.team.clear_cache.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr) } + a.Srv().Store().Channel().ClearMembersForUserCache() + if appErr := a.sendTeamEvent(oldTeam, model.WebsocketEventUpdateTeamScheme); appErr != nil { return nil, appErr } diff --git a/app/team_test.go b/app/team_test.go index 604cef33d6..23fd15117b 100644 --- a/app/team_test.go +++ b/app/team_test.go @@ -1109,6 +1109,45 @@ func TestAppUpdateTeamScheme(t *testing.T) { updatedTeam, err := th.App.UpdateTeamScheme(th.BasicTeam) require.Nil(t, err) require.Equal(t, mockID, updatedTeam.SchemeId, "Wrong Team SchemeId") + + // Test that a newly applied team scheme applies the new permissions to a team member + th.App.SetPhase2PermissionsMigrationStatus(true) + + team2Scheme := th.SetupTeamScheme() + channelUser, err := th.App.GetRoleByName(context.Background(), team2Scheme.DefaultChannelUserRole) + require.Nil(t, err) + channelUser.Permissions = []string{} + _, err = th.App.UpdateRole(channelUser) // Remove all permissions from the team user role of the scheme + require.Nil(t, err) + + channelAdmin, err := th.App.GetRoleByName(context.Background(), team2Scheme.DefaultChannelAdminRole) + require.Nil(t, err) + channelAdmin.Permissions = []string{} + _, err = th.App.UpdateRole(channelAdmin) // Remove all permissions from the team admin role of the scheme + require.Nil(t, err) + + team2 := th.CreateTeam() + th.App.AddUserToTeam(th.Context, team2.Id, th.BasicUser.Id, "") + channel := th.CreateChannel(th.Context, team2) + th.App.AddUserToChannel(th.Context, th.BasicUser, channel, true) + session := model.Session{ + Roles: model.SystemUserRoleId, + UserId: th.BasicUser.Id, + TeamMembers: []*model.TeamMember{ + { + UserId: th.BasicUser.Id, + TeamId: team2.Id, + SchemeUser: true, + }, + }, + } + // ensure user can update channel properties before applying the scheme + require.True(t, th.App.SessionHasPermissionToChannel(th.Context, session, channel.Id, model.PermissionManagePublicChannelProperties)) + // apply the team scheme + team2.SchemeId = &team2Scheme.Id + _, err = th.App.UpdateTeamScheme(team2) + require.Nil(t, err) + require.False(t, th.App.SessionHasPermissionToChannel(th.Context, session, channel.Id, model.PermissionManagePublicChannelProperties)) } func TestGetTeamMembers(t *testing.T) { diff --git a/store/opentracinglayer/opentracinglayer.go b/store/opentracinglayer/opentracinglayer.go index 61d30cf909..0ce432c3d0 100644 --- a/store/opentracinglayer/opentracinglayer.go +++ b/store/opentracinglayer/opentracinglayer.go @@ -696,6 +696,19 @@ func (s *OpenTracingLayerChannelStore) ClearCaches() { } +func (s *OpenTracingLayerChannelStore) ClearMembersForUserCache() { + origCtx := s.Root.Store.Context() + span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.ClearMembersForUserCache") + s.Root.Store.SetContext(newCtx) + defer func() { + s.Root.Store.SetContext(origCtx) + }() + + defer span.Finish() + s.ChannelStore.ClearMembersForUserCache() + +} + func (s *OpenTracingLayerChannelStore) ClearSidebarOnTeamLeave(userID string, teamID string) error { origCtx := s.Root.Store.Context() span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.ClearSidebarOnTeamLeave") diff --git a/store/retrylayer/retrylayer.go b/store/retrylayer/retrylayer.go index e2e17d5e61..b05b3dfc21 100644 --- a/store/retrylayer/retrylayer.go +++ b/store/retrylayer/retrylayer.go @@ -750,6 +750,12 @@ func (s *RetryLayerChannelStore) ClearCaches() { } +func (s *RetryLayerChannelStore) ClearMembersForUserCache() { + + s.ChannelStore.ClearMembersForUserCache() + +} + func (s *RetryLayerChannelStore) ClearSidebarOnTeamLeave(userID string, teamID string) error { tries := 0 diff --git a/store/sqlstore/channel_store.go b/store/sqlstore/channel_store.go index ab1d6c0ebb..85864f3784 100644 --- a/store/sqlstore/channel_store.go +++ b/store/sqlstore/channel_store.go @@ -451,6 +451,10 @@ var channelByNameCache = cache.NewLRU(cache.LRUOptions{ Size: model.ChannelCacheSize, }) +func (s SqlChannelStore) ClearMembersForUserCache() { + allChannelMembersForUserCache.Purge() +} + func (s SqlChannelStore) ClearCaches() { allChannelMembersForUserCache.Purge() allChannelMembersNotifyPropsForChannelCache.Purge() diff --git a/store/store.go b/store/store.go index deebac76f6..7cbf0d3e1b 100644 --- a/store/store.go +++ b/store/store.go @@ -267,6 +267,7 @@ type ChannelStore interface { AnalyticsDeletedTypeCount(teamID string, channelType model.ChannelType) (int64, error) GetChannelUnread(channelID, userID string) (*model.ChannelUnread, error) ClearCaches() + ClearMembersForUserCache() GetChannelsByScheme(schemeID string, offset int, limit int) (model.ChannelList, error) MigrateChannelMembers(fromChannelID string, fromUserID string) (map[string]string, error) ResetAllChannelSchemes() error diff --git a/store/storetest/mocks/ChannelStore.go b/store/storetest/mocks/ChannelStore.go index 5cfe28d6a0..f54a4266d8 100644 --- a/store/storetest/mocks/ChannelStore.go +++ b/store/storetest/mocks/ChannelStore.go @@ -150,6 +150,11 @@ func (_m *ChannelStore) ClearCaches() { _m.Called() } +// ClearMembersForUserCache provides a mock function with given fields: +func (_m *ChannelStore) ClearMembersForUserCache() { + _m.Called() +} + // ClearSidebarOnTeamLeave provides a mock function with given fields: userID, teamID func (_m *ChannelStore) ClearSidebarOnTeamLeave(userID string, teamID string) error { ret := _m.Called(userID, teamID) diff --git a/store/timerlayer/timerlayer.go b/store/timerlayer/timerlayer.go index 86a925e4e4..da4503ae92 100644 --- a/store/timerlayer/timerlayer.go +++ b/store/timerlayer/timerlayer.go @@ -669,6 +669,21 @@ func (s *TimerLayerChannelStore) ClearCaches() { } } +func (s *TimerLayerChannelStore) ClearMembersForUserCache() { + start := time.Now() + + s.ChannelStore.ClearMembersForUserCache() + + elapsed := float64(time.Since(start)) / float64(time.Second) + if s.Root.Metrics != nil { + success := "false" + if true { + success = "true" + } + s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.ClearMembersForUserCache", success, elapsed) + } +} + func (s *TimerLayerChannelStore) ClearSidebarOnTeamLeave(userID string, teamID string) error { start := time.Now()