diff --git a/lib/types/message-types.js b/lib/types/message-types.js --- a/lib/types/message-types.js +++ b/lib/types/message-types.js @@ -1,116 +1,139 @@ // @flow import invariant from 'invariant'; +import t, { type TUnion, type TInterface } from 'tcomb'; import { type ClientDBMediaInfo } from './media-types.js'; import { messageTypes, type MessageType } from './message-types-enum.js'; -import type { - AddMembersMessageData, - AddMembersMessageInfo, - RawAddMembersMessageInfo, +import { + type AddMembersMessageData, + type AddMembersMessageInfo, + type RawAddMembersMessageInfo, + rawAddMembersMessageInfoValidator, } from './messages/add-members.js'; -import type { - ChangeRoleMessageData, - ChangeRoleMessageInfo, - RawChangeRoleMessageInfo, +import { + type ChangeRoleMessageData, + type ChangeRoleMessageInfo, + type RawChangeRoleMessageInfo, + rawChangeRoleMessageInfoValidator, } from './messages/change-role.js'; -import type { - ChangeSettingsMessageData, - ChangeSettingsMessageInfo, - RawChangeSettingsMessageInfo, +import { + type ChangeSettingsMessageData, + type ChangeSettingsMessageInfo, + type RawChangeSettingsMessageInfo, + rawChangeSettingsMessageInfoValidator, } from './messages/change-settings.js'; -import type { - CreateEntryMessageData, - CreateEntryMessageInfo, - RawCreateEntryMessageInfo, +import { + type CreateEntryMessageData, + type CreateEntryMessageInfo, + type RawCreateEntryMessageInfo, + rawCreateEntryMessageInfoValidator, } from './messages/create-entry.js'; -import type { - CreateSidebarMessageData, - CreateSidebarMessageInfo, - RawCreateSidebarMessageInfo, +import { + type CreateSidebarMessageData, + type CreateSidebarMessageInfo, + type RawCreateSidebarMessageInfo, + rawCreateSidebarMessageInfoValidator, } from './messages/create-sidebar.js'; -import type { - CreateSubthreadMessageData, - CreateSubthreadMessageInfo, - RawCreateSubthreadMessageInfo, +import { + type CreateSubthreadMessageData, + type CreateSubthreadMessageInfo, + type RawCreateSubthreadMessageInfo, + rawCreateSubthreadMessageInfoValidator, } from './messages/create-subthread.js'; -import type { - CreateThreadMessageData, - CreateThreadMessageInfo, - RawCreateThreadMessageInfo, +import { + type CreateThreadMessageData, + type CreateThreadMessageInfo, + type RawCreateThreadMessageInfo, + rawCreateThreadMessageInfoValidator, } from './messages/create-thread.js'; -import type { - DeleteEntryMessageData, - DeleteEntryMessageInfo, - RawDeleteEntryMessageInfo, +import { + type DeleteEntryMessageData, + type DeleteEntryMessageInfo, + type RawDeleteEntryMessageInfo, + rawDeleteEntryMessageInfoValidator, } from './messages/delete-entry.js'; -import type { - EditEntryMessageData, - EditEntryMessageInfo, - RawEditEntryMessageInfo, +import { + type EditEntryMessageData, + type EditEntryMessageInfo, + type RawEditEntryMessageInfo, + rawEditEntryMessageInfoValidator, } from './messages/edit-entry.js'; -import type { - RawEditMessageInfo, - EditMessageData, - EditMessageInfo, +import { + type RawEditMessageInfo, + rawEditMessageInfoValidator, + type EditMessageData, + type EditMessageInfo, } from './messages/edit.js'; -import type { - ImagesMessageData, - ImagesMessageInfo, - RawImagesMessageInfo, +import { + type ImagesMessageData, + type ImagesMessageInfo, + type RawImagesMessageInfo, + rawImagesMessageInfoValidator, } from './messages/images.js'; -import type { - JoinThreadMessageData, - JoinThreadMessageInfo, - RawJoinThreadMessageInfo, +import { + type JoinThreadMessageData, + type JoinThreadMessageInfo, + type RawJoinThreadMessageInfo, + rawJoinThreadMessageInfoValidator, } from './messages/join-thread.js'; -import type { - LeaveThreadMessageData, - LeaveThreadMessageInfo, - RawLeaveThreadMessageInfo, +import { + type LeaveThreadMessageData, + type LeaveThreadMessageInfo, + type RawLeaveThreadMessageInfo, + rawLeaveThreadMessageInfoValidator, } from './messages/leave-thread.js'; -import type { - MediaMessageData, - MediaMessageInfo, - MediaMessageServerDBContent, - RawMediaMessageInfo, +import { + type MediaMessageData, + type MediaMessageInfo, + type MediaMessageServerDBContent, + type RawMediaMessageInfo, + rawMediaMessageInfoValidator, } from './messages/media.js'; -import type { - ReactionMessageData, - RawReactionMessageInfo, - ReactionMessageInfo, +import { + type ReactionMessageData, + type RawReactionMessageInfo, + rawReactionMessageInfoValidator, + type ReactionMessageInfo, } from './messages/reaction.js'; -import type { - RawRemoveMembersMessageInfo, - RemoveMembersMessageData, - RemoveMembersMessageInfo, +import { + type RawRemoveMembersMessageInfo, + rawRemoveMembersMessageInfoValidator, + type RemoveMembersMessageData, + type RemoveMembersMessageInfo, } from './messages/remove-members.js'; -import type { - RawRestoreEntryMessageInfo, - RestoreEntryMessageData, - RestoreEntryMessageInfo, +import { + type RawRestoreEntryMessageInfo, + rawRestoreEntryMessageInfoValidator, + type RestoreEntryMessageData, + type RestoreEntryMessageInfo, } from './messages/restore-entry.js'; -import type { - RawTextMessageInfo, - TextMessageData, - TextMessageInfo, +import { + type RawTextMessageInfo, + rawTextMessageInfoValidator, + type TextMessageData, + type TextMessageInfo, } from './messages/text.js'; -import type { - TogglePinMessageData, - TogglePinMessageInfo, - RawTogglePinMessageInfo, +import { + type TogglePinMessageData, + type TogglePinMessageInfo, + type RawTogglePinMessageInfo, + rawTogglePinMessageInfoValidator, } from './messages/toggle-pin.js'; -import type { - RawUnsupportedMessageInfo, - UnsupportedMessageInfo, +import { + type RawUnsupportedMessageInfo, + rawUnsupportedMessageInfoValidator, + type UnsupportedMessageInfo, } from './messages/unsupported.js'; -import type { - RawUpdateRelationshipMessageInfo, - UpdateRelationshipMessageData, - UpdateRelationshipMessageInfo, +import { + type RawUpdateRelationshipMessageInfo, + rawUpdateRelationshipMessageInfoValidator, + type UpdateRelationshipMessageData, + type UpdateRelationshipMessageInfo, } from './messages/update-relationship.js'; import { type RelativeUserInfo, type UserInfos } from './user-types.js'; import type { CallServerEndpointResultInfoInterface } from '../utils/call-server-endpoint.js'; +import { tNumber, tShape, tID } from '../utils/validation-utils.js'; const composableMessageTypes = new Set([ messageTypes.TEXT, @@ -206,9 +229,18 @@ export type RawMultimediaMessageInfo = | RawImagesMessageInfo | RawMediaMessageInfo; +const rawMultimediaMessageInfoValidator = t.union([ + rawImagesMessageInfoValidator, + rawMediaMessageInfoValidator, +]); + export type RawComposableMessageInfo = | RawTextMessageInfo | RawMultimediaMessageInfo; +const rawComposableMessageInfoValidator = t.union([ + rawTextMessageInfoValidator, + rawMultimediaMessageInfoValidator, +]); export type RawRobotextMessageInfo = | RawCreateThreadMessageInfo @@ -227,10 +259,43 @@ | RawCreateSidebarMessageInfo | RawUnsupportedMessageInfo | RawTogglePinMessageInfo; +const rawRobotextMessageInfoValidator = t.union([ + rawCreateThreadMessageInfoValidator, + rawAddMembersMessageInfoValidator, + rawCreateSubthreadMessageInfoValidator, + rawChangeSettingsMessageInfoValidator, + rawRemoveMembersMessageInfoValidator, + rawChangeRoleMessageInfoValidator, + rawLeaveThreadMessageInfoValidator, + rawJoinThreadMessageInfoValidator, + rawCreateEntryMessageInfoValidator, + rawEditEntryMessageInfoValidator, + rawDeleteEntryMessageInfoValidator, + rawRestoreEntryMessageInfoValidator, + rawUpdateRelationshipMessageInfoValidator, + rawCreateSidebarMessageInfoValidator, + rawUnsupportedMessageInfoValidator, + rawTogglePinMessageInfoValidator, +]); + export type RawSidebarSourceMessageInfo = { ...SidebarSourceMessageData, id: string, }; +export const rawSidebarSourceMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.SIDEBAR_SOURCE), + threadID: tID, + creatorID: t.String, + time: t.Number, + sourceMessage: t.maybe( + t.union([ + rawComposableMessageInfoValidator, + rawRobotextMessageInfoValidator, + ]), + ), + id: tID, + }); export type RawMessageInfo = | RawComposableMessageInfo @@ -238,6 +303,13 @@ | RawSidebarSourceMessageInfo | RawReactionMessageInfo | RawEditMessageInfo; +export const rawMessageInfoValidator: TUnion = t.union([ + rawComposableMessageInfoValidator, + rawRobotextMessageInfoValidator, + rawSidebarSourceMessageInfoValidator, + rawReactionMessageInfoValidator, + rawEditMessageInfoValidator, +]); export type LocallyComposedMessageInfo = | ({ diff --git a/lib/types/messages/add-members.js b/lib/types/messages/add-members.js --- a/lib/types/messages/add-members.js +++ b/lib/types/messages/add-members.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tShape, tID, tNumber } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type AddMembersMessageData = { @@ -15,6 +19,16 @@ id: string, }; +export const rawAddMembersMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.ADD_MEMBERS), + threadID: tID, + creatorID: t.String, + time: t.Number, + addedUserIDs: t.list(t.String), + id: tID, + }); + export type AddMembersMessageInfo = { type: 2, id: string, diff --git a/lib/types/messages/change-role.js b/lib/types/messages/change-role.js --- a/lib/types/messages/change-role.js +++ b/lib/types/messages/change-role.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type ChangeRoleMessageData = { @@ -16,6 +20,17 @@ id: string, }; +export const rawChangeRoleMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.CHANGE_ROLE), + threadID: tID, + creatorID: t.String, + time: t.Number, + userIDs: t.list(t.String), + newRole: t.String, + id: tID, + }); + export type ChangeRoleMessageInfo = { type: 6, id: string, diff --git a/lib/types/messages/change-settings.js b/lib/types/messages/change-settings.js --- a/lib/types/messages/change-settings.js +++ b/lib/types/messages/change-settings.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type ChangeSettingsMessageData = { @@ -16,6 +20,17 @@ id: string, }; +export const rawChangeSettingsMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.CHANGE_SETTINGS), + threadID: tID, + creatorID: t.String, + time: t.Number, + field: t.String, + value: t.union([t.String, t.Number]), + id: tID, + }); + export type ChangeSettingsMessageInfo = { type: 4, id: string, diff --git a/lib/types/messages/create-entry.js b/lib/types/messages/create-entry.js --- a/lib/types/messages/create-entry.js +++ b/lib/types/messages/create-entry.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type CreateEntryMessageData = { @@ -17,6 +21,18 @@ id: string, }; +export const rawCreateEntryMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.CREATE_ENTRY), + threadID: tID, + creatorID: t.String, + time: t.Number, + entryID: tID, + date: t.String, + text: t.String, + id: tID, + }); + export type CreateEntryMessageInfo = { type: 9, id: string, diff --git a/lib/types/messages/create-sidebar.js b/lib/types/messages/create-sidebar.js --- a/lib/types/messages/create-sidebar.js +++ b/lib/types/messages/create-sidebar.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { ThreadInfo } from '../thread-types.js'; import type { RelativeUserInfo } from '../user-types.js'; @@ -22,6 +26,22 @@ id: string, }; +export const rawCreateSidebarMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.CREATE_SIDEBAR), + threadID: tID, + creatorID: t.String, + time: t.Number, + sourceMessageAuthorID: t.String, + initialThreadState: tShape({ + name: t.maybe(t.String), + parentThreadID: tID, + color: t.String, + memberIDs: t.list(t.String), + }), + id: tID, + }); + export type CreateSidebarMessageInfo = { +type: 18, +id: string, diff --git a/lib/types/messages/create-subthread.js b/lib/types/messages/create-subthread.js --- a/lib/types/messages/create-subthread.js +++ b/lib/types/messages/create-subthread.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { ThreadInfo } from '../thread-types.js'; import type { RelativeUserInfo } from '../user-types.js'; @@ -16,6 +20,16 @@ id: string, }; +export const rawCreateSubthreadMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.CREATE_SUB_THREAD), + threadID: tID, + creatorID: t.String, + time: t.Number, + childThreadID: tID, + id: tID, + }); + export type CreateSubthreadMessageInfo = { type: 3, id: string, diff --git a/lib/types/messages/create-thread.js b/lib/types/messages/create-thread.js --- a/lib/types/messages/create-thread.js +++ b/lib/types/messages/create-thread.js @@ -1,6 +1,20 @@ // @flow -import type { ThreadInfo, ThreadType } from '../thread-types.js'; +import t, { type TInterface } from 'tcomb'; + +import { values } from '../../utils/objects.js'; +import { + tID, + tNumber, + tShape, + tNumEnum, +} from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; +import { + threadTypes, + type ThreadInfo, + type ThreadType, +} from '../thread-types.js'; import type { RelativeUserInfo } from '../user-types.js'; export type CreateThreadMessageData = { @@ -22,6 +36,22 @@ id: string, }; +export const rawCreateThreadMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.CREATE_THREAD), + threadID: tID, + creatorID: t.String, + time: t.Number, + initialThreadState: tShape({ + type: tNumEnum(values(threadTypes)), + name: t.maybe(t.String), + parentThreadID: t.maybe(tID), + color: t.String, + memberIDs: t.list(t.String), + }), + id: tID, + }); + export type CreateThreadMessageInfo = { type: 1, id: string, diff --git a/lib/types/messages/delete-entry.js b/lib/types/messages/delete-entry.js --- a/lib/types/messages/delete-entry.js +++ b/lib/types/messages/delete-entry.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type DeleteEntryMessageData = { @@ -17,6 +21,18 @@ id: string, }; +export const rawDeleteEntryMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.DELETE_ENTRY), + threadID: tID, + creatorID: t.String, + time: t.Number, + entryID: tID, + date: t.String, + text: t.String, + id: tID, + }); + export type DeleteEntryMessageInfo = { type: 11, id: string, diff --git a/lib/types/messages/edit-entry.js b/lib/types/messages/edit-entry.js --- a/lib/types/messages/edit-entry.js +++ b/lib/types/messages/edit-entry.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type EditEntryMessageData = { @@ -17,6 +21,18 @@ id: string, }; +export const rawEditEntryMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.EDIT_ENTRY), + threadID: tID, + creatorID: t.String, + time: t.Number, + entryID: tID, + date: t.String, + text: t.String, + id: tID, + }); + export type EditEntryMessageInfo = { type: 10, id: string, diff --git a/lib/types/messages/edit.js b/lib/types/messages/edit.js --- a/lib/types/messages/edit.js +++ b/lib/types/messages/edit.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type EditMessageData = { @@ -16,6 +20,17 @@ +id: string, }; +export const rawEditMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.EDIT_MESSAGE), + threadID: tID, + creatorID: t.String, + time: t.Number, + targetMessageID: tID, + text: t.String, + id: tID, + }); + export type EditMessageInfo = { +type: 20, +id: string, diff --git a/lib/types/messages/images.js b/lib/types/messages/images.js --- a/lib/types/messages/images.js +++ b/lib/types/messages/images.js @@ -1,6 +1,10 @@ // @flow -import type { Image } from '../media-types.js'; +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { imageValidator, type Image } from '../media-types.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; type ImagesSharedBase = { @@ -22,6 +26,17 @@ +id?: string, // null if local copy without ID yet }; +export const rawImagesMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.IMAGES), + localID: t.maybe(t.String), + threadID: tID, + creatorID: t.String, + time: t.Number, + media: t.list(imageValidator), + id: t.maybe(tID), + }); + export type ImagesMessageInfo = { +type: 14, +id?: string, // null if local copy without ID yet diff --git a/lib/types/messages/join-thread.js b/lib/types/messages/join-thread.js --- a/lib/types/messages/join-thread.js +++ b/lib/types/messages/join-thread.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type JoinThreadMessageData = { @@ -14,6 +18,15 @@ id: string, }; +export const rawJoinThreadMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.JOIN_THREAD), + threadID: tID, + creatorID: t.String, + time: t.Number, + id: tID, + }); + export type JoinThreadMessageInfo = { type: 8, id: string, diff --git a/lib/types/messages/leave-thread.js b/lib/types/messages/leave-thread.js --- a/lib/types/messages/leave-thread.js +++ b/lib/types/messages/leave-thread.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type LeaveThreadMessageData = { @@ -14,6 +18,15 @@ id: string, }; +export const rawLeaveThreadMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.LEAVE_THREAD), + threadID: tID, + creatorID: t.String, + time: t.Number, + id: tID, + }); + export type LeaveThreadMessageInfo = { type: 7, id: string, diff --git a/lib/types/messages/media.js b/lib/types/messages/media.js --- a/lib/types/messages/media.js +++ b/lib/types/messages/media.js @@ -1,6 +1,10 @@ // @flow -import type { Media } from '../media-types.js'; +import t, { type TInterface } from 'tcomb'; + +import { tShape, tNumber, tID } from '../../utils/validation-utils.js'; +import { type Media, mediaValidator } from '../media-types.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; type MediaSharedBase = { @@ -22,6 +26,17 @@ +id?: string, // null if local copy without ID yet }; +export const rawMediaMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.MULTIMEDIA), + localID: t.maybe(t.String), + threadID: tID, + creatorID: t.String, + time: t.Number, + media: t.list(mediaValidator), + id: t.maybe(tID), + }); + export type MediaMessageInfo = { +type: 15, +id?: string, // null if local copy without ID yet diff --git a/lib/types/messages/reaction.js b/lib/types/messages/reaction.js --- a/lib/types/messages/reaction.js +++ b/lib/types/messages/reaction.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type ReactionMessageData = { @@ -18,6 +22,19 @@ id?: string, // null if local copy without ID yet }; +export const rawReactionMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.REACTION), + localID: t.maybe(t.String), + threadID: tID, + creatorID: t.String, + time: t.Number, + targetMessageID: tID, + reaction: t.String, + action: t.enums.of(['add_reaction', 'remove_reaction']), + id: t.maybe(tID), + }); + export type ReactionMessageInfo = { +type: 19, +id?: string, // null if local copy without ID yet diff --git a/lib/types/messages/remove-members.js b/lib/types/messages/remove-members.js --- a/lib/types/messages/remove-members.js +++ b/lib/types/messages/remove-members.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type RemoveMembersMessageData = { @@ -15,6 +19,16 @@ id: string, }; +export const rawRemoveMembersMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.REMOVE_MEMBERS), + threadID: tID, + creatorID: t.String, + time: t.Number, + removedUserIDs: t.list(t.String), + id: tID, + }); + export type RemoveMembersMessageInfo = { type: 5, id: string, diff --git a/lib/types/messages/restore-entry.js b/lib/types/messages/restore-entry.js --- a/lib/types/messages/restore-entry.js +++ b/lib/types/messages/restore-entry.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type RestoreEntryMessageData = { @@ -17,6 +21,18 @@ id: string, }; +export const rawRestoreEntryMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.RESTORE_ENTRY), + threadID: tID, + creatorID: t.String, + time: t.Number, + entryID: tID, + date: t.String, + text: t.String, + id: tID, + }); + export type RestoreEntryMessageInfo = { type: 12, id: string, diff --git a/lib/types/messages/text.js b/lib/types/messages/text.js --- a/lib/types/messages/text.js +++ b/lib/types/messages/text.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; type TextSharedBase = { @@ -21,6 +25,17 @@ +id?: string, // null if local copy without ID yet }; +export const rawTextMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.TEXT), + localID: t.maybe(t.String), + threadID: tID, + creatorID: t.String, + time: t.Number, + text: t.String, + id: t.maybe(tID), + }); + export type TextMessageInfo = { +type: 0, +id?: string, // null if local copy without ID yet diff --git a/lib/types/messages/toggle-pin.js b/lib/types/messages/toggle-pin.js --- a/lib/types/messages/toggle-pin.js +++ b/lib/types/messages/toggle-pin.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type TogglePinMessageData = { @@ -17,6 +21,18 @@ +id: string, }; +export const rawTogglePinMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.TOGGLE_PIN), + threadID: tID, + targetMessageID: tID, + action: t.enums.of(['pin', 'unpin']), + pinnedContent: t.String, + creatorID: t.String, + time: t.Number, + id: tID, + }); + export type TogglePinMessageInfo = { +type: 21, +id: string, diff --git a/lib/types/messages/unsupported.js b/lib/types/messages/unsupported.js --- a/lib/types/messages/unsupported.js +++ b/lib/types/messages/unsupported.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type RawUnsupportedMessageInfo = { @@ -13,6 +17,18 @@ unsupportedMessageInfo: Object, }; +export const rawUnsupportedMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.UNSUPPORTED), + id: tID, + threadID: tID, + creatorID: t.String, + time: t.Number, + robotext: t.String, + dontPrefixCreator: t.maybe(t.Boolean), + unsupportedMessageInfo: t.Object, + }); + export type UnsupportedMessageInfo = { type: 13, id: string, diff --git a/lib/types/messages/update-relationship.js b/lib/types/messages/update-relationship.js --- a/lib/types/messages/update-relationship.js +++ b/lib/types/messages/update-relationship.js @@ -1,5 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + +import { tID, tNumber, tShape } from '../../utils/validation-utils.js'; +import { messageTypes } from '../message-types-enum.js'; import type { RelativeUserInfo } from '../user-types.js'; export type UpdateRelationshipMessageData = { @@ -16,6 +20,17 @@ id: string, }; +export const rawUpdateRelationshipMessageInfoValidator: TInterface = + tShape({ + type: tNumber(messageTypes.UPDATE_RELATIONSHIP), + threadID: tID, + creatorID: t.String, + targetID: t.String, + time: t.Number, + operation: t.enums.of(['request_sent', 'request_accepted']), + id: tID, + }); + export type UpdateRelationshipMessageInfo = { +type: 16, +id: string, diff --git a/lib/types/validation.test.js b/lib/types/validation.test.js --- a/lib/types/validation.test.js +++ b/lib/types/validation.test.js @@ -1,10 +1,35 @@ // @flow +import _findKey from 'lodash/fp/findKey.js'; + import { imageValidator, videoValidator, mediaValidator, } from './media-types.js'; +import { messageTypes } from './message-types-enum.js'; +import { rawSidebarSourceMessageInfoValidator } from './message-types.js'; +import { rawAddMembersMessageInfoValidator } from './messages/add-members.js'; +import { rawChangeRoleMessageInfoValidator } from './messages/change-role.js'; +import { rawChangeSettingsMessageInfoValidator } from './messages/change-settings.js'; +import { rawCreateEntryMessageInfoValidator } from './messages/create-entry.js'; +import { rawCreateSidebarMessageInfoValidator } from './messages/create-sidebar.js'; +import { rawCreateSubthreadMessageInfoValidator } from './messages/create-subthread.js'; +import { rawCreateThreadMessageInfoValidator } from './messages/create-thread.js'; +import { rawDeleteEntryMessageInfoValidator } from './messages/delete-entry.js'; +import { rawEditEntryMessageInfoValidator } from './messages/edit-entry.js'; +import { rawEditMessageInfoValidator } from './messages/edit.js'; +import { rawImagesMessageInfoValidator } from './messages/images.js'; +import { rawJoinThreadMessageInfoValidator } from './messages/join-thread.js'; +import { rawLeaveThreadMessageInfoValidator } from './messages/leave-thread.js'; +import { rawMediaMessageInfoValidator } from './messages/media.js'; +import { rawReactionMessageInfoValidator } from './messages/reaction.js'; +import { rawRemoveMembersMessageInfoValidator } from './messages/remove-members.js'; +import { rawRestoreEntryMessageInfoValidator } from './messages/restore-entry.js'; +import { rawTextMessageInfoValidator } from './messages/text.js'; +import { rawTogglePinMessageInfoValidator } from './messages/toggle-pin.js'; +import { rawUnsupportedMessageInfoValidator } from './messages/unsupported.js'; +import { rawUpdateRelationshipMessageInfoValidator } from './messages/update-relationship.js'; describe('media validation', () => { const photo = { @@ -42,3 +67,296 @@ expect(mediaValidator.is({ ...video, dimensions: undefined })).toBe(false); }); }); + +describe('message validation', () => { + const messages = [ + { + type: messageTypes.TEXT, + threadID: '83859', + creatorID: '83853', + time: 1682077048858, + text: 'text', + localID: 'local1', + id: '92837', + }, + { + type: messageTypes.CREATE_THREAD, + id: '83876', + threadID: '83859', + time: 1673561105839, + creatorID: '83853', + initialThreadState: { + type: 6, + name: null, + parentThreadID: '1', + color: '57697f', + memberIDs: ['256', '83853'], + }, + }, + { + type: messageTypes.ADD_MEMBERS, + id: '4754380', + threadID: '4746046', + time: 1680179819346, + creatorID: '256', + addedUserIDs: ['518252', '1329299', '1559042'], + }, + { + type: messageTypes.CREATE_SUB_THREAD, + threadID: '87111', + creatorID: '83928', + time: 1682083573756, + childThreadID: '92993', + id: '93000', + }, + { + type: messageTypes.CHANGE_SETTINGS, + threadID: '83859', + creatorID: '83853', + time: 1682082984605, + field: 'color', + value: 'b8753d', + id: '92880', + }, + { + type: messageTypes.REMOVE_MEMBERS, + threadID: '92993', + creatorID: '83928', + time: 1682083613415, + removedUserIDs: ['83890'], + id: '93012', + }, + { + type: messageTypes.CHANGE_ROLE, + threadID: '85027', + creatorID: '256', + time: 1632393331694, + userIDs: ['85081'], + newRole: 'role', + id: '85431', + }, + { + type: messageTypes.LEAVE_THREAD, + id: '93027', + threadID: '92993', + time: 1682083651037, + creatorID: '83928', + }, + { + type: messageTypes.JOIN_THREAD, + threadID: '92993', + creatorID: '83928', + time: 1682083678595, + id: '93035', + }, + { + type: messageTypes.CREATE_ENTRY, + threadID: '84695', + creatorID: '83928', + time: 1682083217395, + entryID: '92917', + date: '2023-04-02', + text: 'text', + id: '92920', + }, + { + type: messageTypes.EDIT_ENTRY, + threadID: '84695', + creatorID: '83928', + time: 1682083374471, + entryID: '92917', + date: '2023-04-02', + text: 'text', + id: '92950', + }, + { + type: messageTypes.DELETE_ENTRY, + threadID: '86033', + creatorID: '83928', + time: 1682083220296, + entryID: '92904', + date: '2023-04-02', + text: 'text', + id: '92932', + }, + { + type: messageTypes.RESTORE_ENTRY, + id: '92962', + threadID: '86033', + time: 1682083414244, + creatorID: '83928', + entryID: '92904', + date: '2023-04-02', + text: 'text', + }, + { + type: messageTypes.UNSUPPORTED, + threadID: '87080', + creatorID: '256', + time: 1640733462322, + robotext: 'unsupported message', + unsupportedMessageInfo: { + type: 105, + threadID: '97489', + creatorID: '256', + time: 1640773011289, + id: '97672', + }, + id: '97730', + }, + { + type: messageTypes.IMAGES, + threadID: '92796', + creatorID: '83928', + time: 1682083469079, + media: [ + { + id: '92974', + uri: 'http://0.0.0.0:3000/comm/upload/92974/ff3d02ded71e2762', + type: 'photo', + dimensions: { + width: 220, + height: 220, + }, + }, + ], + localID: 'local0', + id: '92976', + }, + { + type: messageTypes.MULTIMEDIA, + threadID: '89644', + creatorID: '83853', + time: 1682076177257, + media: [ + { + type: 'video', + id: '92769', + uri: 'http://0.0.0.0:3000/comm/upload/92769/4bcc6987b25b2f66', + dimensions: { + width: 480, + height: 270, + }, + thumbnailID: '92770', + thumbnailURI: + 'http://0.0.0.0:3000/comm/upload/92770/d56466051dcef1db', + }, + ], + id: '92771', + }, + { + type: messageTypes.UPDATE_RELATIONSHIP, + threadID: '92796', + creatorID: '83928', + targetID: '83853', + time: 1682083716312, + operation: 'request_sent', + id: '93039', + }, + { + type: messageTypes.SIDEBAR_SOURCE, + threadID: '93044', + creatorID: '83928', + time: 1682083756831, + sourceMessage: { + type: 0, + id: '92816', + threadID: '92796', + time: 1682076737518, + creatorID: '83928', + text: 'text', + }, + id: '93049', + }, + { + type: messageTypes.CREATE_SIDEBAR, + threadID: '93044', + creatorID: '83928', + time: 1682083756831, + sourceMessageAuthorID: '83928', + initialThreadState: { + name: 'text', + parentThreadID: '92796', + color: 'aa4b4b', + memberIDs: ['83853', '83928'], + }, + id: '93050', + }, + { + type: messageTypes.REACTION, + threadID: '86033', + localID: 'local8', + creatorID: '83928', + time: 1682083295820, + targetMessageID: '91607', + reaction: '😂', + action: 'add_reaction', + id: '92943', + }, + { + type: messageTypes.EDIT_MESSAGE, + threadID: '86033', + creatorID: '83928', + time: 1682083295820, + targetMessageID: '91607', + text: 'text', + id: '92943', + }, + { + type: messageTypes.TOGGLE_PIN, + threadID: '86033', + targetMessageID: '91607', + action: 'pin', + pinnedContent: 'text', + creatorID: '83928', + time: 1682083295820, + id: '92943', + }, + ]; + + const validatorByMessageType = { + '0': rawTextMessageInfoValidator, + '1': rawCreateThreadMessageInfoValidator, + '2': rawAddMembersMessageInfoValidator, + '3': rawCreateSubthreadMessageInfoValidator, + '4': rawChangeSettingsMessageInfoValidator, + '5': rawRemoveMembersMessageInfoValidator, + '6': rawChangeRoleMessageInfoValidator, + '7': rawLeaveThreadMessageInfoValidator, + '8': rawJoinThreadMessageInfoValidator, + '9': rawCreateEntryMessageInfoValidator, + '10': rawEditEntryMessageInfoValidator, + '11': rawDeleteEntryMessageInfoValidator, + '12': rawRestoreEntryMessageInfoValidator, + '13': rawUnsupportedMessageInfoValidator, + '14': rawImagesMessageInfoValidator, + '15': rawMediaMessageInfoValidator, + '16': rawUpdateRelationshipMessageInfoValidator, + '17': rawSidebarSourceMessageInfoValidator, + '18': rawCreateSidebarMessageInfoValidator, + '19': rawReactionMessageInfoValidator, + '20': rawEditMessageInfoValidator, + '21': rawTogglePinMessageInfoValidator, + }; + + for (const validatorMessageType in validatorByMessageType) { + const validator = validatorByMessageType[validatorMessageType]; + const validatorMessageTypeName = _findKey( + e => e === Number(validatorMessageType), + )(messageTypes); + + for (const message of messages) { + const messageTypeName = _findKey(e => e === message.type)(messageTypes); + + if (Number(validatorMessageType) === message.type) { + it(`${validatorMessageTypeName} should validate ${messageTypeName}`, () => { + expect(validator.is(message)).toBe(true); + }); + } else { + it(`${validatorMessageTypeName} shouldn't validate ${messageTypeName}`, () => { + expect(validator.is(message)).toBe(false); + }); + } + } + } +});