diff --git a/lib/shared/dm-ops/add-members-spec.js b/lib/shared/dm-ops/add-members-spec.js --- a/lib/shared/dm-ops/add-members-spec.js +++ b/lib/shared/dm-ops/add-members-spec.js @@ -16,7 +16,9 @@ import type { RawMessageInfo } from '../../types/message-types.js'; import type { AddMembersMessageData } from '../../types/messages/add-members.js'; import { minimallyEncodeMemberInfo } from '../../types/minimally-encoded-thread-permissions-types.js'; +import type { ThickRawThreadInfo } from '../../types/minimally-encoded-thread-permissions-types.js'; import { joinThreadSubscription } from '../../types/subscription-types.js'; +import type { ThreadPermissionsInfo } from '../../types/thread-permission-types.js'; import type { ThickMemberInfo } from '../../types/thread-types.js'; import { updateTypes } from '../../types/update-types-enum.js'; import { values } from '../../utils/objects.js'; @@ -41,6 +43,46 @@ return { messageData, rawMessageInfo }; } +function createPermissionsForNewMembers( + threadInfo: ThickRawThreadInfo, + utilities: ProcessDMOperationUtilities, +): { + +membershipPermissions: ThreadPermissionsInfo, + +roleID: string, +} { + const defaultRoleID = values(threadInfo.roles).find(role => + roleIsDefaultRole(role), + )?.id; + invariant(defaultRoleID, 'Default role ID must exist'); + + const { parentThreadID } = threadInfo; + const parentThreadInfo = parentThreadID + ? utilities.threadInfos[parentThreadID] + : null; + if (parentThreadID && !parentThreadInfo) { + console.log( + `Parent thread with ID ${parentThreadID} was expected while adding ` + + 'thread members but is missing from the store', + ); + } + invariant( + !parentThreadInfo || parentThreadInfo.thick, + 'Parent thread should be thick', + ); + + const { membershipPermissions } = createRoleAndPermissionForThickThreads( + threadInfo.type, + threadInfo.id, + defaultRoleID, + parentThreadInfo, + ); + + return { + membershipPermissions, + roleID: defaultRoleID, + }; +} + const addMembersSpec: DMOperationSpec = Object.freeze({ notificationsCreationData: async (dmOperation: DMAddMembersOperation) => { return { @@ -69,31 +111,9 @@ }; } - const defaultRoleID = values(currentThreadInfo.roles).find(role => - roleIsDefaultRole(role), - )?.id; - invariant(defaultRoleID, 'Default role ID must exist'); - - const parentThreadID = currentThreadInfo.parentThreadID; - const parentThreadInfo = parentThreadID - ? utilities.threadInfos[parentThreadID] - : null; - if (parentThreadID && !parentThreadInfo) { - console.log( - `Parent thread with ID ${parentThreadID} was expected while adding ` + - 'thread members but is missing from the store', - ); - } - invariant( - !parentThreadInfo || parentThreadInfo.thick, - 'Parent thread should be thick', - ); - - const { membershipPermissions } = createRoleAndPermissionForThickThreads( - currentThreadInfo.type, - currentThreadInfo.id, - defaultRoleID, - parentThreadInfo, + const { membershipPermissions, roleID } = createPermissionsForNewMembers( + currentThreadInfo, + utilities, ); const memberTimestamps = { ...currentThreadInfo.timestamps.members }; @@ -122,7 +142,7 @@ newMembers.push( minimallyEncodeMemberInfo({ id: userID, - role: defaultRoleID, + role: roleID, permissions: membershipPermissions, isSender: editorID === viewerID, subscription: joinThreadSubscription, @@ -175,4 +195,5 @@ export { addMembersSpec, createAddNewMembersMessageDataWithInfoFromDMOperation, + createPermissionsForNewMembers, }; diff --git a/lib/shared/dm-ops/add-viewer-to-thread-members-spec.js b/lib/shared/dm-ops/add-viewer-to-thread-members-spec.js --- a/lib/shared/dm-ops/add-viewer-to-thread-members-spec.js +++ b/lib/shared/dm-ops/add-viewer-to-thread-members-spec.js @@ -2,6 +2,7 @@ import uuid from 'uuid'; +import { createPermissionsForNewMembers } from './add-members-spec.js'; import { createThickRawThreadInfo } from './create-thread-spec.js'; import type { DMOperationSpec, @@ -15,7 +16,12 @@ import type { RawMessageInfo } from '../../types/message-types.js'; import { messageTruncationStatus } from '../../types/message-types.js'; import type { AddMembersMessageData } from '../../types/messages/add-members.js'; +import { + minimallyEncodeMemberInfo, + minimallyEncodeThreadCurrentUserInfo, +} from '../../types/minimally-encoded-thread-permissions-types.js'; import { joinThreadSubscription } from '../../types/subscription-types.js'; +import type { ThickMemberInfo } from '../../types/thread-types.js'; import { updateTypes } from '../../types/update-types-enum.js'; import { rawMessageInfoFromMessageData } from '../message-utils.js'; import { userIsMember } from '../thread-utils.js'; @@ -56,7 +62,7 @@ dmOperation: DMAddViewerToThreadMembersOperation, utilities: ProcessDMOperationUtilities, ) => { - const { time, messageID, addedUserIDs, existingThreadDetails } = + const { time, messageID, addedUserIDs, existingThreadDetails, editorID } = dmOperation; const { threadInfos } = utilities; @@ -100,6 +106,54 @@ } } + if (currentThreadInfo) { + const { membershipPermissions, roleID } = + createPermissionsForNewMembers(currentThreadInfo, utilities); + + const newMemberInfos = newMembers.map(userID => + minimallyEncodeMemberInfo({ + id: userID, + role: roleID, + permissions: membershipPermissions, + isSender: editorID === utilities.viewerID, + subscription: joinThreadSubscription, + }), + ); + + const resultThreadInfo = { + ...currentThreadInfo, + members: [...currentThreadInfo.members, ...newMemberInfos], + currentUser: minimallyEncodeThreadCurrentUserInfo({ + role: roleID, + permissions: membershipPermissions, + subscription: joinThreadSubscription, + unread: true, + }), + timestamps: { + ...currentThreadInfo.timestamps, + members: { + ...currentThreadInfo.timestamps.members, + ...memberTimestamps, + }, + }, + }; + + const updateInfos = [ + { + type: updateTypes.UPDATE_THREAD, + id: uuid.v4(), + time, + threadInfo: resultThreadInfo, + }, + ]; + + return { + rawMessageInfos, + updateInfos, + blobOps: [], + }; + } + const resultThreadInfo = createThickRawThreadInfo( { ...existingThreadDetails, @@ -132,7 +186,7 @@ }, ]; return { - rawMessageInfos, + rawMessageInfos: [], updateInfos, blobOps: [], };