MM-22212 & MM-22208: Read from the higher-scoped scheme if the permission is non-moderated. (#13813)
* MM-22212: Read non-moderated permissions from higher-scoped scheme. * MM-2212: Corrects test count in comment. * MM-22212: Adds godoc comment. * MM-2212: Switches to the channel roles check in a few more places. * MM-22212: Refactors and fixes. * MM-22212: Reverts change, no longer required. * MM-22212: Removes translation. * MM-22212: Un-comments merged new permission. * MM-22212: Un-comments merged new permission. * MM-22212: Performance tweak. * MM-22212: Fixes some fmting. * MM-22212: Add unit test for newly-added store methods. * MM-22212: Renames app method. * MM-22212: Re-uses existing function to find string in slice. * MM-22212: Keeps 'higher-scoped' terminology for consistency. * MM-22212: Refactors based on PR feedback. * MM-22212: Fix for some bad merging. * MM-22212: Renamed some things. * MM-22212: Use an 'else' instead of a 'continue' for readability. * MM-22212: Caches (*SqlRoleStore).ChannelRolesUnderTeamRole. * MM-22212: Adds mock to new cache store. * MM-22212: Adds missing open tracing app layer methods. * MM-22212: Adds migration to add moderated permissions to channel_admin if present on channel_user. * MM-22212: Migrates team schemes. Removes unused AppError. * MM-22212: Fix for for if. * MM-22212: Fixes iterator. * MM-22212: Updates open tracing generated methods. * MM-22212: Fix mocks. * MM-22212: Change migration key name. * MM-22212: Switched to data structure from other branch. * MM-22212: Fixes tests after adding 'use_channel_mentions' to the channel_admin role. * MM-22212: Adds tracking of channel moderation. * Revert "MM-22212: Adds tracking of channel moderation." This reverts commit 23689efa22c112e4ba37f6a212535dd7ebfb63db. * MM-22212: Switch some functions to methods and vice versa. * MM-22212: Fix for refactor bug not notifiying websocket about changed role. * MM-22212: Adds test for public/private 'manage_members' handling. * MM-22122 Fix manage channel members edge case for public and private channels (#14049) * MM-22212: Adds moderated permission to team_admin. * MM-22212: Updates migration. * MM-22212: Revert unnecessary update to default roles. * Add channel scheme updated event when channel scheme is deleted or created (#14057) * MM-22212: Adds newline. * MM-22212: Migration fix. * MM-22212: Fix for migration. * MM-22212: Test fix. Co-authored-by: Farhan Munshi <3207297+fm2munsh@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
ace46443b3
Коммит
4d99aa22ba
@@ -24,6 +24,7 @@ const (
|
||||
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_USER_TEAMS = "inv_user_teams"
|
||||
CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_USER = "clear_session_user"
|
||||
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES = "inv_roles"
|
||||
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLE_PERMISSIONS = "inv_role_permissions"
|
||||
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_BY_IDS = "inv_profile_ids"
|
||||
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_IN_CHANNEL = "inv_profile_in_channel"
|
||||
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_SCHEMES = "inv_schemes"
|
||||
|
||||
@@ -15,5 +15,5 @@ const (
|
||||
MIGRATION_KEY_REMOVE_CHANNEL_MANAGE_DELETE_FROM_TEAM_USER = "remove_channel_manage_delete_from_team_user"
|
||||
MIGRATION_KEY_VIEW_MEMBERS_NEW_PERMISSION = "view_members_new_permission"
|
||||
MIGRATION_KEY_ADD_MANAGE_GUESTS_PERMISSIONS = "add_manage_guests_permissions"
|
||||
MIGRATION_KEY_ADD_USE_CHANNEL_MENTIONS_PERMISSION = "add_use_channel_mentions_permission"
|
||||
MIGRATION_KEY_CHANNEL_MODERATIONS_PERMISSIONS = "channel_moderations_permissions"
|
||||
)
|
||||
|
||||
@@ -9,6 +9,29 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var BuiltInSchemeManagedRoleIDs []string
|
||||
|
||||
func init() {
|
||||
BuiltInSchemeManagedRoleIDs = []string{
|
||||
SYSTEM_GUEST_ROLE_ID,
|
||||
SYSTEM_USER_ROLE_ID,
|
||||
SYSTEM_ADMIN_ROLE_ID,
|
||||
SYSTEM_POST_ALL_ROLE_ID,
|
||||
SYSTEM_POST_ALL_PUBLIC_ROLE_ID,
|
||||
SYSTEM_USER_ACCESS_TOKEN_ROLE_ID,
|
||||
|
||||
TEAM_GUEST_ROLE_ID,
|
||||
TEAM_USER_ROLE_ID,
|
||||
TEAM_ADMIN_ROLE_ID,
|
||||
TEAM_POST_ALL_ROLE_ID,
|
||||
TEAM_POST_ALL_PUBLIC_ROLE_ID,
|
||||
|
||||
CHANNEL_GUEST_ROLE_ID,
|
||||
CHANNEL_USER_ROLE_ID,
|
||||
CHANNEL_ADMIN_ROLE_ID,
|
||||
}
|
||||
}
|
||||
|
||||
type RoleType string
|
||||
type RoleScope string
|
||||
|
||||
@@ -60,6 +83,11 @@ type RolePatch struct {
|
||||
Permissions *[]string `json:"permissions"`
|
||||
}
|
||||
|
||||
type RolePermissions struct {
|
||||
RoleID string
|
||||
Permissions []string
|
||||
}
|
||||
|
||||
func (r *Role) ToJson() string {
|
||||
b, _ := json.Marshal(r)
|
||||
return string(b)
|
||||
@@ -99,6 +127,45 @@ func (r *Role) Patch(patch *RolePatch) {
|
||||
}
|
||||
}
|
||||
|
||||
// MergeChannelHigherScopedPermissions is meant to be invoked on a channel scheme's role and merges the higher-scoped
|
||||
// channel role's permissions.
|
||||
func (r *Role) MergeChannelHigherScopedPermissions(higherScopedPermissions *RolePermissions) {
|
||||
mergedPermissions := []string{}
|
||||
|
||||
higherScopedPermissionsMap := AsStringBoolMap(higherScopedPermissions.Permissions)
|
||||
rolePermissionsMap := AsStringBoolMap(r.Permissions)
|
||||
|
||||
for _, cp := range ALL_PERMISSIONS {
|
||||
if cp.Scope != PERMISSION_SCOPE_CHANNEL {
|
||||
continue
|
||||
}
|
||||
|
||||
_, presentOnHigherScope := higherScopedPermissionsMap[cp.Id]
|
||||
|
||||
// For the channel admin role always look to the higher scope to determine if the role has ther permission.
|
||||
// The channel admin is a special case because they're not part of the UI to be "channel moderated", only
|
||||
// channel members and channel guests are.
|
||||
if higherScopedPermissions.RoleID == CHANNEL_ADMIN_ROLE_ID && presentOnHigherScope {
|
||||
mergedPermissions = append(mergedPermissions, cp.Id)
|
||||
continue
|
||||
}
|
||||
|
||||
_, permissionIsModerated := CHANNEL_MODERATED_PERMISSIONS_MAP[cp.Id]
|
||||
if permissionIsModerated {
|
||||
_, presentOnRole := rolePermissionsMap[cp.Id]
|
||||
if presentOnRole && presentOnHigherScope {
|
||||
mergedPermissions = append(mergedPermissions, cp.Id)
|
||||
}
|
||||
} else {
|
||||
if presentOnHigherScope {
|
||||
mergedPermissions = append(mergedPermissions, cp.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r.Permissions = mergedPermissions
|
||||
}
|
||||
|
||||
// Returns an array of permissions that are in either role.Permissions
|
||||
// or patch.Permissions, but not both.
|
||||
func PermissionsChangedByPatch(role *Role, patch *RolePatch) []string {
|
||||
@@ -172,7 +239,7 @@ func ChannelModeratedPermissionsChangedByPatch(role *Role, patch *RolePatch) []s
|
||||
}
|
||||
|
||||
// GetChannelModeratedPermissions returns a map of channel moderated permissions that the role has access to
|
||||
func (r *Role) GetChannelModeratedPermissions() map[string]bool {
|
||||
func (r *Role) GetChannelModeratedPermissions(channelType string) map[string]bool {
|
||||
moderatedPermissions := make(map[string]bool)
|
||||
for _, permission := range r.Permissions {
|
||||
if _, found := CHANNEL_MODERATED_PERMISSIONS_MAP[permission]; !found {
|
||||
@@ -180,8 +247,20 @@ func (r *Role) GetChannelModeratedPermissions() map[string]bool {
|
||||
}
|
||||
|
||||
for moderated, moderatedPermissionValue := range CHANNEL_MODERATED_PERMISSIONS_MAP {
|
||||
// the moderated permission has already been found to be true so skip this iteration
|
||||
if moderatedPermissions[moderatedPermissionValue] {
|
||||
continue
|
||||
}
|
||||
|
||||
if moderated == permission {
|
||||
moderatedPermissions[moderatedPermissionValue] = true
|
||||
// Special case where the channel moderated permission for `manage_members` is different depending on whether the channel is private or public
|
||||
if moderated == PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id || moderated == PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id {
|
||||
canManagePublic := channelType == CHANNEL_OPEN && moderated == PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id
|
||||
canManagePrivate := channelType == CHANNEL_PRIVATE && moderated == PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id
|
||||
moderatedPermissions[moderatedPermissionValue] = canManagePublic || canManagePrivate
|
||||
} else {
|
||||
moderatedPermissions[moderatedPermissionValue] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,16 +231,19 @@ func TestGetChannelModeratedPermissions(t *testing.T) {
|
||||
tests := []struct {
|
||||
Name string
|
||||
Permissions []string
|
||||
ChannelType string
|
||||
Expected map[string]bool
|
||||
}{
|
||||
{
|
||||
"Filters non moderated permissions",
|
||||
[]string{PERMISSION_CREATE_BOT.Id},
|
||||
CHANNEL_OPEN,
|
||||
map[string]bool{},
|
||||
},
|
||||
{
|
||||
"Returns a map of moderated permissions",
|
||||
[]string{PERMISSION_CREATE_POST.Id, PERMISSION_ADD_REACTION.Id, PERMISSION_REMOVE_REACTION.Id, PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, PERMISSION_USE_CHANNEL_MENTIONS.Id},
|
||||
CHANNEL_OPEN,
|
||||
map[string]bool{
|
||||
CHANNEL_MODERATED_PERMISSIONS[0]: true,
|
||||
CHANNEL_MODERATED_PERMISSIONS[1]: true,
|
||||
@@ -251,6 +254,7 @@ func TestGetChannelModeratedPermissions(t *testing.T) {
|
||||
{
|
||||
"Returns a map of moderated permissions when non moderated present",
|
||||
[]string{PERMISSION_CREATE_POST.Id, PERMISSION_CREATE_DIRECT_CHANNEL.Id},
|
||||
CHANNEL_OPEN,
|
||||
map[string]bool{
|
||||
CHANNEL_MODERATED_PERMISSIONS[0]: true,
|
||||
},
|
||||
@@ -258,13 +262,14 @@ func TestGetChannelModeratedPermissions(t *testing.T) {
|
||||
{
|
||||
"Returns a nothing when no permissions present",
|
||||
[]string{},
|
||||
CHANNEL_OPEN,
|
||||
map[string]bool{},
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
role := &Role{Permissions: tc.Permissions}
|
||||
moderatedPermissions := role.GetChannelModeratedPermissions()
|
||||
moderatedPermissions := role.GetChannelModeratedPermissions(tc.ChannelType)
|
||||
for permission := range moderatedPermissions {
|
||||
assert.Equal(t, moderatedPermissions[permission], tc.Expected[permission])
|
||||
}
|
||||
|
||||
@@ -639,3 +639,11 @@ func GetPreferredTimezone(timezone StringMap) string {
|
||||
func IsSamlFile(saml *SamlSettings, filename string) bool {
|
||||
return filename == *saml.PublicCertificateFile || filename == *saml.PrivateKeyFile || filename == *saml.IdpCertificateFile
|
||||
}
|
||||
|
||||
func AsStringBoolMap(list []string) map[string]bool {
|
||||
listMap := map[string]bool{}
|
||||
for _, p := range list {
|
||||
listMap[p] = true
|
||||
}
|
||||
return listMap
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ const (
|
||||
WEBSOCKET_EVENT_CHANNEL_RESTORED = "channel_restored"
|
||||
WEBSOCKET_EVENT_CHANNEL_UPDATED = "channel_updated"
|
||||
WEBSOCKET_EVENT_CHANNEL_MEMBER_UPDATED = "channel_member_updated"
|
||||
WEBSOCKET_EVENT_CHANNEL_SCHEME_UPDATED = "channel_scheme_updated"
|
||||
WEBSOCKET_EVENT_DIRECT_ADDED = "direct_added"
|
||||
WEBSOCKET_EVENT_GROUP_ADDED = "group_added"
|
||||
WEBSOCKET_EVENT_NEW_USER = "new_user"
|
||||
|
||||
Ссылка в новой задаче
Block a user