Page MenuHomePhabricator

D13132.id43797.diff
No OneTemporary

D13132.id43797.diff

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
@@ -9,6 +9,7 @@
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 { joinThreadSubscription } from '../../types/subscription-types.js';
import { updateTypes } from '../../types/update-types-enum.js';
import { rawMessageInfoFromMessageData } from '../message-utils.js';
@@ -40,7 +41,13 @@
const resultThreadInfo = createThickRawThreadInfo(
{
...existingThreadDetails,
- allMemberIDs: [...existingThreadDetails.allMemberIDs, ...addedUserIDs],
+ allMemberIDsWithSubscriptions: [
+ ...existingThreadDetails.allMemberIDsWithSubscriptions,
+ ...addedUserIDs.map(id => ({
+ id,
+ subscription: joinThreadSubscription,
+ })),
+ ],
},
viewerID,
);
diff --git a/lib/shared/dm-ops/change-thread-subscription.js b/lib/shared/dm-ops/change-thread-subscription.js
new file mode 100644
--- /dev/null
+++ b/lib/shared/dm-ops/change-thread-subscription.js
@@ -0,0 +1,80 @@
+// @flow
+
+import invariant from 'invariant';
+import uuid from 'uuid';
+
+import type {
+ ProcessDMOperationUtilities,
+ DMOperationSpec,
+} from './dm-op-spec.js';
+import type { DMChangeThreadSubscriptionOperation } from '../../types/dm-ops.js';
+import { updateTypes } from '../../types/update-types-enum.js';
+import type { ClientUpdateInfo } from '../../types/update-types.js';
+
+const changeThreadSubscriptionSpec: DMOperationSpec<DMChangeThreadSubscriptionOperation> =
+ Object.freeze({
+ processDMOperation: async (
+ dmOperation: DMChangeThreadSubscriptionOperation,
+ viewerID: string,
+ utilities: ProcessDMOperationUtilities,
+ ) => {
+ const { creatorID, threadID, subscription, time } = dmOperation;
+
+ const threadInfo = utilities.threadInfos[threadID];
+ invariant(threadInfo.thick, 'Thread should be thick');
+
+ const creatorMemberInfo = threadInfo.members.find(
+ member => member.id === creatorID,
+ );
+ invariant(creatorMemberInfo, 'operation creator missing in thread');
+ const updatedCreatorMemberInfo = {
+ ...creatorMemberInfo,
+ subscription,
+ };
+ const otherMemberInfos = threadInfo.members.filter(
+ member => member.id !== creatorID,
+ );
+ const membersUpdate = [...otherMemberInfos, updatedCreatorMemberInfo];
+
+ const threadInfoUpdate = {
+ ...threadInfo,
+ members: membersUpdate,
+ };
+ const updateInfos: Array<ClientUpdateInfo> = [
+ {
+ type: updateTypes.UPDATE_THREAD,
+ id: uuid.v4(),
+ time,
+ threadInfo: threadInfoUpdate,
+ },
+ ];
+
+ return { updateInfos, rawMessageInfos: [] };
+ },
+ canBeProcessed(
+ dmOperation: DMChangeThreadSubscriptionOperation,
+ viewerID: string,
+ utilities: ProcessDMOperationUtilities,
+ ) {
+ const { threadID, creatorID } = dmOperation;
+ if (!utilities.threadInfos[threadID]) {
+ return {
+ isProcessingPossible: false,
+ reason: { type: 'missing_thread', threadID },
+ };
+ }
+
+ if (
+ !utilities.threadInfos[threadID].members.find(
+ memberInfo => memberInfo.id === creatorID,
+ )
+ ) {
+ return { isProcessingPossible: false, reason: { type: 'invalid' } };
+ }
+
+ return { isProcessingPossible: true };
+ },
+ supportsAutoRetry: true,
+ });
+
+export { changeThreadSubscriptionSpec };
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
@@ -13,6 +13,7 @@
type RawMessageInfo,
messageTruncationStatus,
} from '../../types/message-types.js';
+import { joinThreadSubscription } from '../../types/subscription-types.js';
import { threadTypes } from '../../types/thread-types-enum.js';
import { updateTypes } from '../../types/update-types-enum.js';
import { generatePendingThreadColor } from '../color-utils.js';
@@ -107,6 +108,10 @@
newCreateSidebarMessageID,
} = dmOperation;
const allMemberIDs = [creatorID, ...memberIDs];
+ const allMemberIDsWithSubscriptions = allMemberIDs.map(id => ({
+ id,
+ subscription: joinThreadSubscription,
+ }));
const rawThreadInfo = createThickRawThreadInfo(
{
@@ -114,7 +119,7 @@
threadType: threadTypes.THICK_SIDEBAR,
creationTime: time,
parentThreadID,
- allMemberIDs,
+ allMemberIDsWithSubscriptions,
roleID,
unread: creatorID !== viewerID,
sourceMessageID,
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
@@ -65,7 +65,7 @@
threadType,
creationTime,
parentThreadID,
- allMemberIDs,
+ allMemberIDsWithSubscriptions,
roleID,
unread,
name,
@@ -78,7 +78,11 @@
pinnedCount,
} = input;
- const threadColor = color ?? generatePendingThreadColor(allMemberIDs);
+ const threadColor =
+ color ??
+ generatePendingThreadColor(
+ allMemberIDsWithSubscriptions.map(({ id }) => id),
+ );
const { membershipPermissions, role } =
createRoleAndPermissionForThickThreads(threadType, threadID, roleID);
@@ -91,14 +95,15 @@
color: threadColor,
creationTime,
parentThreadID,
- members: allMemberIDs.map(memberID =>
- minimallyEncodeMemberInfo<ThickMemberInfo>({
- id: memberID,
- role: role.id,
- permissions: membershipPermissions,
- isSender: memberID === viewerID,
- subscription: joinThreadSubscription,
- }),
+ members: allMemberIDsWithSubscriptions.map(
+ ({ id: memberID, subscription }) =>
+ minimallyEncodeMemberInfo<ThickMemberInfo>({
+ id: memberID,
+ role: role.id,
+ permissions: membershipPermissions,
+ isSender: memberID === viewerID,
+ subscription,
+ }),
),
roles: {
[role.id]: role,
@@ -163,13 +168,17 @@
newMessageID,
} = dmOperation;
const allMemberIDs = [creatorID, ...memberIDs];
+ const allMemberIDsWithSubscriptions = allMemberIDs.map(id => ({
+ id,
+ subscription: joinThreadSubscription,
+ }));
const rawThreadInfo = createThickRawThreadInfo(
{
threadID,
threadType,
creationTime: time,
- allMemberIDs,
+ allMemberIDsWithSubscriptions,
roleID,
unread: creatorID !== viewerID,
},
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
@@ -3,6 +3,7 @@
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 { changeThreadSubscriptionSpec } from './change-thread-subscription.js';
import { createSidebarSpec } from './create-sidebar-spec.js';
import { createThreadSpec } from './create-thread-spec.js';
import type { DMOperationSpec } from './dm-op-spec.js';
@@ -28,4 +29,5 @@
[dmOperationTypes.LEAVE_THREAD]: leaveThreadSpec,
[dmOperationTypes.REMOVE_MEMBERS]: removeMembersSpec,
[dmOperationTypes.CHANGE_THREAD_SETTINGS]: changeThreadSettingsSpec,
+ [dmOperationTypes.CHANGE_THREAD_SUBSCRIPTION]: changeThreadSubscriptionSpec,
});
diff --git a/lib/shared/dm-ops/dm-op-utils.js b/lib/shared/dm-ops/dm-op-utils.js
--- a/lib/shared/dm-ops/dm-op-utils.js
+++ b/lib/shared/dm-ops/dm-op-utils.js
@@ -12,7 +12,10 @@
DMAddViewerToThreadMembersOperation,
DMOperation,
} from '../../types/dm-ops.js';
-import type { ThreadInfo } from '../../types/minimally-encoded-thread-permissions-types.js';
+import type {
+ ThickRawThreadInfo,
+ ThreadInfo,
+} from '../../types/minimally-encoded-thread-permissions-types.js';
import type { InboundActionMetadata } from '../../types/redux-types.js';
import {
outboundP2PMessageStatuses,
@@ -130,7 +133,7 @@
}
function getCreateThickRawThreadInfoInputFromThreadInfo(
- threadInfo: ThreadInfo,
+ threadInfo: ThickRawThreadInfo,
): CreateThickRawThreadInfoInput {
const roleID = Object.keys(threadInfo.roles).pop();
const thickThreadType = assertThickThreadType(threadInfo.type);
@@ -139,7 +142,12 @@
threadType: thickThreadType,
creationTime: threadInfo.creationTime,
parentThreadID: threadInfo.parentThreadID,
- allMemberIDs: threadInfo.members.map(member => member.id),
+ allMemberIDsWithSubscriptions: threadInfo.members.map(
+ ({ id, subscription }) => ({
+ id,
+ subscription,
+ }),
+ ),
roleID,
unread: !!threadInfo.currentUser.unread,
name: threadInfo.name,
@@ -165,8 +173,10 @@
return React.useCallback(
async (newMemberIDs: $ReadOnlyArray<string>, threadInfo: ThreadInfo) => {
+ const rawThreadInfo = threadInfos[threadInfo.id];
+ invariant(rawThreadInfo.thick, 'thread should be thick');
const existingThreadDetails =
- getCreateThickRawThreadInfoInputFromThreadInfo(threadInfo);
+ getCreateThickRawThreadInfoInputFromThreadInfo(rawThreadInfo);
invariant(viewerID, 'viewerID should be set');
const addViewerToThreadMembersOperation: DMAddViewerToThreadMembersOperation =
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
@@ -69,7 +69,10 @@
const newThreadInfo = createThickRawThreadInfo(
{
...existingThreadDetails,
- allMemberIDs: [...existingThreadDetails.allMemberIDs, joinerID],
+ allMemberIDsWithSubscriptions: [
+ ...existingThreadDetails.allMemberIDsWithSubscriptions,
+ { id: joinerID, subscription: joinThreadSubscription },
+ ],
},
viewerID,
);
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
@@ -6,6 +6,10 @@
import type { RawMessageInfo } from './message-types.js';
import type { NotificationsCreationData } from './notif-types.js';
import type { OutboundP2PMessage } from './sqlite-types.js';
+import {
+ type ThreadSubscription,
+ threadSubscriptionValidator,
+} from './subscription-types.js';
import {
type NonSidebarThickThreadType,
nonSidebarThickThreadTypes,
@@ -28,15 +32,26 @@
LEAVE_THREAD: 'leave_thread',
REMOVE_MEMBERS: 'remove_members',
CHANGE_THREAD_SETTINGS: 'change_thread_settings',
+ CHANGE_THREAD_SUBSCRIPTION: 'change_thread_subscription',
});
export type DMOperationType = $Values<typeof dmOperationTypes>;
+type MemberIDWithSubscription = {
+ +id: string,
+ +subscription: ThreadSubscription,
+};
+export const memberIDWithSubscriptionValidator: TInterface<MemberIDWithSubscription> =
+ tShape<MemberIDWithSubscription>({
+ id: tUserID,
+ subscription: threadSubscriptionValidator,
+ });
+
export type CreateThickRawThreadInfoInput = {
+threadID: string,
+threadType: ThickThreadType,
+creationTime: number,
+parentThreadID?: ?string,
- +allMemberIDs: $ReadOnlyArray<string>,
+ +allMemberIDsWithSubscriptions: $ReadOnlyArray<MemberIDWithSubscription>,
+roleID: string,
+unread: boolean,
+name?: ?string,
@@ -54,7 +69,7 @@
threadType: thickThreadTypeValidator,
creationTime: t.Number,
parentThreadID: t.maybe(t.String),
- allMemberIDs: t.list(tUserID),
+ allMemberIDsWithSubscriptions: t.list(memberIDWithSubscriptionValidator),
roleID: t.String,
unread: t.Boolean,
name: t.maybe(t.String),
@@ -292,6 +307,22 @@
messageIDsPrefix: t.String,
});
+export type DMChangeThreadSubscriptionOperation = {
+ +type: 'change_thread_subscription',
+ +time: number,
+ +threadID: string,
+ +creatorID: string,
+ +subscription: ThreadSubscription,
+};
+export const dmChangeThreadSubscriptionOperationValidator: TInterface<DMChangeThreadSubscriptionOperation> =
+ tShape<DMChangeThreadSubscriptionOperation>({
+ type: tString(dmOperationTypes.CHANGE_THREAD_SUBSCRIPTION),
+ time: t.Number,
+ threadID: t.String,
+ creatorID: tUserID,
+ subscription: threadSubscriptionValidator,
+ });
+
export type DMOperation =
| DMCreateThreadOperation
| DMCreateSidebarOperation
@@ -303,7 +334,8 @@
| DMJoinThreadOperation
| DMLeaveThreadOperation
| DMRemoveMembersOperation
- | DMChangeThreadSettingsOperation;
+ | DMChangeThreadSettingsOperation
+ | DMChangeThreadSubscriptionOperation;
export const dmOperationValidator: TUnion<DMOperation> = t.union([
dmCreateThreadOperationValidator,
dmCreateSidebarOperationValidator,
@@ -316,6 +348,7 @@
dmLeaveThreadOperationValidator,
dmRemoveMembersOperationValidator,
dmChangeThreadSettingsOperationValidator,
+ dmChangeThreadSubscriptionOperationValidator,
]);
export type DMOperationResult = {

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 27, 12:04 AM (14 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2586998
Default Alt Text
D13132.id43797.diff (13 KB)

Event Timeline