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 @@ -1,5 +1,8 @@ // @flow +import _keyBy from 'lodash/fp/keyBy.js'; +import _mapValues from 'lodash/fp/mapValues.js'; + import genesis from 'lib/facts/genesis.js'; import { permissionLookup, @@ -8,9 +11,16 @@ } from 'lib/permissions/thread-permissions.js'; import { relationshipBlockedInEitherDirection } from 'lib/shared/relationship-utils.js'; import { - threadFrozenDueToBlock, permissionsDisabledByBlock, + threadIsWithBlockedUserOnlyWithoutAdminRoleCheck, + threadMembersWithoutAddedAdmin, + roleIsAdminRole, } from 'lib/shared/thread-utils.js'; +import type { + MemberInfoWithPermissions, + RelativeMemberInfo, + ThreadInfo, +} from 'lib/types/minimally-encoded-thread-permissions-types.js'; import { userRelationshipStatus } from 'lib/types/relationship-types.js'; import type { ThreadPermission, @@ -18,6 +28,7 @@ ThreadRolePermissionsBlob, } from 'lib/types/thread-permission-types.js'; import type { ThreadType } from 'lib/types/thread-types-enum.js'; +import { values } from 'lib/utils/objects.js'; import { fetchThreadInfos } from './thread-fetchers.js'; import { fetchKnownUserInfos } from './user-fetchers.js'; @@ -157,16 +168,54 @@ fetchKnownUserInfos(viewer), ]); + const communityThreadIDs = new Set(); + for (const threadInfo of values(threadInfos)) { + const communityRootThread = threadInfo.community; + if (!communityRootThread) { + continue; + } + communityThreadIDs.add(communityRootThread); + } + + const { threadInfos: communityThreadInfos } = await fetchThreadInfos(viewer, { + threadIDs: communityThreadIDs, + }); + + const communityRootMembersToRole = _mapValues((threadInfo: ThreadInfo) => { + const keyedMembers = _keyBy('id')(threadInfo.members); + const keyedMembersToRole = _mapValues( + (member: MemberInfoWithPermissions | RelativeMemberInfo) => { + return member.role ? threadInfo.roles[member.role] : null; + }, + )(keyedMembers); + return keyedMembersToRole; + })(communityThreadInfos); + for (const threadID in threadInfos) { - const blockedThread = threadFrozenDueToBlock( - threadInfos[threadID], + const threadInfo = threadInfos[threadID]; + const communityMembersToRole = + communityRootMembersToRole[threadInfo.community]; + + const memberHasAdminRole = threadMembersWithoutAddedAdmin(threadInfo).some( + m => roleIsAdminRole(communityMembersToRole?.[m.id]), + ); + + if (memberHasAdminRole) { + continue; + } + + const blockedThread = threadIsWithBlockedUserOnlyWithoutAdminRoleCheck( + threadInfo, viewer.id, userInfos, + false, ); + if (blockedThread) { threadIDsWithDisabledPermissions.add(threadID); } } + return threadIDsWithDisabledPermissions; } 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 @@ -1006,7 +1006,7 @@ } function threadIsWithBlockedUserOnlyWithoutAdminRoleCheck( - threadInfo: ThreadInfo, + threadInfo: ThreadInfo | RawThreadInfo | LegacyRawThreadInfo, viewerID: ?string, userInfos: UserInfos, checkOnlyViewerBlock: boolean, @@ -1753,6 +1753,7 @@ threadUIName, threadInfoFromRawThreadInfo, threadTypeDescriptions, + threadIsWithBlockedUserOnlyWithoutAdminRoleCheck, memberHasAdminPowers, roleIsDefaultRole, roleIsAdminRole,