diff --git a/keyserver/src/creators/thread-creator.js b/keyserver/src/creators/thread-creator.js --- a/keyserver/src/creators/thread-creator.js +++ b/keyserver/src/creators/thread-creator.js @@ -41,6 +41,7 @@ import { determineThreadAncestry, personalThreadQuery, + determineThreadAncestryForPossibleMemberResolution, } from '../fetchers/thread-fetchers.js'; import { checkThreadPermission, @@ -162,6 +163,11 @@ const validateMembersPromise = (async () => { const threadAncestry = await determineThreadAncestryPromise; + const containingThreadIDForPossibleMemberResolution = + determineThreadAncestryForPossibleMemberResolution( + parentThreadID, + threadAncestry.containingThreadID, + ); const defaultRolePermissions = getRolePermissionBlobs(threadType).Members; const { initialMemberIDs, ghostMemberIDs } = await validateCandidateMembers( viewer, @@ -172,8 +178,9 @@ { threadType, parentThreadID, - containingThreadID: threadAncestry.containingThreadID, + containingThreadID: containingThreadIDForPossibleMemberResolution, defaultRolePermissions, + communityID: threadAncestry.community, }, { requireRelationship: !shouldCreateRelationships }, ); 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 @@ -2,6 +2,7 @@ import invariant from 'invariant'; +import genesis from 'lib/facts/genesis.js'; import { specialRoles } from 'lib/permissions/special-roles.js'; import { getAllThreadPermissions } from 'lib/permissions/thread-permissions.js'; import { @@ -382,6 +383,18 @@ return { containingThreadID, community, depth }; } +function determineThreadAncestryForPossibleMemberResolution( + parentThreadID: ?string, + containingThreadID: ?string, +): ?string { + let resolvedContainingThreadID = containingThreadID; + if (resolvedContainingThreadID === genesis().id) { + resolvedContainingThreadID = + parentThreadID === genesis().id ? null : parentThreadID; + } + return resolvedContainingThreadID; +} + function personalThreadQuery( firstMemberID: string, secondMemberID: string, @@ -442,6 +455,7 @@ verifyThreadIDs, verifyThreadID, determineThreadAncestry, + determineThreadAncestryForPossibleMemberResolution, personalThreadQuery, fetchPersonalThreadID, serverThreadInfoFromMessageInfo, diff --git a/keyserver/src/fetchers/thread-permission-fetchers.js b/keyserver/src/fetchers/thread-permission-fetchers.js --- a/keyserver/src/fetchers/thread-permission-fetchers.js +++ b/keyserver/src/fetchers/thread-permission-fetchers.js @@ -274,6 +274,7 @@ +parentThreadID: ?string, +containingThreadID: ?string, +defaultRolePermissions: ThreadRolePermissionsBlob, + +communityID: ?string, }; type ValidateCandidateMembersOptions = { +requireRelationship?: boolean }; async function validateCandidateMembers( @@ -370,14 +371,17 @@ continue; } const permissionsFromParent = parentPermissions[memberID]; - if (memberOfContainingThread.get(memberID) === 'non-member') { + if ( + memberOfContainingThread.get(memberID) === 'non-member' && + (params.communityID !== genesis().id || + (relationshipStatus !== userRelationshipStatus.FRIEND && + requireRelationship)) + ) { ignoreMembers.add(memberID); continue; } - const isParentThreadGenesis = params.parentThreadID === genesis().id; if ( - (memberOfContainingThread.get(memberID) === 'no-containing-thread' || - isParentThreadGenesis) && + memberOfContainingThread.get(memberID) === 'no-containing-thread' && relationshipStatus !== userRelationshipStatus.FRIEND && requireRelationship ) { diff --git a/keyserver/src/updaters/thread-updaters.js b/keyserver/src/updaters/thread-updaters.js --- a/keyserver/src/updaters/thread-updaters.js +++ b/keyserver/src/updaters/thread-updaters.js @@ -53,6 +53,7 @@ fetchServerThreadInfos, determineThreadAncestry, rawThreadInfosFromServerThreadInfos, + determineThreadAncestryForPossibleMemberResolution, } from '../fetchers/thread-fetchers.js'; import { checkThreadPermission, @@ -586,14 +587,21 @@ determineThreadAncestryPromise, ]); + const containingThreadIDForPossibleMemberResolution = + determineThreadAncestryForPossibleMemberResolution( + nextParentThreadID, + nextThreadAncestry.containingThreadID, + ); + const { newMemberIDs: validatedIDs } = await validateCandidateMembers( viewer, { newMemberIDs }, { threadType: nextThreadType, parentThreadID: nextParentThreadID, - containingThreadID: nextThreadAncestry.containingThreadID, + containingThreadID: containingThreadIDForPossibleMemberResolution, defaultRolePermissions, + communityID: nextThreadAncestry.community, }, { requireRelationship: !forceAddMembers }, );