diff --git a/lib/types/thread-permission-types.js b/lib/types/thread-permission-types.js --- a/lib/types/thread-permission-types.js +++ b/lib/types/thread-permission-types.js @@ -124,10 +124,7 @@ userSurfacedPermission: userSurfacedPermissions.EDIT_CALENDAR, }; const editEntries = threadPermissions.EDIT_ENTRIES; -const descendantEditEntries = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissions.EDIT_ENTRIES; -const editCalendarPermissions = new Set([editEntries, descendantEditEntries]); +const editCalendarPermissions = new Set([editEntries]); const knowOfSecretChannelsPermission = { title: 'Know of secret channels', @@ -170,42 +167,16 @@ userSurfacedPermission: userSurfacedPermissions.CREATE_AND_EDIT_CHANNELS, }; const editThreadName = threadPermissions.EDIT_THREAD_NAME; -const descendantEditThreadName = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissions.EDIT_THREAD_NAME; const editThreadDescription = threadPermissions.EDIT_THREAD_DESCRIPTION; -const descendantEditThreadDescription = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissions.EDIT_THREAD_DESCRIPTION; const editThreadColor = threadPermissions.EDIT_THREAD_COLOR; -const descendantEditThreadColor = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissions.EDIT_THREAD_COLOR; const createSubchannels = threadPermissions.CREATE_SUBCHANNELS; -const descendantCreateSubchannels = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissionFilterPrefixes.TOP_LEVEL + - threadPermissions.CREATE_SUBCHANNELS; const editThreadAvatar = threadPermissions.EDIT_THREAD_AVATAR; -const descendantEditThreadAvatar = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissions.EDIT_THREAD_AVATAR; -const descendantTopLevelCreateSidebars = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissionFilterPrefixes.TOP_LEVEL + - threadPermissions.CREATE_SIDEBARS; const createAndEditChannelsPermissions = new Set([ editThreadName, - descendantEditThreadName, editThreadDescription, - descendantEditThreadDescription, editThreadColor, - descendantEditThreadColor, createSubchannels, - descendantCreateSubchannels, editThreadAvatar, - descendantEditThreadAvatar, - descendantTopLevelCreateSidebars, ]); const deleteChannelsPermission = { @@ -214,13 +185,7 @@ userSurfacedPermission: userSurfacedPermissions.DELETE_CHANNELS, }; const deleteThread = threadPermissions.DELETE_THREAD; -const descendantDeleteThread = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissions.DELETE_THREAD; -const deleteChannelsPermissions = new Set([ - deleteThread, - descendantDeleteThread, -]); +const deleteChannelsPermissions = new Set([deleteThread]); const addMembersPermission = { title: 'Add members', @@ -228,18 +193,11 @@ userSurfacedPermission: userSurfacedPermissions.ADD_MEMBERS, }; const addMembers = threadPermissions.ADD_MEMBERS; -const descendantAddMembers = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissions.ADD_MEMBERS; const childOpenAddMembers = threadPermissionPropagationPrefixes.CHILD + threadPermissionFilterPrefixes.OPEN + threadPermissions.ADD_MEMBERS; -const addMembersPermissions = new Set([ - addMembers, - descendantAddMembers, - childOpenAddMembers, -]); +const addMembersPermissions = new Set([addMembers, childOpenAddMembers]); const removeMembersPermission = { title: 'Remove members', @@ -247,13 +205,7 @@ userSurfacedPermission: userSurfacedPermissions.REMOVE_MEMBERS, }; const removeMembers = threadPermissions.REMOVE_MEMBERS; -const descendantRemoveMembers = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissions.REMOVE_MEMBERS; -const removeMembersPermissions = new Set([ - removeMembers, - descendantRemoveMembers, -]); +const removeMembersPermissions = new Set([removeMembers]); const changeRolePermission = { title: 'Change roles', @@ -261,10 +213,7 @@ userSurfacedPermission: userSurfacedPermissions.CHANGE_ROLES, }; const changeRole = threadPermissions.CHANGE_ROLE; -const descendantChangeRole = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissions.CHANGE_ROLE; -const changeRolePermissions = new Set([changeRole, descendantChangeRole]); +const changeRolePermissions = new Set([changeRole]); const editVisibilityPermission = { title: 'Edit visibility', @@ -272,13 +221,7 @@ userSurfacedPermission: userSurfacedPermissions.EDIT_VISIBILITY, }; const editPermissions = threadPermissions.EDIT_PERMISSIONS; -const descendantEditPermissions = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissions.EDIT_PERMISSIONS; -const editVisibilityPermissions = new Set([ - editPermissions, - descendantEditPermissions, -]); +const editVisibilityPermissions = new Set([editPermissions]); const managePinsPermission = { title: 'Manage pins', @@ -286,10 +229,7 @@ userSurfacedPermission: userSurfacedPermissions.MANAGE_PINS, }; const managePins = threadPermissions.MANAGE_PINS; -const descendantManagePins = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissions.MANAGE_PINS; -const managePinsPermissions = new Set([managePins, descendantManagePins]); +const managePinsPermissions = new Set([managePins]); const reactToMessagePermission = { title: 'React to messages', @@ -297,13 +237,7 @@ userSurfacedPermission: userSurfacedPermissions.REACT_TO_MESSAGES, }; const reactToMessage = threadPermissions.REACT_TO_MESSAGE; -const descendantReactToMessage = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissions.REACT_TO_MESSAGE; -const reactToMessagePermissions = new Set([ - reactToMessage, - descendantReactToMessage, -]); +const reactToMessagePermissions = new Set([reactToMessage]); const editMessagePermission = { title: 'Edit messages', @@ -311,10 +245,7 @@ userSurfacedPermission: userSurfacedPermissions.EDIT_MESSAGES, }; const editMessage = threadPermissions.EDIT_MESSAGE; -const descendantEditMessage = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissions.EDIT_MESSAGE; -const editMessagePermissions = new Set([editMessage, descendantEditMessage]); +const editMessagePermissions = new Set([editMessage]); const manageInviteLinksPermission = { title: 'Manage invite links', @@ -322,13 +253,7 @@ userSurfacedPermission: userSurfacedPermissions.MANAGE_INVITE_LINKS, }; const manageInviteLinks = threadPermissions.MANAGE_INVITE_LINKS; -const descendantManageInviteLinks = - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissions.MANAGE_INVITE_LINKS; -const manageInviteLinksPermissions = new Set([ - manageInviteLinks, - descendantManageInviteLinks, -]); +const manageInviteLinksPermissions = new Set([manageInviteLinks]); export type UserSurfacedPermissionOption = { +title: string, @@ -388,8 +313,7 @@ threadPermissionFilterPrefixes.OPEN + threadPermissions.VISIBLE, - // join_thread | child_open_join_thread | descendant_opentoplevel_join_thread - threadPermissions.JOIN_THREAD, + // child_open_join_thread | descendant_opentoplevel_join_thread threadPermissionPropagationPrefixes.CHILD + threadPermissionFilterPrefixes.OPEN + threadPermissions.JOIN_THREAD, diff --git a/lib/types/thread-permission-types.test.js b/lib/types/thread-permission-types.test.js --- a/lib/types/thread-permission-types.test.js +++ b/lib/types/thread-permission-types.test.js @@ -1,22 +1,24 @@ // @flow +import _isEqual from 'lodash/fp/isEqual.js'; + import { configurableCommunityPermissions, universalCommunityPermissions, userSurfacedPermissions, - type UserSurfacedPermission, threadPermissions, } from './thread-permission-types.js'; import { getRolePermissionBlobs } from '../permissions/thread-permissions.js'; import { threadTypes } from '../types/thread-types-enum.js'; -import { deepDiff, values } from '../utils/objects.js'; +import { values } from '../utils/objects.js'; +import { toggleUserSurfacedPermission } from '../utils/role-utils.js'; describe('Community Announcement Root', () => { - it('should find Member permissions from getRolePermissionBlobs and user-surfaced permissions to be equal', () => { - const { Members: membersPermissionBlob } = getRolePermissionBlobs( - threadTypes.COMMUNITY_ANNOUNCEMENT_ROOT, - ); + const { Members: membersPermissionBlob } = getRolePermissionBlobs( + threadTypes.COMMUNITY_ANNOUNCEMENT_ROOT, + ); + it('should find Member permissions from getRolePermissionBlobs and user-surfaced permissions to be equal', () => { const membersPermissionsConstructed = [ ...configurableCommunityPermissions[userSurfacedPermissions.ADD_MEMBERS], ...configurableCommunityPermissions[ @@ -32,41 +34,34 @@ ); expect( - deepDiff(membersPermissionBlob, membersPermissionsConstructedBlob), - ).toEqual({}); + _isEqual(membersPermissionBlob, membersPermissionsConstructedBlob), + ).toBe(true); }); - it('should find Admin permissions from getRolePermissionBlobs and user-surfaced permissions to be equal', () => { - const adminsPermissionBlob = - getRolePermissionBlobs(threadTypes.COMMUNITY_ANNOUNCEMENT_ROOT).Admins ?? - {}; - - const adminsPermissionsConstructed = [ - ...values(userSurfacedPermissions) - .map((permission: UserSurfacedPermission) => [ - ...configurableCommunityPermissions[permission], - ]) - .flat(), - ...universalCommunityPermissions, - ]; - - const adminsPermissionsConstructedBlob = Object.fromEntries( - adminsPermissionsConstructed.map(permission => [permission, true]), - ); + it('should find equal permission blobs when toggling user-surfaced permissions', () => { + for (const userSurfacedPermission of values(userSurfacedPermissions)) { + const firstTimeToggledPermissionSet = toggleUserSurfacedPermission( + membersPermissionBlob, + userSurfacedPermission, + ); + const secondTimeToggledPermissionSet = toggleUserSurfacedPermission( + firstTimeToggledPermissionSet, + userSurfacedPermission, + ); - // Context: https://phab.comm.dev/D8478#inline-55680 - expect( - deepDiff(adminsPermissionBlob, adminsPermissionsConstructedBlob), - ).toEqual({ descendant_voiced: true }); + expect( + _isEqual(membersPermissionBlob, secondTimeToggledPermissionSet), + ).toBe(true); + } }); }); describe('Community Root', () => { - it('should find Member permissions from getRolePermissionBlobs and user-surfaced permissions to be equal', () => { - const { Members: membersPermissionBlob } = getRolePermissionBlobs( - threadTypes.COMMUNITY_ROOT, - ); + const { Members: membersPermissionBlob } = getRolePermissionBlobs( + threadTypes.COMMUNITY_ROOT, + ); + it('should find Member permissions from getRolePermissionBlobs and user-surfaced permissions to be equal', () => { const membersPermissionsConstructed = [ ...configurableCommunityPermissions[userSurfacedPermissions.ADD_MEMBERS], ...configurableCommunityPermissions[ @@ -89,7 +84,24 @@ ); expect( - deepDiff(membersPermissionBlob, membersPermissionsConstructedBlob), - ).toEqual({}); + _isEqual(membersPermissionBlob, membersPermissionsConstructedBlob), + ).toBe(true); + }); + + it('should find equal permission blobs when toggling user-surfaced permissions', () => { + for (const userSurfacedPermission of values(userSurfacedPermissions)) { + const firstTimeToggledPermissionSet = toggleUserSurfacedPermission( + membersPermissionBlob, + userSurfacedPermission, + ); + const secondTimeToggledPermissionSet = toggleUserSurfacedPermission( + firstTimeToggledPermissionSet, + userSurfacedPermission, + ); + + expect( + _isEqual(membersPermissionBlob, secondTimeToggledPermissionSet), + ).toBe(true); + } }); }); diff --git a/lib/utils/migration-utils.js b/lib/utils/migration-utils.js --- a/lib/utils/migration-utils.js +++ b/lib/utils/migration-utils.js @@ -130,6 +130,50 @@ threadPermissionPropagationPrefixes.DESCENDANT + threadPermissionFilterPrefixes.OPEN + threadPermissions.VOICED, + + threadPermissions.JOIN_THREAD, + + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.EDIT_ENTRIES, + + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.EDIT_THREAD_NAME, + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.EDIT_THREAD_DESCRIPTION, + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.EDIT_THREAD_COLOR, + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissionFilterPrefixes.TOP_LEVEL + + threadPermissions.CREATE_SUBCHANNELS, + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.EDIT_THREAD_AVATAR, + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissionFilterPrefixes.TOP_LEVEL + + threadPermissions.CREATE_SIDEBARS, + + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.ADD_MEMBERS, + + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.REMOVE_MEMBERS, + + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.CHANGE_ROLE, + + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.EDIT_PERMISSIONS, + + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.MANAGE_PINS, + + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.REACT_TO_MESSAGE, + + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.EDIT_MESSAGE, + + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.MANAGE_INVITE_LINKS, ]; export { diff --git a/lib/utils/role-utils.js b/lib/utils/role-utils.js --- a/lib/utils/role-utils.js +++ b/lib/utils/role-utils.js @@ -13,6 +13,9 @@ type UserSurfacedPermissionOption, userSurfacedPermissions, userSurfacedPermissionOptions, + configurableCommunityPermissions, + type ThreadRolePermissionsBlob, + type UserSurfacedPermission, } from '../types/thread-permission-types.js'; import { type ThreadType, threadTypes } from '../types/thread-types-enum.js'; import type { @@ -125,9 +128,36 @@ return roleMap; } +function toggleUserSurfacedPermission( + rolePermissions: ThreadRolePermissionsBlob, + userSurfacedPermission: UserSurfacedPermission, +): ThreadRolePermissionsBlob { + const userSurfacedPermissionSet = Array.from( + configurableCommunityPermissions[userSurfacedPermission], + ); + const currentRolePermissions = { ...rolePermissions }; + + const roleHasPermission = userSurfacedPermissionSet.every( + permission => currentRolePermissions[permission], + ); + + if (roleHasPermission) { + for (const permission of userSurfacedPermissionSet) { + delete currentRolePermissions[permission]; + } + } else { + for (const permission of userSurfacedPermissionSet) { + currentRolePermissions[permission] = true; + } + } + + return currentRolePermissions; +} + export { useFilterPermissionOptionsByThreadType, constructRoleDeletionMessagePrompt, useRoleDeletableAndEditableStatus, useRolesFromCommunityThreadInfo, + toggleUserSurfacedPermission, };