Page MenuHomePhabricator

D12658.id42138.diff
No OneTemporary

D12658.id42138.diff

diff --git a/lib/shared/dm-ops/create-sidebar-spec.js b/lib/shared/dm-ops/create-sidebar-spec.js
new file mode 100644
--- /dev/null
+++ b/lib/shared/dm-ops/create-sidebar-spec.js
@@ -0,0 +1,106 @@
+// @flow
+
+import uuid from 'uuid';
+
+import { createThickRawThreadInfo } from './create-thread-spec.js';
+import type {
+ DMOperationSpec,
+ ProcessDMOperationUtilities,
+} from './dm-op-spec.js';
+import { isInvalidSidebarSource } from '../../shared/message-utils.js';
+import type { DMCreateSidebarOperation } from '../../types/dm-ops.js';
+import { messageTypes } from '../../types/message-types-enum.js';
+import {
+ type RawMessageInfo,
+ messageTruncationStatus,
+} from '../../types/message-types.js';
+import { threadTypes } from '../../types/thread-types-enum.js';
+import { updateTypes } from '../../types/update-types-enum.js';
+
+export const createSidebarSpec: DMOperationSpec<DMCreateSidebarOperation> =
+ Object.freeze({
+ processDMOperation: async (
+ dmOperation: DMCreateSidebarOperation,
+ viewerID: string,
+ utilities: ProcessDMOperationUtilities,
+ ) => {
+ const {
+ threadID,
+ creatorID,
+ time,
+ parentThreadID,
+ memberIDs,
+ sourceMessageID,
+ roleID,
+ newSidebarSourceMessageID,
+ newCreateSidebarMessageID,
+ } = dmOperation;
+ const allMemberIDs = [creatorID, ...memberIDs];
+
+ const rawThreadInfo = createThickRawThreadInfo({
+ threadID,
+ threadType: threadTypes.THICK_SIDEBAR,
+ creationTime: time,
+ parentThreadID,
+ allMemberIDs,
+ roleID,
+ creatorID,
+ viewerID,
+ });
+
+ rawThreadInfo.sourceMessageID = sourceMessageID;
+ rawThreadInfo.containingThreadID = parentThreadID;
+
+ 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 rawMessageInfos: Array<RawMessageInfo> = [
+ {
+ 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,
+ },
+ },
+ ];
+
+ const threadJoinUpdateInfo = {
+ type: updateTypes.JOIN_THREAD,
+ id: uuid.v4(),
+ time,
+ threadInfo: rawThreadInfo,
+ rawMessageInfos,
+ truncationStatus: messageTruncationStatus.UNCHANGED,
+ rawEntryInfos: [],
+ };
+
+ return {
+ rawMessageInfos: [], // included in updateInfos below
+ updateInfos: [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
@@ -1,14 +1,160 @@
// @flow
+import uuid from 'uuid';
+
import type { DMOperationSpec } from './dm-op-spec.js';
+import { specialRoles } from '../../permissions/special-roles.js';
+import {
+ getAllThreadPermissions,
+ makePermissionsBlob,
+ getThickThreadRolePermissionsBlob,
+} from '../../permissions/thread-permissions.js';
+import { generatePendingThreadColor } from '../../shared/color-utils.js';
import type { DMCreateThreadOperation } from '../../types/dm-ops.js';
+import { messageTypes } from '../../types/message-types-enum.js';
+import {
+ type RawMessageInfo,
+ messageTruncationStatus,
+} from '../../types/message-types.js';
+import {
+ type ThickRawThreadInfo,
+ type RoleInfo,
+ minimallyEncodeMemberInfo,
+ minimallyEncodeRoleInfo,
+ minimallyEncodeThreadCurrentUserInfo,
+} from '../../types/minimally-encoded-thread-permissions-types.js';
+import { defaultThreadSubscription } from '../../types/subscription-types.js';
+import type { ThickThreadType } from '../../types/thread-types-enum.js';
+import type { ThickMemberInfo } from '../../types/thread-types.js';
+import { updateTypes } from '../../types/update-types-enum.js';
+
+type CreateThickRawThreadInfoInput = {
+ +threadID: string,
+ +threadType: ThickThreadType,
+ +creationTime: number,
+ +parentThreadID?: ?string,
+ +allMemberIDs: $ReadOnlyArray<string>,
+ +roleID: string,
+ +creatorID: string,
+ +viewerID: string,
+};
+type MutableThickRawThreadInfo = { ...ThickRawThreadInfo };
+export function createThickRawThreadInfo(
+ input: CreateThickRawThreadInfoInput,
+): MutableThickRawThreadInfo {
+ const {
+ threadID,
+ threadType,
+ creationTime,
+ parentThreadID,
+ allMemberIDs,
+ roleID,
+ creatorID,
+ viewerID,
+ } = input;
+
+ const color = generatePendingThreadColor(allMemberIDs);
+
+ const rolePermissions = getThickThreadRolePermissionsBlob(threadType);
+ const membershipPermissions = getAllThreadPermissions(
+ makePermissionsBlob(rolePermissions, null, threadID, threadType),
+ threadID,
+ );
+ const role: RoleInfo = {
+ ...minimallyEncodeRoleInfo({
+ id: roleID,
+ name: 'Members',
+ permissions: rolePermissions,
+ isDefault: true,
+ }),
+ specialRole: specialRoles.DEFAULT_ROLE,
+ };
+
+ return {
+ thick: true,
+ minimallyEncoded: true,
+ id: threadID,
+ type: threadType,
+ color,
+ creationTime,
+ parentThreadID,
+ members: allMemberIDs.map(memberID =>
+ minimallyEncodeMemberInfo<ThickMemberInfo>({
+ id: memberID,
+ role: role.id,
+ permissions: membershipPermissions,
+ isSender: memberID === viewerID,
+ subscription: defaultThreadSubscription,
+ }),
+ ),
+ roles: {
+ [role.id]: role,
+ },
+ currentUser: minimallyEncodeThreadCurrentUserInfo({
+ role: role.id,
+ permissions: membershipPermissions,
+ subscription: defaultThreadSubscription,
+ unread: creatorID !== viewerID,
+ }),
+ repliesCount: 0,
+ };
+}
export const createThreadSpec: DMOperationSpec<DMCreateThreadOperation> =
Object.freeze({
- processDMOperation: async () => {
+ processDMOperation: async (
+ dmOperation: DMCreateThreadOperation,
+ viewerID: string,
+ ) => {
+ const {
+ threadID,
+ creatorID,
+ time,
+ threadType,
+ memberIDs,
+ roleID,
+ newMessageID,
+ } = dmOperation;
+ const allMemberIDs = [creatorID, ...memberIDs];
+
+ const rawThreadInfo = createThickRawThreadInfo({
+ threadID,
+ threadType,
+ creationTime: time,
+ allMemberIDs,
+ roleID,
+ creatorID,
+ viewerID,
+ });
+
+ const rawMessageInfos: Array<RawMessageInfo> = [
+ {
+ type: messageTypes.CREATE_THREAD,
+ id: newMessageID,
+ threadID,
+ creatorID,
+ time,
+ initialThreadState: {
+ type: threadType,
+ color: rawThreadInfo.color,
+ memberIDs: allMemberIDs,
+ },
+ },
+ ];
+
+ const threadJoinUpdateInfo = {
+ type: updateTypes.JOIN_THREAD,
+ id: uuid.v4(),
+ time,
+ threadInfo: rawThreadInfo,
+ rawMessageInfos,
+ truncationStatus: messageTruncationStatus.UNCHANGED,
+ rawEntryInfos: [],
+ };
+
return {
- rawMessageInfos: [],
- updateInfos: [],
+ rawMessageInfos: [], // included in updateInfos below
+ updateInfos: [threadJoinUpdateInfo],
};
},
});
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,5 +1,6 @@
// @flow
+import { createSidebarSpec } from './create-sidebar-spec.js';
import { createThreadSpec } from './create-thread-spec.js';
import type { DMOperationSpec } from './dm-op-spec.js';
import { sendTextMessageSpec } from './send-text-message-spec.js';
@@ -9,5 +10,6 @@
+[DMOperationType]: DMOperationSpec<any>,
} = Object.freeze({
[dmOperationTypes.CREATE_THREAD]: createThreadSpec,
+ [dmOperationTypes.CREATE_SIDEBAR]: createSidebarSpec,
[dmOperationTypes.SEND_TEXT_MESSAGE]: sendTextMessageSpec,
});
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
@@ -4,13 +4,17 @@
import t from 'tcomb';
import type { RawMessageInfo } from './message-types.js';
-import { type ThickThreadType, thickThreadTypes } from './thread-types-enum.js';
+import {
+ type NonSidebarThickThreadType,
+ nonSidebarThickThreadTypes,
+} from './thread-types-enum.js';
import type { ClientUpdateInfo } from './update-types.js';
import { values } from '../utils/objects.js';
import { tShape, tString, tUserID } from '../utils/validation-utils.js';
export const dmOperationTypes = Object.freeze({
CREATE_THREAD: 'create_thread',
+ CREATE_SIDEBAR: 'create_sidebar',
SEND_TEXT_MESSAGE: 'send_text_message',
});
export type DMOperationType = $Values<typeof dmOperationTypes>;
@@ -20,10 +24,10 @@
+threadID: string,
+creatorID: string,
+time: number,
- +threadType: ThickThreadType,
- +parentThreadID?: ?string,
+ +threadType: NonSidebarThickThreadType,
+memberIDs: $ReadOnlyArray<string>,
- +sourceMessageID?: ?string,
+ +roleID: string,
+ +newMessageID: string,
};
export const dmCreateThreadOperationValidator: TInterface<DMCreateThreadOperation> =
tShape<DMCreateThreadOperation>({
@@ -31,10 +35,36 @@
threadID: t.String,
creatorID: tUserID,
time: t.Number,
- threadType: t.enums.of(values(thickThreadTypes)),
- parentThreadID: t.maybe(t.String),
+ threadType: t.enums.of(values(nonSidebarThickThreadTypes)),
memberIDs: t.list(tUserID),
- sourceMessageID: t.maybe(t.String),
+ roleID: t.String,
+ newMessageID: t.String,
+ });
+
+export type DMCreateSidebarOperation = {
+ +type: 'create_sidebar',
+ +threadID: string,
+ +creatorID: string,
+ +time: number,
+ +parentThreadID: string,
+ +memberIDs: $ReadOnlyArray<string>,
+ +sourceMessageID: string,
+ +roleID: string,
+ +newSidebarSourceMessageID: string,
+ +newCreateSidebarMessageID: string,
+};
+export const dmCreateSidebarOperationValidator: TInterface<DMCreateSidebarOperation> =
+ tShape<DMCreateSidebarOperation>({
+ type: tString(dmOperationTypes.CREATE_SIDEBAR),
+ threadID: t.String,
+ creatorID: tUserID,
+ time: t.Number,
+ parentThreadID: t.String,
+ memberIDs: t.list(tUserID),
+ sourceMessageID: t.String,
+ roleID: t.String,
+ newSidebarSourceMessageID: t.String,
+ newCreateSidebarMessageID: t.String,
});
export type DMSendTextMessageOperation = {
@@ -55,7 +85,10 @@
text: t.String,
});
-export type DMOperation = DMCreateThreadOperation | DMSendTextMessageOperation;
+export type DMOperation =
+ | DMCreateThreadOperation
+ | DMCreateSidebarOperation
+ | DMSendTextMessageOperation;
export type DMOperationResult = {
rawMessageInfos: Array<RawMessageInfo>,
diff --git a/lib/types/thread-types-enum.js b/lib/types/thread-types-enum.js
--- a/lib/types/thread-types-enum.js
+++ b/lib/types/thread-types-enum.js
@@ -38,7 +38,7 @@
});
export type ThinThreadType = $Values<typeof thinThreadTypes>;
-export const thickThreadTypes = Object.freeze({
+export const nonSidebarThickThreadTypes = Object.freeze({
// local "thick" thread (outside of community). no parent, can only have
// sidebar children
LOCAL: 13,
@@ -46,11 +46,25 @@
PERSONAL: 14,
// canonical thread for each single user
PRIVATE: 15,
+});
+export type NonSidebarThickThreadType = $Values<
+ typeof nonSidebarThickThreadTypes,
+>;
+
+export const sidebarThickThreadTypes = Object.freeze({
// has parent, not top-level (appears under parent in inbox), and visible to
// all members of parent
THICK_SIDEBAR: 16,
});
-export type ThickThreadType = $Values<typeof thickThreadTypes>;
+export type SidebarThickThreadType = $Values<typeof sidebarThickThreadTypes>;
+
+export const thickThreadTypes = Object.freeze({
+ ...nonSidebarThickThreadTypes,
+ ...sidebarThickThreadTypes,
+});
+export type ThickThreadType =
+ | NonSidebarThickThreadType
+ | SidebarThickThreadType;
export type ThreadType = ThinThreadType | ThickThreadType;

File Metadata

Mime Type
text/plain
Expires
Sun, Nov 24, 5:11 AM (20 h, 26 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2573592
Default Alt Text
D12658.id42138.diff (12 KB)

Event Timeline