diff --git a/keyserver/src/fetchers/thread-fetchers.js b/keyserver/src/fetchers/thread-fetchers.js --- a/keyserver/src/fetchers/thread-fetchers.js +++ b/keyserver/src/fetchers/thread-fetchers.js @@ -9,7 +9,10 @@ getContainingThreadID, getCommunity, } from 'lib/shared/thread-utils.js'; -import { hasMinCodeVersion } from 'lib/shared/version-utils.js'; +import { + hasMinCodeVersion, + FUTURE_CODE_VERSION, +} from 'lib/shared/version-utils.js'; import type { AvatarDBContent, ClientAvatar } from 'lib/types/avatar-types.js'; import type { RawMessageInfo, MessageInfo } from 'lib/types/message-types.js'; import type { RawThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; @@ -289,6 +292,13 @@ native: 336, web: 79, }); + const addingUsersToCommunityRootSupported = !hasMinCodeVersion( + viewer.platformDetails, + { + native: FUTURE_CODE_VERSION, + web: FUTURE_CODE_VERSION, + }, + ); const threadInfos: { [string]: LegacyRawThreadInfo | RawThreadInfo, @@ -305,6 +315,7 @@ filterVoicedInAnnouncementChannelsPermission: codeVersionBelow283, minimallyEncodePermissions: minimallyEncodedPermissionsSupported, includeSpecialRoleFieldInRoles: specialRoleFieldSupported, + allowAddingUsersToCommunityRoot: addingUsersToCommunityRootSupported, }, ); if (threadInfo) { diff --git a/lib/permissions/thread-permissions.js b/lib/permissions/thread-permissions.js --- a/lib/permissions/thread-permissions.js +++ b/lib/permissions/thread-permissions.js @@ -291,7 +291,6 @@ [threadPermissions.EDIT_THREAD_AVATAR]: true, [threadPermissions.CREATE_SUBCHANNELS]: true, [threadPermissions.CREATE_SIDEBARS]: true, - [threadPermissions.ADD_MEMBERS]: true, [threadPermissions.DELETE_THREAD]: true, [threadPermissions.REMOVE_MEMBERS]: true, [threadPermissions.CHANGE_ROLE]: true, @@ -321,7 +320,10 @@ let adminPermissions; if (threadType === threadTypes.GENESIS) { - adminPermissions = baseAdminPermissions; + adminPermissions = { + ...baseAdminPermissions, + [threadPermissions.ADD_MEMBERS]: true, + }; } else { adminPermissions = { ...baseAdminPermissions, diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js --- a/lib/shared/thread-utils.js +++ b/lib/shared/thread-utils.js @@ -621,6 +621,7 @@ +filterVoicedInAnnouncementChannelsPermission?: boolean, +minimallyEncodePermissions?: boolean, +includeSpecialRoleFieldInRoles?: boolean, + +allowAddingUsersToCommunityRoot?: boolean, }; function rawThreadInfoFromServerThreadInfo( @@ -638,31 +639,50 @@ const shouldMinimallyEncodePermissions = options?.minimallyEncodePermissions; const shouldIncludeSpecialRoleFieldInRoles = options?.includeSpecialRoleFieldInRoles; + const allowAddingUsersToCommunityRoot = + options?.allowAddingUsersToCommunityRoot; - const filterThreadPermissions = _omitBy( - (v, k) => - (filterThreadEditAvatarPermission && - [ - threadPermissions.EDIT_THREAD_AVATAR, - threadPermissionPropagationPrefixes.DESCENDANT + + const filterThreadPermissions = ( + innerThreadPermissions: ThreadPermissionsInfo, + ) => { + if ( + allowAddingUsersToCommunityRoot && + (serverThreadInfo.type === threadTypes.COMMUNITY_ANNOUNCEMENT_ROOT || + serverThreadInfo.type === threadTypes.COMMUNITY_ROOT) + ) { + innerThreadPermissions = { + ...innerThreadPermissions, + [threadPermissions.ADD_MEMBERS]: { + value: true, + source: serverThreadInfo.id, + }, + }; + } + return _omitBy( + (v, k) => + (filterThreadEditAvatarPermission && + [ threadPermissions.EDIT_THREAD_AVATAR, - ].includes(k)) || - (excludePinInfo && - [ - threadPermissions.MANAGE_PINS, - threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.EDIT_THREAD_AVATAR, + ].includes(k)) || + (excludePinInfo && + [ threadPermissions.MANAGE_PINS, - ].includes(k)) || - (filterManageInviteLinksPermission && - [threadPermissions.MANAGE_INVITE_LINKS].includes(k)) || - (filterVoicedInAnnouncementChannelsPermission && - [ - threadPermissions.VOICED_IN_ANNOUNCEMENT_CHANNELS, - threadPermissionPropagationPrefixes.DESCENDANT + - threadPermissionFilterPrefixes.TOP_LEVEL + + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissions.MANAGE_PINS, + ].includes(k)) || + (filterManageInviteLinksPermission && + [threadPermissions.MANAGE_INVITE_LINKS].includes(k)) || + (filterVoicedInAnnouncementChannelsPermission && + [ threadPermissions.VOICED_IN_ANNOUNCEMENT_CHANNELS, - ].includes(k)), - ); + threadPermissionPropagationPrefixes.DESCENDANT + + threadPermissionFilterPrefixes.TOP_LEVEL + + threadPermissions.VOICED_IN_ANNOUNCEMENT_CHANNELS, + ].includes(k)), + )(innerThreadPermissions); + }; const members = []; let currentUser; 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 @@ -214,12 +214,11 @@ description: 'Allows members to add other members to channels', userSurfacedPermission: userSurfacedPermissions.ADD_MEMBERS, }; -const addMembers = threadPermissions.ADD_MEMBERS; const childOpenAddMembers = threadPermissionPropagationPrefixes.CHILD + threadPermissionFilterPrefixes.OPEN + threadPermissions.ADD_MEMBERS; -const addMembersPermissions = new Set([addMembers, childOpenAddMembers]); +const addMembersPermissions = new Set([childOpenAddMembers]); const removeMembersPermission = { title: 'Remove members',