Page MenuHomePhabricator

D13052.id43518.diff
No OneTemporary

D13052.id43518.diff

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
@@ -3,10 +3,7 @@
import invariant from 'invariant';
import uuid from 'uuid';
-import {
- createRoleAndPermissionForThickThreads,
- createThickRawThreadInfo,
-} from './create-thread-spec.js';
+import { createRoleAndPermissionForThickThreads } from './create-thread-spec.js';
import type {
DMOperationSpec,
ProcessDMOperationUtilities,
@@ -14,10 +11,7 @@
import { createRepliesCountUpdate } from './dm-op-utils.js';
import type { DMAddMembersOperation } from '../../types/dm-ops.js';
import { messageTypes } from '../../types/message-types-enum.js';
-import {
- messageTruncationStatus,
- type RawMessageInfo,
-} from '../../types/message-types.js';
+import { type RawMessageInfo } from '../../types/message-types.js';
import {
minimallyEncodeMemberInfo,
type ThickRawThreadInfo,
@@ -38,104 +32,62 @@
+updateInfos: Array<ClientUpdateInfo>,
+threadInfo: ?ThickRawThreadInfo,
} {
- const { editorID, time, messageID, addedUserIDs, existingThreadDetails } =
- dmOperation;
+ const { editorID, time, messageID, addedUserIDs, threadID } = dmOperation;
const addMembersMessage = {
type: messageTypes.ADD_MEMBERS,
id: messageID,
- threadID: existingThreadDetails.threadID,
+ threadID,
creatorID: editorID,
time,
addedUserIDs: [...addedUserIDs],
};
- const viewerIsAdded = addedUserIDs.includes(viewerID);
- const updateInfos: Array<ClientUpdateInfo> = [];
- const rawMessageInfos: Array<RawMessageInfo> = [];
- let resultThreadInfo: ?ThickRawThreadInfo;
- if (viewerIsAdded) {
- const newThread = createThickRawThreadInfo(
- {
- ...existingThreadDetails,
- allMemberIDs: [...existingThreadDetails.allMemberIDs, ...addedUserIDs],
- },
- viewerID,
- );
- resultThreadInfo = newThread;
- updateInfos.push({
- type: updateTypes.JOIN_THREAD,
- id: uuid.v4(),
- time,
- threadInfo: newThread,
- rawMessageInfos: [addMembersMessage],
- truncationStatus: messageTruncationStatus.EXHAUSTIVE,
- rawEntryInfos: [],
- });
- const repliesCountUpdate = createRepliesCountUpdate(newThread, [
- addMembersMessage,
- ]);
- if (
- repliesCountUpdate &&
- repliesCountUpdate.type === updateTypes.UPDATE_THREAD
- ) {
- updateInfos.push(repliesCountUpdate);
- resultThreadInfo.repliesCount =
- repliesCountUpdate.threadInfo.repliesCount;
- }
- } else {
- const currentThreadInfoOptional =
- utilities.threadInfos[existingThreadDetails.threadID];
- if (!currentThreadInfoOptional || !currentThreadInfoOptional.thick) {
- // We can't perform this operation now. It should be queued for later.
- return {
- rawMessageInfos: [],
- updateInfos: [],
- threadInfo: null,
- };
- }
- const currentThreadInfo: ThickRawThreadInfo = currentThreadInfoOptional;
- const defaultRoleID = values(currentThreadInfo.roles).find(role =>
- roleIsDefaultRole(role),
- )?.id;
- invariant(defaultRoleID, 'Default role ID must exist');
- const { membershipPermissions } = createRoleAndPermissionForThickThreads(
- currentThreadInfo.type,
- currentThreadInfo.id,
- defaultRoleID,
- );
- const newMembers = addedUserIDs
- .filter(userID => !userIsMember(currentThreadInfo, userID))
- .map(userID =>
- minimallyEncodeMemberInfo<ThickMemberInfo>({
- id: userID,
- role: defaultRoleID,
- permissions: membershipPermissions,
- isSender: editorID === viewerID,
- subscription: joinThreadSubscription,
- }),
- );
-
- const newThreadInfo = {
- ...currentThreadInfo,
- members: [...currentThreadInfo.members, ...newMembers],
+ const currentThreadInfo = utilities.threadInfos[threadID];
+ if (!currentThreadInfo.thick) {
+ return {
+ rawMessageInfos: [],
+ updateInfos: [],
+ threadInfo: null,
};
- resultThreadInfo = newThreadInfo;
- const updateWithRepliesCount = createRepliesCountUpdate(newThreadInfo, [
- addMembersMessage,
- ]);
- updateInfos.push(
- updateWithRepliesCount ?? {
- type: updateTypes.UPDATE_THREAD,
- id: uuid.v4(),
- time,
- threadInfo: newThreadInfo,
- },
- );
- rawMessageInfos.push(addMembersMessage);
}
+ const defaultRoleID = values(currentThreadInfo.roles).find(role =>
+ roleIsDefaultRole(role),
+ )?.id;
+ invariant(defaultRoleID, 'Default role ID must exist');
+ const { membershipPermissions } = createRoleAndPermissionForThickThreads(
+ currentThreadInfo.type,
+ currentThreadInfo.id,
+ defaultRoleID,
+ );
+ const newMembers = addedUserIDs
+ .filter(userID => !userIsMember(currentThreadInfo, userID))
+ .map(userID =>
+ minimallyEncodeMemberInfo<ThickMemberInfo>({
+ id: userID,
+ role: defaultRoleID,
+ permissions: membershipPermissions,
+ isSender: editorID === viewerID,
+ subscription: joinThreadSubscription,
+ }),
+ );
+
+ const resultThreadInfo = {
+ ...currentThreadInfo,
+ members: [...currentThreadInfo.members, ...newMembers],
+ };
+ const updateWithRepliesCount = createRepliesCountUpdate(resultThreadInfo, [
+ addMembersMessage,
+ ]);
+ const update = updateWithRepliesCount ?? {
+ type: updateTypes.UPDATE_THREAD,
+ id: uuid.v4(),
+ time,
+ threadInfo: resultThreadInfo,
+ };
+
return {
- rawMessageInfos,
- updateInfos,
+ rawMessageInfos: [addMembersMessage],
+ updateInfos: [update],
threadInfo: resultThreadInfo,
};
}
@@ -158,17 +110,14 @@
viewerID: string,
utilities: ProcessDMOperationUtilities,
) {
- if (
- utilities.threadInfos[dmOperation.existingThreadDetails.threadID] ||
- dmOperation.addedUserIDs.includes(viewerID)
- ) {
+ if (utilities.threadInfos[dmOperation.threadID]) {
return { isProcessingPossible: true };
}
return {
isProcessingPossible: false,
reason: {
type: 'missing_thread',
- threadID: dmOperation.existingThreadDetails.threadID,
+ threadID: dmOperation.threadID,
},
};
},
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
new file mode 100644
--- /dev/null
+++ b/lib/shared/dm-ops/add-viewer-to-thread-members-spec.js
@@ -0,0 +1,99 @@
+// @flow
+
+import uuid from 'uuid';
+
+import { createThickRawThreadInfo } from './create-thread-spec.js';
+import type { DMOperationSpec } from './dm-op-spec.js';
+import { createRepliesCountUpdate } from './dm-op-utils.js';
+import type { DMAddViewerToThreadMembersOperation } from '../../types/dm-ops.js';
+import { messageTypes } from '../../types/message-types-enum.js';
+import {
+ messageTruncationStatus,
+ type RawMessageInfo,
+} from '../../types/message-types.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';
+
+function createAddViewerToThreadMembersResults(
+ dmOperation: DMAddViewerToThreadMembersOperation,
+ viewerID: string,
+): {
+ +rawMessageInfos: Array<RawMessageInfo>,
+ +updateInfos: Array<ClientUpdateInfo>,
+ +threadInfo: ?ThickRawThreadInfo,
+} {
+ const { editorID, time, messageID, addedUserIDs, existingThreadDetails } =
+ dmOperation;
+ const addMembersMessage = {
+ type: messageTypes.ADD_MEMBERS,
+ id: messageID,
+ threadID: existingThreadDetails.threadID,
+ creatorID: editorID,
+ time,
+ addedUserIDs: [...addedUserIDs],
+ };
+
+ const updateInfos: Array<ClientUpdateInfo> = [];
+
+ const resultThreadInfo = createThickRawThreadInfo(
+ {
+ ...existingThreadDetails,
+ allMemberIDs: [...existingThreadDetails.allMemberIDs, ...addedUserIDs],
+ },
+ viewerID,
+ );
+ updateInfos.push({
+ type: updateTypes.JOIN_THREAD,
+ id: uuid.v4(),
+ time,
+ threadInfo: resultThreadInfo,
+ rawMessageInfos: [addMembersMessage],
+ truncationStatus: messageTruncationStatus.EXHAUSTIVE,
+ rawEntryInfos: [],
+ });
+ const repliesCountUpdate = createRepliesCountUpdate(resultThreadInfo, [
+ addMembersMessage,
+ ]);
+ if (
+ repliesCountUpdate &&
+ repliesCountUpdate.type === updateTypes.UPDATE_THREAD
+ ) {
+ updateInfos.push(repliesCountUpdate);
+ resultThreadInfo.repliesCount = repliesCountUpdate.threadInfo.repliesCount;
+ }
+ return {
+ rawMessageInfos: [],
+ updateInfos,
+ threadInfo: resultThreadInfo,
+ };
+}
+
+const addViewerToThreadMembersSpec: DMOperationSpec<DMAddViewerToThreadMembersOperation> =
+ Object.freeze({
+ processDMOperation: async (
+ dmOperation: DMAddViewerToThreadMembersOperation,
+ viewerID: string,
+ ) => {
+ const { rawMessageInfos, updateInfos } =
+ createAddViewerToThreadMembersResults(dmOperation, viewerID);
+ return { rawMessageInfos, updateInfos };
+ },
+ canBeProcessed(
+ dmOperation: DMAddViewerToThreadMembersOperation,
+ viewerID: string,
+ ) {
+ if (dmOperation.addedUserIDs.includes(viewerID)) {
+ return { isProcessingPossible: true };
+ }
+ console.log('Invalid DM operation', dmOperation);
+ return {
+ isProcessingPossible: false,
+ reason: {
+ type: 'invalid',
+ },
+ };
+ },
+ });
+
+export { addViewerToThreadMembersSpec, createAddViewerToThreadMembersResults };
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
@@ -3,10 +3,11 @@
import invariant from 'invariant';
import uuid from 'uuid';
+import { createAddNewMembersResults } from './add-members-spec.js';
import {
- addMembersSpec,
- createAddNewMembersResults,
-} from './add-members-spec.js';
+ addViewerToThreadMembersSpec,
+ createAddViewerToThreadMembersResults,
+} from './add-viewer-to-thread-members-spec.js';
import type {
DMOperationSpec,
ProcessDMOperationUtilities,
@@ -23,6 +24,7 @@
function createAddMembersOperation(
dmOperation: DMChangeThreadSettingsOperation,
+ viewerID: string,
) {
const { editorID, time, messageIDsPrefix, changes, existingThreadDetails } =
dmOperation;
@@ -30,16 +32,39 @@
changes.newMemberIDs && changes.newMemberIDs.length > 0
? [...new Set(changes.newMemberIDs)]
: [];
+ if (newMemberIDs.includes(viewerID)) {
+ return {
+ type: 'add_viewer_to_thread_members',
+ editorID,
+ time,
+ messageID: `${messageIDsPrefix}/add_members`,
+ addedUserIDs: newMemberIDs,
+ existingThreadDetails,
+ };
+ }
return {
type: 'add_members',
editorID,
time,
messageID: `${messageIDsPrefix}/add_members`,
addedUserIDs: newMemberIDs,
- existingThreadDetails,
+ threadID: existingThreadDetails.threadID,
};
}
+function processAddMembersOperation(
+ dmOperation: DMChangeThreadSettingsOperation,
+ viewerID: string,
+ utilities: ProcessDMOperationUtilities,
+) {
+ const operation = createAddMembersOperation(dmOperation, viewerID);
+ if (operation.type === 'add_viewer_to_thread_members') {
+ return createAddViewerToThreadMembersResults(operation, viewerID);
+ } else {
+ return createAddNewMembersResults(operation, viewerID, utilities);
+ }
+}
+
const changeThreadSettingsSpec: DMOperationSpec<DMChangeThreadSettingsOperation> =
Object.freeze({
processDMOperation: async (
@@ -63,9 +88,8 @@
const rawMessageInfos: Array<RawMessageInfo> = [];
if (changes.newMemberIDs && changes.newMemberIDs.length > 0) {
- const addMembersOperation = createAddMembersOperation(dmOperation);
- const addMembersResult = createAddNewMembersResults(
- addMembersOperation,
+ const addMembersResult = processAddMembersOperation(
+ dmOperation,
viewerID,
utilities,
);
@@ -150,11 +174,25 @@
viewerID: string,
utilities: ProcessDMOperationUtilities,
) {
- return addMembersSpec.canBeProcessed(
- createAddMembersOperation(dmOperation),
- viewerID,
- utilities,
- );
+ const operation = createAddMembersOperation(dmOperation, viewerID);
+ if (operation.type === 'add_viewer_to_thread_members') {
+ return addViewerToThreadMembersSpec.canBeProcessed(
+ operation,
+ viewerID,
+ utilities,
+ );
+ } else if (
+ utilities.threadInfos[dmOperation.existingThreadDetails.threadID]
+ ) {
+ return { isProcessingPossible: true };
+ }
+ return {
+ isProcessingPossible: false,
+ reason: {
+ type: 'missing_thread',
+ threadID: dmOperation.existingThreadDetails.threadID,
+ },
+ };
},
});
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
@@ -24,6 +24,8 @@
| { +isProcessingPossible: true }
| {
+isProcessingPossible: false,
- +reason: { +type: 'missing_thread', +threadID: string },
+ +reason:
+ | { +type: 'missing_thread', +threadID: string }
+ | { +type: 'invalid' },
},
};
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
@@ -1,6 +1,7 @@
// @flow
import { addMembersSpec } from './add-members-spec.js';
+import { addViewerToThreadMembersSpec } from './add-viewer-to-thread-members-spec.js';
import { changeThreadSettingsSpec } from './change-thread-settings-spec.js';
import { createSidebarSpec } from './create-sidebar-spec.js';
import { createThreadSpec } from './create-thread-spec.js';
@@ -22,6 +23,7 @@
[dmOperationTypes.SEND_REACTION_MESSAGE]: sendReactionMessageSpec,
[dmOperationTypes.SEND_EDIT_MESSAGE]: sendEditMessageSpec,
[dmOperationTypes.ADD_MEMBERS]: addMembersSpec,
+ [dmOperationTypes.ADD_VIEWER_TO_THREAD_MEMBERS]: addViewerToThreadMembersSpec,
[dmOperationTypes.JOIN_THREAD]: joinThreadSpec,
[dmOperationTypes.LEAVE_THREAD]: leaveThreadSpec,
[dmOperationTypes.REMOVE_MEMBERS]: removeMembersSpec,
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
@@ -22,6 +22,7 @@
SEND_REACTION_MESSAGE: 'send_reaction_message',
SEND_EDIT_MESSAGE: 'send_edit_message',
ADD_MEMBERS: 'add_members',
+ ADD_VIEWER_TO_THREAD_MEMBERS: 'add_viewer_to_thread_members',
JOIN_THREAD: 'join_thread',
LEAVE_THREAD: 'leave_thread',
REMOVE_MEMBERS: 'remove_members',
@@ -173,22 +174,41 @@
text: t.String,
});
-export type DMAddMembersOperation = {
- +type: 'add_members',
+type DMAddMembersBase = {
+editorID: string,
+time: number,
+messageID: string,
+addedUserIDs: $ReadOnlyArray<string>,
- +existingThreadDetails: CreateThickRawThreadInfoInput,
};
+const dmAddMembersBaseValidatorShape = {
+ editorID: tUserID,
+ time: t.Number,
+ messageID: t.String,
+ addedUserIDs: t.list(tUserID),
+};
+
+export type DMAddMembersOperation = $ReadOnly<{
+ +type: 'add_members',
+ +threadID: string,
+ ...DMAddMembersBase,
+}>;
export const dmAddMembersOperationValidator: TInterface<DMAddMembersOperation> =
tShape<DMAddMembersOperation>({
type: tString(dmOperationTypes.ADD_MEMBERS),
- editorID: tUserID,
- time: t.Number,
- messageID: t.String,
- addedUserIDs: t.list(tUserID),
+ threadID: t.String,
+ ...dmAddMembersBaseValidatorShape,
+ });
+
+export type DMAddViewerToThreadMembersOperation = $ReadOnly<{
+ +type: 'add_viewer_to_thread_members',
+ +existingThreadDetails: CreateThickRawThreadInfoInput,
+ ...DMAddMembersBase,
+}>;
+export const dmAddViewerToThreadMembersValidator: TInterface<DMAddViewerToThreadMembersOperation> =
+ tShape<DMAddViewerToThreadMembersOperation>({
+ type: tString(dmOperationTypes.ADD_VIEWER_TO_THREAD_MEMBERS),
existingThreadDetails: createThickRawThreadInfoInputValidator,
+ ...dmAddMembersBaseValidatorShape,
});
export type DMJoinThreadOperation = {
@@ -278,6 +298,7 @@
| DMSendReactionMessageOperation
| DMSendEditMessageOperation
| DMAddMembersOperation
+ | DMAddViewerToThreadMembersOperation
| DMJoinThreadOperation
| DMLeaveThreadOperation
| DMRemoveMembersOperation
@@ -289,6 +310,7 @@
dmSendReactionMessageOperationValidator,
dmSendEditMessageOperationValidator,
dmAddMembersOperationValidator,
+ dmAddViewerToThreadMembersValidator,
dmJoinThreadOperationValidator,
dmLeaveThreadOperationValidator,
dmRemoveMembersOperationValidator,

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 29, 1:25 PM (20 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2596898
Default Alt Text
D13052.id43518.diff (16 KB)

Event Timeline