Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3351612
D12658.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
12 KB
Referenced Files
None
Subscribers
None
D12658.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 24, 2:47 AM (20 h, 46 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2573592
Default Alt Text
D12658.diff (12 KB)
Attached To
Mode
D12658: [lib] DMOperationSpec for CREATE_THREAD operation
Attached
Detach File
Event Timeline
Log In to Comment