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 @@ -10,26 +10,15 @@ } from './dm-op-spec.js'; import type { DMAddMembersOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; -import { type RawMessageInfo } from '../../types/message-types.js'; import type { AddMembersMessageData } from '../../types/messages/add-members.js'; -import { - minimallyEncodeMemberInfo, - type ThickRawThreadInfo, -} from '../../types/minimally-encoded-thread-permissions-types.js'; +import { minimallyEncodeMemberInfo } 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 type { ClientUpdateInfo } from '../../types/update-types.js'; import { values } from '../../utils/objects.js'; import { rawMessageInfoFromMessageData } from '../message-utils.js'; import { roleIsDefaultRole, userIsMember } from '../thread-utils.js'; -export type AddMembersResult = { - rawMessageInfos: Array, - updateInfos: Array, - threadInfo: ?ThickRawThreadInfo, -}; - function createAddNewMembersMessageDataFromDMOperation( dmOperation: DMAddMembersOperation, ): AddMembersMessageData { 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,9 +2,11 @@ import uuid from 'uuid'; -import type { AddMembersResult } from './add-members-spec.js'; import { createThickRawThreadInfo } from './create-thread-spec.js'; -import type { DMOperationSpec } from './dm-op-spec.js'; +import type { + DMOperationSpec, + ProcessDMOperationUtilities, +} from './dm-op-spec.js'; import type { DMAddViewerToThreadMembersOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; import { messageTruncationStatus } from '../../types/message-types.js'; @@ -12,6 +14,7 @@ import { joinThreadSubscription } from '../../types/subscription-types.js'; import { updateTypes } from '../../types/update-types-enum.js'; import { rawMessageInfoFromMessageData } from '../message-utils.js'; +import { userIsMember } from '../thread-utils.js'; function createAddViewerToThreadMembersMessageDataFromDMOp( dmOperation: DMAddViewerToThreadMembersOperation, @@ -26,49 +29,6 @@ }; } -function createAddViewerToThreadMembersResults( - dmOperation: DMAddViewerToThreadMembersOperation, - viewerID: string, -): AddMembersResult { - const { time, messageID, addedUserIDs, existingThreadDetails } = dmOperation; - const messageData = - createAddViewerToThreadMembersMessageDataFromDMOp(dmOperation); - - const rawMessageInfos = [ - rawMessageInfoFromMessageData(messageData, messageID), - ]; - - const resultThreadInfo = createThickRawThreadInfo( - { - ...existingThreadDetails, - allMemberIDsWithSubscriptions: [ - ...existingThreadDetails.allMemberIDsWithSubscriptions, - ...addedUserIDs.map(id => ({ - id, - subscription: joinThreadSubscription, - })), - ], - }, - viewerID, - ); - const updateInfos = [ - { - type: updateTypes.JOIN_THREAD, - id: uuid.v4(), - time, - threadInfo: resultThreadInfo, - rawMessageInfos, - truncationStatus: messageTruncationStatus.EXHAUSTIVE, - rawEntryInfos: [], - }, - ]; - return { - rawMessageInfos: [], - updateInfos, - threadInfo: resultThreadInfo, - }; -} - const addViewerToThreadMembersSpec: DMOperationSpec = Object.freeze({ notificationsCreationData: async ( @@ -81,9 +41,85 @@ processDMOperation: async ( dmOperation: DMAddViewerToThreadMembersOperation, viewerID: string, + utilities: ProcessDMOperationUtilities, ) => { - const { rawMessageInfos, updateInfos } = - createAddViewerToThreadMembersResults(dmOperation, viewerID); + const { time, messageID, addedUserIDs, existingThreadDetails } = + dmOperation; + const messageData = + createAddViewerToThreadMembersMessageDataFromDMOp(dmOperation); + + const rawMessageInfos = [ + rawMessageInfoFromMessageData(messageData, messageID), + ]; + + const threadID = existingThreadDetails.threadID; + const currentThreadInfo = utilities.threadInfos[threadID]; + if (currentThreadInfo && !currentThreadInfo.thick) { + return { + rawMessageInfos: [], + updateInfos: [], + }; + } + + const memberTimestamps = { + ...currentThreadInfo?.timestamps?.members, + }; + const newMembers = []; + for (const userID of addedUserIDs) { + if (!memberTimestamps[userID]) { + memberTimestamps[userID] = { + isMember: time, + subscription: existingThreadDetails.creationTime, + }; + } + + if (memberTimestamps[userID].isMember > time) { + continue; + } + + memberTimestamps[userID] = { + ...memberTimestamps[userID], + isMember: time, + }; + + if (!userIsMember(currentThreadInfo, userID)) { + newMembers.push(userID); + } + } + + const resultThreadInfo = createThickRawThreadInfo( + { + ...existingThreadDetails, + allMemberIDsWithSubscriptions: [ + ...existingThreadDetails.allMemberIDsWithSubscriptions, + ...newMembers.map(id => ({ + id, + subscription: joinThreadSubscription, + })), + ], + }, + viewerID, + ); + const updateInfos = [ + { + type: updateTypes.JOIN_THREAD, + id: uuid.v4(), + time, + threadInfo: { + ...resultThreadInfo, + timestamps: { + ...resultThreadInfo.timestamps, + members: { + ...resultThreadInfo.timestamps.members, + ...memberTimestamps, + }, + }, + }, + rawMessageInfos, + truncationStatus: messageTruncationStatus.EXHAUSTIVE, + rawEntryInfos: [], + }, + ]; return { rawMessageInfos, updateInfos }; }, canBeProcessed( @@ -106,6 +142,5 @@ export { addViewerToThreadMembersSpec, - createAddViewerToThreadMembersResults, createAddViewerToThreadMembersMessageDataFromDMOp, };