diff --git a/lib/shared/dm-ops/dm-op-specs.js b/lib/shared/dm-ops/dm-op-specs.js --- a/lib/shared/dm-ops/dm-op-specs.js +++ b/lib/shared/dm-ops/dm-op-specs.js @@ -5,6 +5,7 @@ import { createThreadSpec } from './create-thread-spec.js'; import type { DMOperationSpec } from './dm-op-spec.js'; import { joinThreadSpec } from './join-thread-spec.js'; +import { leaveThreadSpec } from './leave-thread-spec.js'; import { sendEditMessageSpec } from './send-edit-message-spec.js'; import { sendReactionMessageSpec } from './send-reaction-message-spec.js'; import { sendTextMessageSpec } from './send-text-message-spec.js'; @@ -20,4 +21,5 @@ [dmOperationTypes.SEND_EDIT_MESSAGE]: sendEditMessageSpec, [dmOperationTypes.ADD_MEMBERS]: addMembersSpec, [dmOperationTypes.JOIN_THREAD]: joinThreadSpec, + [dmOperationTypes.LEAVE_THREAD]: leaveThreadSpec, }); diff --git a/lib/shared/dm-ops/leave-thread-spec.js b/lib/shared/dm-ops/leave-thread-spec.js new file mode 100644 --- /dev/null +++ b/lib/shared/dm-ops/leave-thread-spec.js @@ -0,0 +1,76 @@ +// @flow + +import { uuid } from 'uuid'; + +import type { + DMOperationSpec, + ProcessDMOperationUtilities, +} from './dm-op-spec.js'; +import type { DMLeaveThreadOperation } from '../../types/dm-ops.js'; +import { messageTypes } from '../../types/message-types-enum.js'; +import type { ThickRawThreadInfo } from '../../types/minimally-encoded-thread-permissions-types.js'; +import { updateTypes } from '../../types/update-types-enum.js'; +import type { ClientUpdateInfo } from '../../types/update-types.js'; +import { userIsMember } from '../thread-utils.js'; + +const leaveThreadSpec: DMOperationSpec = Object.freeze({ + processDMOperation: async ( + dmOperation: DMLeaveThreadOperation, + viewerID: string, + utilities: ProcessDMOperationUtilities, + ) => { + const { editorID, time, messageID, threadID } = dmOperation; + + const threadInfoOptional = utilities.getThreadInfo(threadID); + if (!threadInfoOptional || !threadInfoOptional.thick) { + // We can't perform this operation now. It should be queued for later. + return { + rawMessageInfos: [], + updateInfos: [], + }; + } + const threadInfo: ThickRawThreadInfo = threadInfoOptional; + if (!userIsMember(threadInfo, editorID)) { + return { + rawMessageInfos: [], + updateInfos: [], + }; + } + + const leaveThreadMessage = { + type: messageTypes.LEAVE_THREAD, + id: messageID, + threadID, + creatorID: editorID, + time, + }; + + const updateInfos: Array = []; + if (viewerID === editorID) { + updateInfos.push({ + type: updateTypes.DELETE_THREAD, + id: uuid.v4(), + time, + threadID, + }); + } else { + const updatedThreadInfo = { + ...threadInfo, + members: threadInfo.members.filter(member => member.id !== editorID), + }; + updateInfos.push({ + type: updateTypes.UPDATE_THREAD, + id: uuid.v4(), + time, + threadInfo: updatedThreadInfo, + }); + } + + return { + rawMessageInfos: [leaveThreadMessage], + updateInfos, + }; + }, +}); + +export { leaveThreadSpec }; 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 @@ -29,6 +29,7 @@ SEND_EDIT_MESSAGE: 'send_edit_message', ADD_MEMBERS: 'add_members', JOIN_THREAD: 'join_thread', + LEAVE_THREAD: 'leave_thread', }); export type DMOperationType = $Values; @@ -186,6 +187,22 @@ rawEntryInfos: t.list(rawEntryInfoValidator), }); +export type DMLeaveThreadOperation = { + +type: 'leave_thread', + +editorID: string, + +time: number, + +messageID: string, + +threadID: string, +}; +export const dmLeaveThreadOperation: TInterface = + tShape({ + type: tString(dmOperationTypes.JOIN_THREAD), + editorID: tUserID, + time: t.Number, + messageID: t.String, + threadID: t.String, + }); + export type DMOperation = | DMCreateThreadOperation | DMCreateSidebarOperation @@ -193,7 +210,8 @@ | DMSendReactionMessageOperation | DMSendEditMessageOperation | DMAddMembersOperation - | DMJoinThreadOperation; + | DMJoinThreadOperation + | DMLeaveThreadOperation; export const dmOperationValidator: TUnion = t.union([ dmCreateThreadOperationValidator, dmCreateSidebarOperationValidator, @@ -202,6 +220,7 @@ dmSendEditMessageOperation, dmAddMembersOperation, dmJoinThreadOperation, + dmLeaveThreadOperation, ]); export type DMOperationResult = {