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 @@ -11,6 +11,7 @@ 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, @@ -20,6 +21,7 @@ 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 = { @@ -28,21 +30,30 @@ threadInfo: ?ThickRawThreadInfo, }; -function createAddNewMembersResults( +function createAddNewMembersMessageDataFromDMOperation( dmOperation: DMAddMembersOperation, - viewerID: string, - utilities: ProcessDMOperationUtilities, -): AddMembersResult { - const { editorID, time, messageID, addedUserIDs, threadID } = dmOperation; - const addMembersMessage = { +): AddMembersMessageData { + const { editorID, time, addedUserIDs, threadID } = dmOperation; + return { type: messageTypes.ADD_MEMBERS, - id: messageID, threadID, creatorID: editorID, time, addedUserIDs: [...addedUserIDs], }; +} +function createAddNewMembersResults( + dmOperation: DMAddMembersOperation, + viewerID: string, + utilities: ProcessDMOperationUtilities, +): AddMembersResult { + const { editorID, time, messageID, addedUserIDs, threadID } = dmOperation; + const messageData = + createAddNewMembersMessageDataFromDMOperation(dmOperation); + const rawMessageInfos = [ + rawMessageInfoFromMessageData(messageData, messageID), + ]; const currentThreadInfo = utilities.threadInfos[threadID]; if (!currentThreadInfo.thick) { return { @@ -86,13 +97,18 @@ ]; return { - rawMessageInfos: [addMembersMessage], + rawMessageInfos, updateInfos, threadInfo: resultThreadInfo, }; } const addMembersSpec: DMOperationSpec = Object.freeze({ + notificationsCreationData: async (dmOperation: DMAddMembersOperation) => { + const messageData = + createAddNewMembersMessageDataFromDMOperation(dmOperation); + return { messageDatas: [messageData] }; + }, processDMOperation: async ( dmOperation: DMAddMembersOperation, viewerID: string, @@ -124,4 +140,8 @@ supportsAutoRetry: true, }); -export { addMembersSpec, createAddNewMembersResults }; +export { + addMembersSpec, + createAddNewMembersResults, + createAddNewMembersMessageDataFromDMOperation, +}; 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 @@ -8,22 +8,34 @@ import type { DMAddViewerToThreadMembersOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; import { messageTruncationStatus } from '../../types/message-types.js'; +import type { AddMembersMessageData } from '../../types/messages/add-members.js'; import { updateTypes } from '../../types/update-types-enum.js'; +import { rawMessageInfoFromMessageData } from '../message-utils.js'; -function createAddViewerToThreadMembersResults( +function createAddViewerToThreadMembersMessageDataFromDMOp( dmOperation: DMAddViewerToThreadMembersOperation, - viewerID: string, -): AddMembersResult { - const { editorID, time, messageID, addedUserIDs, existingThreadDetails } = - dmOperation; - const addMembersMessage = { +): AddMembersMessageData { + const { editorID, time, addedUserIDs, existingThreadDetails } = dmOperation; + return { type: messageTypes.ADD_MEMBERS, - id: messageID, threadID: existingThreadDetails.threadID, creatorID: editorID, time, addedUserIDs: [...addedUserIDs], }; +} + +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( { @@ -38,7 +50,7 @@ id: uuid.v4(), time, threadInfo: resultThreadInfo, - rawMessageInfos: [addMembersMessage], + rawMessageInfos, truncationStatus: messageTruncationStatus.EXHAUSTIVE, rawEntryInfos: [], }, @@ -52,6 +64,13 @@ const addViewerToThreadMembersSpec: DMOperationSpec = Object.freeze({ + notificationsCreationData: async ( + dmOperation: DMAddViewerToThreadMembersOperation, + ) => { + const messageData = + createAddViewerToThreadMembersMessageDataFromDMOp(dmOperation); + return { messageDatas: [messageData] }; + }, processDMOperation: async ( dmOperation: DMAddViewerToThreadMembersOperation, viewerID: string, @@ -78,4 +97,8 @@ supportsAutoRetry: true, }); -export { addViewerToThreadMembersSpec, createAddViewerToThreadMembersResults }; +export { + addViewerToThreadMembersSpec, + createAddViewerToThreadMembersResults, + createAddViewerToThreadMembersMessageDataFromDMOp, +}; diff --git a/lib/shared/dm-ops/change-thread-settings-and-add-viewer-spec.js b/lib/shared/dm-ops/change-thread-settings-and-add-viewer-spec.js --- a/lib/shared/dm-ops/change-thread-settings-and-add-viewer-spec.js +++ b/lib/shared/dm-ops/change-thread-settings-and-add-viewer-spec.js @@ -3,13 +3,19 @@ import { addViewerToThreadMembersSpec, createAddViewerToThreadMembersResults, + createAddViewerToThreadMembersMessageDataFromDMOp, } from './add-viewer-to-thread-members-spec.js'; -import { processChangeSettingsOperation } from './change-thread-settings-spec.js'; +import { + processChangeSettingsOperation, + createChangeSettingsMessageDatasAndUpdate, +} from './change-thread-settings-spec.js'; import type { DMOperationSpec, ProcessDMOperationUtilities, } from './dm-op-spec.js'; import type { DMChangeThreadSettingsAndAddViewerOperation } from '../../types/dm-ops.js'; +import type { MessageData } from '../../types/message-types.js'; +import { values } from '../../utils/objects.js'; function createAddViewerAndMembersOperation( dmOperation: DMChangeThreadSettingsAndAddViewerOperation, @@ -43,6 +49,25 @@ const changeThreadSettingsAndAddViewerSpec: DMOperationSpec = Object.freeze({ + notificationsCreationData: async ( + dmOperation: DMChangeThreadSettingsAndAddViewerOperation, + ) => { + const messageDatas: Array = []; + const addNewMembersOperation = + createAddViewerAndMembersOperation(dmOperation); + if (addNewMembersOperation) { + const addNewMembersMessageData = + createAddViewerToThreadMembersMessageDataFromDMOp( + addNewMembersOperation, + ); + messageDatas.push(addNewMembersMessageData); + } + + const { fieldNameToMessageData } = + createChangeSettingsMessageDatasAndUpdate(dmOperation); + messageDatas.push(...values(fieldNameToMessageData)); + return { messageDatas }; + }, processDMOperation: async ( dmOperation: DMChangeThreadSettingsAndAddViewerOperation, viewerID: string, diff --git a/lib/shared/dm-ops/change-thread-settings-spec.js b/lib/shared/dm-ops/change-thread-settings-spec.js --- a/lib/shared/dm-ops/change-thread-settings-spec.js +++ b/lib/shared/dm-ops/change-thread-settings-spec.js @@ -6,6 +6,7 @@ import { type AddMembersResult, createAddNewMembersResults, + createAddNewMembersMessageDataFromDMOperation, } from './add-members-spec.js'; import type { DMOperationSpec, @@ -15,19 +16,19 @@ DMChangeThreadSettingsAndAddViewerOperation, DMChangeThreadSettingsOperation, DMOperationResult, + DMThreadSettingsChangesBase, } from '../../types/dm-ops.js'; +import type { MessageData, RawMessageInfo } from '../../types/message-types'; import { messageTypes } from '../../types/message-types-enum.js'; -import type { RawMessageInfo } from '../../types/message-types.js'; +import type { ChangeSettingsMessageData } from '../../types/messages/change-settings.js'; import type { RawThreadInfo } from '../../types/minimally-encoded-thread-permissions-types.js'; -import type { LegacyRawThreadInfo } 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'; -function processAddMembersOperation( +function createAddMembersOperation( dmOperation: DMChangeThreadSettingsOperation, - viewerID: string, - utilities: ProcessDMOperationUtilities, ) { const { editorID, time, messageIDsPrefix, changes, threadID } = dmOperation; const newMemberIDs = @@ -37,7 +38,7 @@ if (!changes.newMemberIDs || changes.newMemberIDs.length === 0) { return null; } - const operation = { + return { type: 'add_members', editorID, time, @@ -45,87 +46,127 @@ addedUserIDs: newMemberIDs, threadID, }; +} + +function processAddMembersOperation( + dmOperation: DMChangeThreadSettingsOperation, + viewerID: string, + utilities: ProcessDMOperationUtilities, +) { + const operation = createAddMembersOperation(dmOperation); + if (!operation) { + return null; + } return createAddNewMembersResults(operation, viewerID, utilities); } -function processChangeSettingsOperation( +function getThreadIDFromChangeThreadSettingsDMOp( dmOperation: | DMChangeThreadSettingsOperation | DMChangeThreadSettingsAndAddViewerOperation, - viewerID: string, - utilities: ProcessDMOperationUtilities, - addMembersResult: ?AddMembersResult, -): DMOperationResult { - const { editorID, time, changes, messageIDsPrefix } = dmOperation; - const { name, description, color, avatar } = changes; - const threadID = - dmOperation.type === 'change_thread_settings' - ? dmOperation.threadID - : dmOperation.existingThreadDetails.threadID; - - let threadInfoToUpdate: ?(RawThreadInfo | LegacyRawThreadInfo) = - utilities.threadInfos[threadID]; - const updateInfos: Array = []; - const rawMessageInfos: Array = []; - - if (addMembersResult) { - if (addMembersResult.threadInfo) { - threadInfoToUpdate = addMembersResult.threadInfo; - } - updateInfos.push(...addMembersResult.updateInfos); - rawMessageInfos.push(...addMembersResult.rawMessageInfos); - } +): string { + return dmOperation.type === 'change_thread_settings' + ? dmOperation.threadID + : dmOperation.existingThreadDetails.threadID; +} - invariant(threadInfoToUpdate?.thick, 'Thread should be thick'); +function createChangeSettingsMessageDatasAndUpdate( + dmOperation: + | DMChangeThreadSettingsOperation + | DMChangeThreadSettingsAndAddViewerOperation, +): { + +fieldNameToMessageData: { +[fieldName: string]: ChangeSettingsMessageData }, + +threadInfoUpdate: DMThreadSettingsChangesBase, +} { + const { changes, editorID, time } = dmOperation; + const { name, description, color, avatar } = changes; + const threadID = getThreadIDFromChangeThreadSettingsDMOp(dmOperation); - const changedFields: { [string]: string | number } = {}; + const threadInfoUpdate: { ...DMThreadSettingsChangesBase } = {}; if (name !== undefined && name !== null) { - changedFields.name = name; - threadInfoToUpdate = { - ...threadInfoToUpdate, - name, - }; + threadInfoUpdate.name = name; } if (description !== undefined && description !== null) { - changedFields.description = description; - threadInfoToUpdate = { - ...threadInfoToUpdate, - description, - }; + threadInfoUpdate.description = description; } if (color) { - changedFields.color = color; - threadInfoToUpdate = { - ...threadInfoToUpdate, - color, - }; + threadInfoUpdate.color = color; } if (avatar) { - changedFields.avatar = JSON.stringify(avatar); - threadInfoToUpdate = { - ...threadInfoToUpdate, - avatar, - }; + threadInfoUpdate.avatar; } - for (const fieldName in changedFields) { - const newValue = changedFields[fieldName]; - rawMessageInfos.push({ + const fieldNameToMessageData: { + [fieldName: string]: ChangeSettingsMessageData, + } = {}; + + const { avatar: avatarObject, ...rest } = threadInfoUpdate; + const normalizedThreadInfoUpdate = avatarObject + ? { ...rest, avatar: JSON.stringify(avatarObject) } + : { ...rest }; + + for (const fieldName in normalizedThreadInfoUpdate) { + const value = normalizedThreadInfoUpdate[fieldName]; + fieldNameToMessageData[fieldName] = { type: messageTypes.CHANGE_SETTINGS, threadID, creatorID: editorID, time, field: fieldName, - value: newValue, - id: `${messageIDsPrefix}/${fieldName}`, - }); + value: value, + }; } - if (values(changedFields).length > 0) { + return { fieldNameToMessageData, threadInfoUpdate }; +} + +function processChangeSettingsOperation( + dmOperation: + | DMChangeThreadSettingsOperation + | DMChangeThreadSettingsAndAddViewerOperation, + viewerID: string, + utilities: ProcessDMOperationUtilities, + addMembersResult: ?AddMembersResult, +): DMOperationResult { + const { time, messageIDsPrefix } = dmOperation; + const threadID = getThreadIDFromChangeThreadSettingsDMOp(dmOperation); + + let threadInfoToUpdate: ?RawThreadInfo = utilities.threadInfos[threadID]; + const updateInfos: Array = []; + const rawMessageInfos: Array = []; + + if (addMembersResult) { + if (addMembersResult.threadInfo) { + threadInfoToUpdate = addMembersResult.threadInfo; + } + updateInfos.push(...addMembersResult.updateInfos); + rawMessageInfos.push(...addMembersResult.rawMessageInfos); + } + + invariant(threadInfoToUpdate?.thick, 'Thread should be thick'); + const { fieldNameToMessageData, threadInfoUpdate } = + createChangeSettingsMessageDatasAndUpdate(dmOperation); + + const fieldNameToMessageDataPairs = Object.entries(fieldNameToMessageData); + rawMessageInfos.push( + ...fieldNameToMessageDataPairs.map(([fieldName, messageData]) => + rawMessageInfoFromMessageData( + messageData, + `${messageIDsPrefix}/${fieldName}`, + ), + ), + ); + + threadInfoToUpdate = { + ...threadInfoToUpdate, + ...threadInfoUpdate, + }; + + if (fieldNameToMessageDataPairs.length > 0) { updateInfos.push({ type: updateTypes.UPDATE_THREAD, id: uuid.v4(), @@ -142,6 +183,22 @@ const changeThreadSettingsSpec: DMOperationSpec = Object.freeze({ + notificationsCreationData: async ( + dmOperation: DMChangeThreadSettingsOperation, + ) => { + const messageDatas: Array = []; + const addNewMembersOperation = createAddMembersOperation(dmOperation); + if (addNewMembersOperation) { + const addNewMembersMessageData = + createAddNewMembersMessageDataFromDMOperation(addNewMembersOperation); + messageDatas.push(addNewMembersMessageData); + } + + const { fieldNameToMessageData } = + createChangeSettingsMessageDatasAndUpdate(dmOperation); + messageDatas.push(...values(fieldNameToMessageData)); + return { messageDatas }; + }, processDMOperation: async ( dmOperation: DMChangeThreadSettingsOperation, viewerID: string, @@ -179,4 +236,8 @@ supportsAutoRetry: true, }); -export { changeThreadSettingsSpec, processChangeSettingsOperation }; +export { + changeThreadSettingsSpec, + processChangeSettingsOperation, + createChangeSettingsMessageDatasAndUpdate, +}; diff --git a/lib/shared/dm-ops/create-sidebar-spec.js b/lib/shared/dm-ops/create-sidebar-spec.js --- a/lib/shared/dm-ops/create-sidebar-spec.js +++ b/lib/shared/dm-ops/create-sidebar-spec.js @@ -15,10 +15,81 @@ } from '../../types/message-types.js'; import { threadTypes } from '../../types/thread-types-enum.js'; import { updateTypes } from '../../types/update-types-enum.js'; -import { isInvalidSidebarSource } from '../message-utils.js'; +import { generatePendingThreadColor } from '../color-utils.js'; +import { + isInvalidSidebarSource, + rawMessageInfoFromMessageData, +} from '../message-utils.js'; + +async function createMessageDatasFromDMOperation( + dmOperation: DMCreateSidebarOperation, + utilities: ProcessDMOperationUtilities, + threadColor?: string, +) { + const { + threadID, + creatorID, + time, + parentThreadID, + memberIDs, + sourceMessageID, + } = dmOperation; + + const allMemberIDs = [creatorID, ...memberIDs]; + const color = threadColor ?? generatePendingThreadColor(allMemberIDs); + const sourceMessage = await utilities.fetchMessage(sourceMessageID); + + if (!sourceMessage) { + throw new Error( + `could not find sourceMessage ${sourceMessageID}... probably ` + + 'joined thick thread ${parentThreadID} after its creation', + ); + } + if (isInvalidSidebarSource(sourceMessage)) { + throw new Error( + `sourceMessage ${sourceMessageID} is an invalid sidebar source`, + ); + } + + const sidebarSourceMessageData = { + type: messageTypes.SIDEBAR_SOURCE, + threadID, + creatorID, + time, + sourceMessage: sourceMessage, + }; + + const createSidebarMessageData = { + type: messageTypes.CREATE_SIDEBAR, + threadID, + creatorID, + time: time + 1, + sourceMessageAuthorID: sourceMessage.creatorID, + initialThreadState: { + parentThreadID, + color, + memberIDs: allMemberIDs, + }, + }; + + return { + sidebarSourceMessageData, + createSidebarMessageData, + }; +} const createSidebarSpec: DMOperationSpec = Object.freeze({ + notificationsCreationData: async ( + dmOperation: DMCreateSidebarOperation, + utilities: ProcessDMOperationUtilities, + ) => { + const { sidebarSourceMessageData, createSidebarMessageData } = + await createMessageDatasFromDMOperation(dmOperation, utilities); + return { + messageDatas: [sidebarSourceMessageData, createSidebarMessageData], + }; + }, processDMOperation: async ( dmOperation: DMCreateSidebarOperation, viewerID: string, @@ -52,41 +123,25 @@ viewerID, ); - const sourceMessage = await utilities.fetchMessage(sourceMessageID); - if (!sourceMessage) { - throw new Error( - `could not find sourceMessage ${sourceMessageID}... probably ` + - 'joined thick thread ${parentThreadID} after its creation', + const { sidebarSourceMessageData, createSidebarMessageData } = + await createMessageDatasFromDMOperation( + dmOperation, + utilities, + rawThreadInfo.color, ); - } - if (isInvalidSidebarSource(sourceMessage)) { - throw new Error( - `sourceMessage ${sourceMessageID} is an invalid sidebar source`, - ); - } + + const sidebarSourceMessageInfo = rawMessageInfoFromMessageData( + sidebarSourceMessageData, + newSidebarSourceMessageID, + ); + const createSidebarMessageInfo = rawMessageInfoFromMessageData( + createSidebarMessageData, + newCreateSidebarMessageID, + ); const rawMessageInfos: Array = [ - { - type: messageTypes.SIDEBAR_SOURCE, - id: newSidebarSourceMessageID, - threadID, - creatorID, - time, - sourceMessage, - }, - { - type: messageTypes.CREATE_SIDEBAR, - id: newCreateSidebarMessageID, - threadID, - creatorID, - time: time + 1, - sourceMessageAuthorID: sourceMessage.creatorID, - initialThreadState: { - parentThreadID, - color: rawThreadInfo.color, - memberIDs: allMemberIDs, - }, - }, + sidebarSourceMessageInfo, + createSidebarMessageInfo, ]; const threadJoinUpdateInfo = { diff --git a/lib/shared/dm-ops/create-thread-spec.js b/lib/shared/dm-ops/create-thread-spec.js --- a/lib/shared/dm-ops/create-thread-spec.js +++ b/lib/shared/dm-ops/create-thread-spec.js @@ -14,10 +14,7 @@ DMCreateThreadOperation, } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; -import { - type RawMessageInfo, - messageTruncationStatus, -} from '../../types/message-types.js'; +import { messageTruncationStatus } from '../../types/message-types.js'; import { type ThickRawThreadInfo, type RoleInfo, @@ -31,6 +28,7 @@ import type { ThickMemberInfo } from '../../types/thread-types.js'; import { updateTypes } from '../../types/update-types-enum.js'; import { generatePendingThreadColor } from '../color-utils.js'; +import { rawMessageInfoFromMessageData } from '../message-utils.js'; function createRoleAndPermissionForThickThreads( threadType: ThickThreadType, @@ -126,8 +124,31 @@ return newThread; } +function createMessageDataFromDMOperation( + dmOperation: DMCreateThreadOperation, +) { + const { threadID, creatorID, time, threadType, memberIDs } = dmOperation; + const allMemberIDs = [creatorID, ...memberIDs]; + const color = generatePendingThreadColor(allMemberIDs); + return { + type: messageTypes.CREATE_THREAD, + threadID, + creatorID, + time, + initialThreadState: { + type: threadType, + color, + memberIDs: allMemberIDs, + }, + }; +} + const createThreadSpec: DMOperationSpec = Object.freeze({ + notificationsCreationData: async (dmOperation: DMCreateThreadOperation) => { + const messageData = createMessageDataFromDMOperation(dmOperation); + return { messageDatas: [messageData] }; + }, processDMOperation: async ( dmOperation: DMCreateThreadOperation, viewerID: string, @@ -155,19 +176,9 @@ viewerID, ); - const rawMessageInfos: Array = [ - { - type: messageTypes.CREATE_THREAD, - id: newMessageID, - threadID, - creatorID, - time, - initialThreadState: { - type: threadType, - color: rawThreadInfo.color, - memberIDs: allMemberIDs, - }, - }, + const messageData = createMessageDataFromDMOperation(dmOperation); + const rawMessageInfos = [ + rawMessageInfoFromMessageData(messageData, newMessageID), ]; const threadJoinUpdateInfo = { diff --git a/lib/shared/dm-ops/dm-op-spec.js b/lib/shared/dm-ops/dm-op-spec.js --- a/lib/shared/dm-ops/dm-op-spec.js +++ b/lib/shared/dm-ops/dm-op-spec.js @@ -2,6 +2,7 @@ import type { DMOperation, DMOperationResult } from '../../types/dm-ops.js'; import type { RawMessageInfo } from '../../types/message-types.js'; +import type { NotificationsCreationData } from '../../types/notif-types.js'; import type { RawThreadInfos } from '../../types/thread-types.js'; export type ProcessDMOperationUtilities = { @@ -11,6 +12,10 @@ }; export type DMOperationSpec = { + +notificationsCreationData?: ( + dmOp: DMOp, + utilities: ProcessDMOperationUtilities, + ) => Promise, +processDMOperation: ( dmOp: DMOp, viewerID: string, diff --git a/lib/shared/dm-ops/join-thread-spec.js b/lib/shared/dm-ops/join-thread-spec.js --- a/lib/shared/dm-ops/join-thread-spec.js +++ b/lib/shared/dm-ops/join-thread-spec.js @@ -23,9 +23,24 @@ 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'; +function createMessageDataFromDMOperation(dmOperation: DMJoinThreadOperation) { + const { joinerID, time, existingThreadDetails } = dmOperation; + return { + type: messageTypes.JOIN_THREAD, + threadID: existingThreadDetails.threadID, + creatorID: joinerID, + time, + }; +} + const joinThreadSpec: DMOperationSpec = Object.freeze({ + notificationsCreationData: async (dmOperation: DMJoinThreadOperation) => { + const messageData = createMessageDataFromDMOperation(dmOperation); + return { messageDatas: [messageData] }; + }, processDMOperation: async ( dmOperation: DMJoinThreadOperation, viewerID: string, @@ -36,17 +51,14 @@ const currentThreadInfo = utilities.threadInfos[existingThreadDetails.threadID]; - const joinThreadMessage = { - type: messageTypes.JOIN_THREAD, - id: messageID, - threadID: existingThreadDetails.threadID, - creatorID: joinerID, - time, - }; + const messageData = createMessageDataFromDMOperation(dmOperation); + const joinThreadMessageInfos = [ + rawMessageInfoFromMessageData(messageData, messageID), + ]; if (userIsMember(currentThreadInfo, joinerID)) { return { - rawMessageInfos: [joinThreadMessage], + rawMessageInfos: joinThreadMessageInfos, updateInfos: [], }; } @@ -66,14 +78,14 @@ id: uuid.v4(), time, threadInfo: newThreadInfo, - rawMessageInfos: [joinThreadMessage], + rawMessageInfos: joinThreadMessageInfos, truncationStatus: messageTruncationStatus.EXHAUSTIVE, rawEntryInfos: [], }); } else { invariant(currentThreadInfo.thick, 'Thread should be thick'); - rawMessageInfos.push(joinThreadMessage); + rawMessageInfos.push(...joinThreadMessageInfos); const defaultRoleID = values(currentThreadInfo.roles).find(role => roleIsDefaultRole(role), )?.id; diff --git a/lib/shared/dm-ops/leave-thread-spec.js b/lib/shared/dm-ops/leave-thread-spec.js --- a/lib/shared/dm-ops/leave-thread-spec.js +++ b/lib/shared/dm-ops/leave-thread-spec.js @@ -12,9 +12,24 @@ import { threadTypes } from '../../types/thread-types-enum.js'; import { updateTypes } from '../../types/update-types-enum.js'; import type { ClientUpdateInfo } from '../../types/update-types.js'; +import { rawMessageInfoFromMessageData } from '../message-utils.js'; import { userIsMember } from '../thread-utils.js'; +function createMessageDataFromDMOperation(dmOperation: DMLeaveThreadOperation) { + const { editorID, time, threadID } = dmOperation; + return { + type: messageTypes.LEAVE_THREAD, + threadID, + creatorID: editorID, + time, + }; +} + const leaveThreadSpec: DMOperationSpec = Object.freeze({ + notificationsCreationData: async (dmOperation: DMLeaveThreadOperation) => { + const messageData = createMessageDataFromDMOperation(dmOperation); + return { messageDatas: [messageData] }; + }, processDMOperation: async ( dmOperation: DMLeaveThreadOperation, viewerID: string, @@ -25,13 +40,10 @@ const threadInfo = utilities.threadInfos[threadID]; invariant(threadInfo.thick, 'Thread should be thick'); - const leaveThreadMessage = { - type: messageTypes.LEAVE_THREAD, - id: messageID, - threadID, - creatorID: editorID, - time, - }; + const messageData = createMessageDataFromDMOperation(dmOperation); + const rawMessageInfos = [ + rawMessageInfoFromMessageData(messageData, messageID), + ]; const updateInfos: Array = []; if ( @@ -61,7 +73,7 @@ } return { - rawMessageInfos: [leaveThreadMessage], + rawMessageInfos, updateInfos, }; }, diff --git a/lib/shared/dm-ops/remove-members-spec.js b/lib/shared/dm-ops/remove-members-spec.js --- a/lib/shared/dm-ops/remove-members-spec.js +++ b/lib/shared/dm-ops/remove-members-spec.js @@ -12,28 +12,43 @@ import { threadTypes } from '../../types/thread-types-enum.js'; import { updateTypes } from '../../types/update-types-enum.js'; import type { ClientUpdateInfo } from '../../types/update-types.js'; +import { rawMessageInfoFromMessageData } from '../message-utils.js'; + +function createMessageDataFromDMOperation( + dmOperation: DMRemoveMembersOperation, +) { + const { editorID, time, threadID, removedUserIDs } = dmOperation; + return { + type: messageTypes.REMOVE_MEMBERS, + threadID, + time, + creatorID: editorID, + removedUserIDs: [...removedUserIDs], + }; +} const removeMembersSpec: DMOperationSpec = Object.freeze({ + notificationsCreationData: async ( + dmOperation: DMRemoveMembersOperation, + ) => { + const messageData = createMessageDataFromDMOperation(dmOperation); + return { messageDatas: [messageData] }; + }, processDMOperation: async ( dmOperation: DMRemoveMembersOperation, viewerID: string, utilities: ProcessDMOperationUtilities, ) => { - const { editorID, time, messageID, threadID, removedUserIDs } = - dmOperation; + const { time, messageID, threadID, removedUserIDs } = dmOperation; const threadInfo = utilities.threadInfos[threadID]; invariant(threadInfo.thick, 'Thread should be thick'); - const removeMembersMessage = { - type: messageTypes.REMOVE_MEMBERS, - id: messageID, - threadID, - time, - creatorID: editorID, - removedUserIDs: [...removedUserIDs], - }; + const messageData = createMessageDataFromDMOperation(dmOperation); + const rawMessageInfos = [ + rawMessageInfoFromMessageData(messageData, messageID), + ]; const removedUserIDsSet = new Set(removedUserIDs); const viewerIsRemoved = removedUserIDsSet.has(viewerID); @@ -65,7 +80,7 @@ }); } return { - rawMessageInfos: [removeMembersMessage], + rawMessageInfos, updateInfos, }; }, diff --git a/lib/shared/dm-ops/send-edit-message-spec.js b/lib/shared/dm-ops/send-edit-message-spec.js --- a/lib/shared/dm-ops/send-edit-message-spec.js +++ b/lib/shared/dm-ops/send-edit-message-spec.js @@ -6,24 +6,39 @@ } from './dm-op-spec.js'; import type { DMSendEditMessageOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; +import { rawMessageInfoFromMessageData } from '../message-utils.js'; + +function createMessageDataFromDMOperation( + dmOperation: DMSendEditMessageOperation, +) { + const { threadID, creatorID, time, targetMessageID, text } = dmOperation; + return { + type: messageTypes.EDIT_MESSAGE, + threadID, + creatorID, + time, + targetMessageID, + text, + }; +} const sendEditMessageSpec: DMOperationSpec = Object.freeze({ + notificationsCreationData: async ( + dmOperation: DMSendEditMessageOperation, + ) => { + const messageData = createMessageDataFromDMOperation(dmOperation); + return { messageDatas: [messageData] }; + }, processDMOperation: async (dmOperation: DMSendEditMessageOperation) => { - const { threadID, creatorID, time, messageID, targetMessageID, text } = - dmOperation; - const editMessage = { - type: messageTypes.EDIT_MESSAGE, - id: messageID, - threadID, - creatorID, - time, - targetMessageID, - text, - }; + const { messageID } = dmOperation; + const messageData = createMessageDataFromDMOperation(dmOperation); + const rawMessageInfos = [ + rawMessageInfoFromMessageData(messageData, messageID), + ]; return { - rawMessageInfos: [editMessage], + rawMessageInfos, updateInfos: [], }; }, diff --git a/lib/shared/dm-ops/send-reaction-message-spec.js b/lib/shared/dm-ops/send-reaction-message-spec.js --- a/lib/shared/dm-ops/send-reaction-message-spec.js +++ b/lib/shared/dm-ops/send-reaction-message-spec.js @@ -6,32 +6,41 @@ } from './dm-op-spec.js'; import type { DMSendReactionMessageOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; +import { rawMessageInfoFromMessageData } from '../message-utils.js'; + +function createMessageDataFromDMOperation( + dmOperation: DMSendReactionMessageOperation, +) { + const { threadID, creatorID, time, targetMessageID, reaction, action } = + dmOperation; + return { + type: messageTypes.REACTION, + threadID, + creatorID, + time, + targetMessageID, + reaction, + action, + }; +} const sendReactionMessageSpec: DMOperationSpec = Object.freeze({ + notificationsCreationData: async ( + dmOperation: DMSendReactionMessageOperation, + ) => { + const messageData = createMessageDataFromDMOperation(dmOperation); + return { messageDatas: [messageData] }; + }, processDMOperation: async (dmOperation: DMSendReactionMessageOperation) => { - const { - threadID, - creatorID, - time, - messageID, - targetMessageID, - reaction, - action, - } = dmOperation; - const reactionMessage = { - type: messageTypes.REACTION, - id: messageID, - threadID, - creatorID, - time, - targetMessageID, - reaction, - action, - }; + const { messageID } = dmOperation; + const messageData = createMessageDataFromDMOperation(dmOperation); + const rawMessageInfos = [ + rawMessageInfoFromMessageData(messageData, messageID), + ]; return { - rawMessageInfos: [reactionMessage], + rawMessageInfos, updateInfos: [], }; }, diff --git a/lib/shared/dm-ops/send-text-message-spec.js b/lib/shared/dm-ops/send-text-message-spec.js --- a/lib/shared/dm-ops/send-text-message-spec.js +++ b/lib/shared/dm-ops/send-text-message-spec.js @@ -7,22 +7,38 @@ import type { DMSendTextMessageOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; import type { ClientUpdateInfo } from '../../types/update-types.js'; +import { rawMessageInfoFromMessageData } from '../message-utils.js'; + +function createMessageDataFromDMOperation( + dmOperation: DMSendTextMessageOperation, +) { + const { threadID, creatorID, time, text } = dmOperation; + return { + type: messageTypes.TEXT, + threadID, + creatorID, + time, + text, + }; +} const sendTextMessageSpec: DMOperationSpec = Object.freeze({ + notificationsCreationData: async ( + dmOperation: DMSendTextMessageOperation, + ) => { + const messageData = createMessageDataFromDMOperation(dmOperation); + return { messageDatas: [messageData] }; + }, processDMOperation: async (dmOperation: DMSendTextMessageOperation) => { - const { threadID, creatorID, time, messageID, text } = dmOperation; - const textMessage = { - type: messageTypes.TEXT, - id: messageID, - threadID, - creatorID, - time, - text, - }; + const { messageID } = dmOperation; + const messageData = createMessageDataFromDMOperation(dmOperation); + const rawMessageInfos = [ + rawMessageInfoFromMessageData(messageData, messageID), + ]; const updateInfos: Array = []; return { - rawMessageInfos: [textMessage], + rawMessageInfos, updateInfos, }; }, diff --git a/lib/types/dm-ops.js b/lib/types/dm-ops.js --- a/lib/types/dm-ops.js +++ b/lib/types/dm-ops.js @@ -263,18 +263,25 @@ removedUserIDs: t.list(tUserID), }); +export type DMThreadSettingsChangesBase = { + +name?: string, + +description?: string, + +color?: string, + +avatar?: ClientAvatar, +}; + +type DMThreadSettingsChanges = $ReadOnly<{ + ...DMThreadSettingsChangesBase, + +newMemberIDs?: $ReadOnlyArray, +}>; + type DMChangeThreadSettingsBase = { +editorID: string, +time: number, - +changes: { - +name?: string, - +description?: string, - +color?: string, - +newMemberIDs?: $ReadOnlyArray, - +avatar?: ClientAvatar, - }, + +changes: DMThreadSettingsChanges, +messageIDsPrefix: string, }; + const dmChangeThreadSettingsBaseValidatorShape: TStructProps = { editorID: tUserID,