diff --git a/lib/types/update-types.js b/lib/types/update-types.js index 601bc41bc..1a08e62aa 100644 --- a/lib/types/update-types.js +++ b/lib/types/update-types.js @@ -1,319 +1,408 @@ // @flow import invariant from 'invariant'; +import t, { type TUnion, type TInterface } from 'tcomb'; -import type { RawEntryInfo } from './entry-types.js'; -import type { - RawMessageInfo, - MessageTruncationStatus, +import { type RawEntryInfo, rawEntryInfoValidator } from './entry-types.js'; +import { + type RawMessageInfo, + rawMessageInfoValidator, + type MessageTruncationStatus, + messageTruncationStatusValidator, } from './message-types.js'; -import type { RawThreadInfo } from './thread-types.js'; -import type { - UserInfo, - UserInfos, - LoggedInUserInfo, - OldLoggedInUserInfo, +import { type RawThreadInfo, rawThreadInfoValidator } from './thread-types.js'; +import { + type UserInfo, + type UserInfos, + type LoggedInUserInfo, + loggedInUserInfoValidator, + type OldLoggedInUserInfo, + oldLoggedInUserInfoValidator, } from './user-types.js'; +import { tNumber, tShape, tID } from '../utils/validation-utils.js'; export const updateTypes = Object.freeze({ DELETE_ACCOUNT: 0, UPDATE_THREAD: 1, UPDATE_THREAD_READ_STATUS: 2, DELETE_THREAD: 3, JOIN_THREAD: 4, BAD_DEVICE_TOKEN: 5, UPDATE_ENTRY: 6, UPDATE_CURRENT_USER: 7, UPDATE_USER: 8, }); export type UpdateType = $Values; export function assertUpdateType(ourUpdateType: number): UpdateType { invariant( ourUpdateType === 0 || ourUpdateType === 1 || ourUpdateType === 2 || ourUpdateType === 3 || ourUpdateType === 4 || ourUpdateType === 5 || ourUpdateType === 6 || ourUpdateType === 7 || ourUpdateType === 8, 'number is not UpdateType enum', ); return ourUpdateType; } type AccountDeletionData = { +deletedUserID: string, }; type ThreadData = { +threadID: string, }; type ThreadReadStatusData = { +threadID: string, +unread: boolean, }; type ThreadDeletionData = { +threadID: string, }; type ThreadJoinData = { +threadID: string, }; type BadDeviceTokenData = { +deviceToken: string, }; type EntryData = { +entryID: string, }; type CurrentUserData = {}; type UserData = { // ID of the UserInfo being updated +updatedUserID: string, }; type SharedUpdateData = { +userID: string, +time: number, }; type AccountDeletionUpdateData = { ...SharedUpdateData, ...AccountDeletionData, +type: 0, }; type ThreadUpdateData = { ...SharedUpdateData, ...ThreadData, +type: 1, +targetSession?: string, }; type ThreadReadStatusUpdateData = { ...SharedUpdateData, ...ThreadReadStatusData, +type: 2, }; type ThreadDeletionUpdateData = { ...SharedUpdateData, ...ThreadDeletionData, +type: 3, }; type ThreadJoinUpdateData = { ...SharedUpdateData, ...ThreadJoinData, +type: 4, +targetSession?: string, }; type BadDeviceTokenUpdateData = { ...SharedUpdateData, ...BadDeviceTokenData, +type: 5, +targetCookie: string, }; type EntryUpdateData = { ...SharedUpdateData, ...EntryData, +type: 6, +targetSession: string, }; type CurrentUserUpdateData = { ...SharedUpdateData, ...CurrentUserData, +type: 7, }; type UserUpdateData = { ...SharedUpdateData, ...UserData, +type: 8, +targetSession?: string, }; export type UpdateData = | AccountDeletionUpdateData | ThreadUpdateData | ThreadReadStatusUpdateData | ThreadDeletionUpdateData | ThreadJoinUpdateData | BadDeviceTokenUpdateData | EntryUpdateData | CurrentUserUpdateData | UserUpdateData; type SharedRawUpdateInfo = { +id: string, +time: number, }; type AccountDeletionRawUpdateInfo = { ...SharedRawUpdateInfo, ...AccountDeletionData, +type: 0, }; type ThreadRawUpdateInfo = { ...SharedRawUpdateInfo, ...ThreadData, +type: 1, }; type ThreadReadStatusRawUpdateInfo = { ...SharedRawUpdateInfo, ...ThreadReadStatusData, +type: 2, }; type ThreadDeletionRawUpdateInfo = { ...SharedRawUpdateInfo, ...ThreadDeletionData, +type: 3, }; type ThreadJoinRawUpdateInfo = { ...SharedRawUpdateInfo, ...ThreadJoinData, +type: 4, }; type BadDeviceTokenRawUpdateInfo = { ...SharedRawUpdateInfo, ...BadDeviceTokenData, +type: 5, }; type EntryRawUpdateInfo = { ...SharedRawUpdateInfo, ...EntryData, +type: 6, }; type CurrentUserRawUpdateInfo = { ...SharedRawUpdateInfo, ...CurrentUserData, +type: 7, }; type UserRawUpdateInfo = { ...SharedRawUpdateInfo, ...UserData, +type: 8, }; export type RawUpdateInfo = | AccountDeletionRawUpdateInfo | ThreadRawUpdateInfo | ThreadReadStatusRawUpdateInfo | ThreadDeletionRawUpdateInfo | ThreadJoinRawUpdateInfo | BadDeviceTokenRawUpdateInfo | EntryRawUpdateInfo | CurrentUserRawUpdateInfo | UserRawUpdateInfo; type AccountDeletionUpdateInfo = { +type: 0, +id: string, +time: number, +deletedUserID: string, }; +export const accountDeletionUpdateInfoValidator: TInterface = + tShape({ + type: tNumber(updateTypes.DELETE_ACCOUNT), + id: t.String, + time: t.Number, + deletedUserID: t.String, + }); + type ThreadUpdateInfo = { +type: 1, +id: string, +time: number, +threadInfo: RawThreadInfo, }; +export const threadUpdateInfoValidator: TInterface = + tShape({ + type: tNumber(updateTypes.UPDATE_THREAD), + id: t.String, + time: t.Number, + threadInfo: rawThreadInfoValidator, + }); type ThreadReadStatusUpdateInfo = { +type: 2, +id: string, +time: number, +threadID: string, +unread: boolean, }; +export const threadReadStatusUpdateInfoValidator: TInterface = + tShape({ + type: tNumber(updateTypes.UPDATE_THREAD_READ_STATUS), + id: t.String, + time: t.Number, + threadID: tID, + unread: t.Boolean, + }); type ThreadDeletionUpdateInfo = { +type: 3, +id: string, +time: number, +threadID: string, }; +export const threadDeletionUpdateInfoValidator: TInterface = + tShape({ + type: tNumber(updateTypes.DELETE_THREAD), + id: t.String, + time: t.Number, + threadID: tID, + }); + type ThreadJoinUpdateInfo = { +type: 4, +id: string, +time: number, +threadInfo: RawThreadInfo, +rawMessageInfos: $ReadOnlyArray, +truncationStatus: MessageTruncationStatus, +rawEntryInfos: $ReadOnlyArray, }; +export const threadJoinUpdateInfoValidator: TInterface = + tShape({ + type: tNumber(updateTypes.JOIN_THREAD), + id: t.String, + time: t.Number, + threadInfo: rawThreadInfoValidator, + rawMessageInfos: t.list(rawMessageInfoValidator), + truncationStatus: messageTruncationStatusValidator, + rawEntryInfos: t.list(rawEntryInfoValidator), + }); type BadDeviceTokenUpdateInfo = { +type: 5, +id: string, +time: number, +deviceToken: string, }; +export const badDeviceTokenUpdateInfoValidator: TInterface = + tShape({ + type: tNumber(updateTypes.BAD_DEVICE_TOKEN), + id: t.String, + time: t.Number, + deviceToken: t.String, + }); type EntryUpdateInfo = { +type: 6, +id: string, +time: number, +entryInfo: RawEntryInfo, }; +export const entryUpdateInfoValidator: TInterface = + tShape({ + type: tNumber(updateTypes.UPDATE_ENTRY), + id: t.String, + time: t.Number, + entryInfo: rawEntryInfoValidator, + }); type CurrentUserUpdateInfo = { +type: 7, +id: string, +time: number, +currentUserInfo: LoggedInUserInfo, }; type UserUpdateInfo = { +type: 8, +id: string, +time: number, // Updated UserInfo is already contained within the UpdatesResultWithUserInfos +updatedUserID: string, }; +export const userUpdateInfoValidator: TInterface = + tShape({ + type: tNumber(updateTypes.UPDATE_USER), + id: t.String, + time: t.Number, + updatedUserID: t.String, + }); export type ClientUpdateInfo = | AccountDeletionUpdateInfo | ThreadUpdateInfo | ThreadReadStatusUpdateInfo | ThreadDeletionUpdateInfo | ThreadJoinUpdateInfo | BadDeviceTokenUpdateInfo | EntryUpdateInfo | CurrentUserUpdateInfo | UserUpdateInfo; type ServerCurrentUserUpdateInfo = { +type: 7, +id: string, +time: number, +currentUserInfo: LoggedInUserInfo | OldLoggedInUserInfo, }; +export const serverCurrentUserUpdateInfoValidator: TInterface = + tShape({ + type: tNumber(updateTypes.UPDATE_CURRENT_USER), + id: t.String, + time: t.Number, + currentUserInfo: t.union([ + loggedInUserInfoValidator, + oldLoggedInUserInfoValidator, + ]), + }); export type ServerUpdateInfo = | AccountDeletionUpdateInfo | ThreadUpdateInfo | ThreadReadStatusUpdateInfo | ThreadDeletionUpdateInfo | ThreadJoinUpdateInfo | BadDeviceTokenUpdateInfo | EntryUpdateInfo | ServerCurrentUserUpdateInfo | UserUpdateInfo; +export const serverUpdateInfoValidator: TUnion = t.union([ + accountDeletionUpdateInfoValidator, + threadUpdateInfoValidator, + threadReadStatusUpdateInfoValidator, + threadDeletionUpdateInfoValidator, + threadJoinUpdateInfoValidator, + badDeviceTokenUpdateInfoValidator, + entryUpdateInfoValidator, + serverCurrentUserUpdateInfoValidator, + userUpdateInfoValidator, +]); export type ServerUpdatesResult = { +currentAsOf: number, +newUpdates: $ReadOnlyArray, }; export type ServerUpdatesResultWithUserInfos = { +updatesResult: ServerUpdatesResult, +userInfos: $ReadOnlyArray, }; export type ClientUpdatesResult = { +currentAsOf: number, +newUpdates: $ReadOnlyArray, }; export type ClientUpdatesResultWithUserInfos = { +updatesResult: ClientUpdatesResult, +userInfos: $ReadOnlyArray, }; export type CreateUpdatesResult = { +viewerUpdates: $ReadOnlyArray, +userInfos: UserInfos, }; export type ServerCreateUpdatesResponse = { +viewerUpdates: $ReadOnlyArray, +userInfos: $ReadOnlyArray, }; export type ClientCreateUpdatesResponse = { +viewerUpdates: $ReadOnlyArray, +userInfos: $ReadOnlyArray, }; export const processUpdatesActionType = 'PROCESS_UPDATES'; diff --git a/lib/types/validation.test.js b/lib/types/validation.test.js index 7f8ba4b05..7f673246f 100644 --- a/lib/types/validation.test.js +++ b/lib/types/validation.test.js @@ -1,657 +1,768 @@ // @flow import _findKey from 'lodash/fp/findKey.js'; import { rawEntryInfoValidator } from './entry-types.js'; import { imageValidator, videoValidator, mediaValidator, } from './media-types.js'; import { messageTypes } from './message-types-enum.js'; import { threadTypes, rawThreadInfoValidator } from './thread-types.js'; +import { + updateTypes, + accountDeletionUpdateInfoValidator, + badDeviceTokenUpdateInfoValidator, + entryUpdateInfoValidator, + serverCurrentUserUpdateInfoValidator, + threadDeletionUpdateInfoValidator, + threadJoinUpdateInfoValidator, + threadReadStatusUpdateInfoValidator, + threadUpdateInfoValidator, + userUpdateInfoValidator, +} from './update-types.js'; import { messageSpecs } from '../shared/messages/message-specs.js'; describe('media validation', () => { const photo = { id: '92696', type: 'photo', uri: 'http://0.0.0.0:3000/comm/upload/92696/0fb272bd1c75d976', dimensions: { width: 340, height: 288, }, }; const video = { 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', }; it('should validate correct media', () => { expect(mediaValidator.is(photo)).toBe(true); expect(imageValidator.is(photo)).toBe(true); expect(mediaValidator.is(video)).toBe(true); expect(videoValidator.is(video)).toBe(true); }); it('should not validate incorrect media', () => { expect(imageValidator.is(video)).toBe(false); expect(videoValidator.is(photo)).toBe(false); expect(mediaValidator.is({ ...photo, type: undefined })).toBe(false); 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', +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.UNSUPPORTED, - threadID: '87080', + }, + { + 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: 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', + time: 1640773011289, + id: '97672', }, - { - type: messageTypes.SIDEBAR_SOURCE, - threadID: '93044', - creatorID: '83928', - time: 1682083756831, - sourceMessage: { - type: 0, - id: '92816', - threadID: '92796', - time: 1682076737518, - creatorID: '83928', - text: 'text', + 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, + }, }, - id: '93049', - }, - { - type: messageTypes.CREATE_SIDEBAR, - threadID: '93044', - creatorID: '83928', - time: 1682083756831, - sourceMessageAuthorID: '83928', - initialThreadState: { - name: 'text', - parentThreadID: '92796', - color: 'aa4b4b', - memberIDs: ['83853', '83928'], + ], + 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: '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', + ], + 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', - 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', + 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', + }, +]; +describe('message validation', () => { for (const validatorMessageTypeName in messageTypes) { const validatorMessageType = messageTypes[validatorMessageTypeName]; const validator = messageSpecs[validatorMessageType].validator; for (const message of messages) { const messageTypeName = _findKey(e => e === message.type)(messageTypes); if (validatorMessageType === message.type) { it(`${validatorMessageTypeName} should validate ${messageTypeName}`, () => { expect(validator.is(message)).toBe(true); }); } else if ( !( (validatorMessageType === messageTypes.IMAGES && message.type === messageTypes.MULTIMEDIA) || (validatorMessageType === messageTypes.MULTIMEDIA && message.type === messageTypes.IMAGES) ) ) { it(`${validatorMessageTypeName} shouldn't validate ${messageTypeName}`, () => { expect(validator.is(message)).toBe(false); }); } } } }); -describe('thread validation', () => { - const thread = { - id: '85171', - type: threadTypes.PERSONAL, - name: '', - description: '', - color: '6d49ab', - creationTime: 1675887298557, - parentThreadID: '1', - members: [ - { - id: '256', - role: null, - permissions: { - know_of: { - value: true, - source: '1', - }, - membership: { - value: false, - source: null, - }, - visible: { - value: true, - source: '1', - }, - voiced: { - value: true, - source: '1', - }, - edit_entries: { - value: true, - source: '1', - }, - edit_thread: { - value: true, - source: '1', - }, - edit_thread_description: { - value: true, - source: '1', - }, - edit_thread_color: { - value: true, - source: '1', - }, - delete_thread: { - value: true, - source: '1', - }, - create_subthreads: { - value: true, - source: '1', - }, - create_sidebars: { - value: true, - source: '1', - }, - join_thread: { - value: true, - source: '1', - }, - edit_permissions: { - value: true, - source: '1', - }, - add_members: { - value: true, - source: '1', - }, - remove_members: { - value: true, - source: '1', - }, - change_role: { - value: true, - source: '1', - }, - leave_thread: { - value: false, - source: null, - }, - react_to_message: { - value: false, - source: null, - }, - edit_message: { - value: false, - source: null, - }, - manage_pins: { - value: true, - source: '1', - }, - }, - isSender: false, - }, - { - id: '83853', - role: '85172', - permissions: { - know_of: { - value: true, - source: '85171', - }, - membership: { - value: false, - source: null, - }, - visible: { - value: true, - source: '85171', - }, - voiced: { - value: true, - source: '85171', - }, - edit_entries: { - value: true, - source: '85171', - }, - edit_thread: { - value: true, - source: '85171', - }, - edit_thread_description: { - value: true, - source: '85171', - }, - edit_thread_color: { - value: true, - source: '85171', - }, - delete_thread: { - value: false, - source: null, - }, - create_subthreads: { - value: false, - source: null, - }, - create_sidebars: { - value: true, - source: '85171', - }, - join_thread: { - value: false, - source: null, - }, - edit_permissions: { - value: false, - source: null, - }, - add_members: { - value: false, - source: null, - }, - remove_members: { - value: false, - source: null, - }, - change_role: { - value: false, - source: null, - }, - leave_thread: { - value: false, - source: null, - }, - react_to_message: { - value: true, - source: '85171', - }, - edit_message: { - value: true, - source: '85171', - }, - manage_pins: { - value: false, - source: null, - }, - }, - isSender: true, - }, - ], - roles: { - '85172': { - id: '85172', - name: 'Members', - permissions: { - know_of: true, - visible: true, - voiced: true, - react_to_message: true, - edit_message: true, - edit_entries: true, - edit_thread: true, - edit_thread_color: true, - edit_thread_description: true, - create_sidebars: true, - descendant_open_know_of: true, - descendant_open_visible: true, - child_open_join_thread: true, - }, - isDefault: true, +const thread = { + id: '85171', + type: threadTypes.PERSONAL, + name: '', + description: '', + color: '6d49ab', + creationTime: 1675887298557, + parentThreadID: '1', + members: [ + { + id: '256', + role: null, + permissions: { + know_of: { + value: true, + source: '1', + }, + membership: { + value: false, + source: null, + }, + visible: { + value: true, + source: '1', + }, + voiced: { + value: true, + source: '1', + }, + edit_entries: { + value: true, + source: '1', + }, + edit_thread: { + value: true, + source: '1', + }, + edit_thread_description: { + value: true, + source: '1', + }, + edit_thread_color: { + value: true, + source: '1', + }, + delete_thread: { + value: true, + source: '1', + }, + create_subthreads: { + value: true, + source: '1', + }, + create_sidebars: { + value: true, + source: '1', + }, + join_thread: { + value: true, + source: '1', + }, + edit_permissions: { + value: true, + source: '1', + }, + add_members: { + value: true, + source: '1', + }, + remove_members: { + value: true, + source: '1', + }, + change_role: { + value: true, + source: '1', + }, + leave_thread: { + value: false, + source: null, + }, + react_to_message: { + value: false, + source: null, + }, + edit_message: { + value: false, + source: null, + }, + manage_pins: { + value: true, + source: '1', + }, }, + isSender: false, }, - currentUser: { + { + id: '83853', role: '85172', permissions: { know_of: { value: true, source: '85171', }, membership: { value: false, source: null, }, visible: { value: true, source: '85171', }, voiced: { value: true, source: '85171', }, edit_entries: { value: true, source: '85171', }, edit_thread: { value: true, source: '85171', }, edit_thread_description: { value: true, source: '85171', }, edit_thread_color: { value: true, source: '85171', }, delete_thread: { value: false, source: null, }, create_subthreads: { value: false, source: null, }, create_sidebars: { value: true, source: '85171', }, join_thread: { value: false, source: null, }, edit_permissions: { value: false, source: null, }, add_members: { value: false, source: null, }, remove_members: { value: false, source: null, }, change_role: { value: false, source: null, }, leave_thread: { value: false, source: null, }, react_to_message: { value: true, source: '85171', }, edit_message: { value: true, source: '85171', }, manage_pins: { value: false, source: null, }, }, - subscription: { - home: true, - pushNotifs: true, + isSender: true, + }, + ], + roles: { + '85172': { + id: '85172', + name: 'Members', + permissions: { + know_of: true, + visible: true, + voiced: true, + react_to_message: true, + edit_message: true, + edit_entries: true, + edit_thread: true, + edit_thread_color: true, + edit_thread_description: true, + create_sidebars: true, + descendant_open_know_of: true, + descendant_open_visible: true, + child_open_join_thread: true, }, - unread: false, + isDefault: true, }, - repliesCount: 0, - containingThreadID: '1', - community: '1', - pinnedCount: 0, - }; + }, + currentUser: { + role: '85172', + permissions: { + know_of: { + value: true, + source: '85171', + }, + membership: { + value: false, + source: null, + }, + visible: { + value: true, + source: '85171', + }, + voiced: { + value: true, + source: '85171', + }, + edit_entries: { + value: true, + source: '85171', + }, + edit_thread: { + value: true, + source: '85171', + }, + edit_thread_description: { + value: true, + source: '85171', + }, + edit_thread_color: { + value: true, + source: '85171', + }, + delete_thread: { + value: false, + source: null, + }, + create_subthreads: { + value: false, + source: null, + }, + create_sidebars: { + value: true, + source: '85171', + }, + join_thread: { + value: false, + source: null, + }, + edit_permissions: { + value: false, + source: null, + }, + add_members: { + value: false, + source: null, + }, + remove_members: { + value: false, + source: null, + }, + change_role: { + value: false, + source: null, + }, + leave_thread: { + value: false, + source: null, + }, + react_to_message: { + value: true, + source: '85171', + }, + edit_message: { + value: true, + source: '85171', + }, + manage_pins: { + value: false, + source: null, + }, + }, + subscription: { + home: true, + pushNotifs: true, + }, + unread: false, + }, + repliesCount: 0, + containingThreadID: '1', + community: '1', + pinnedCount: 0, +}; +describe('thread validation', () => { it('should validate correct thread', () => { expect(rawThreadInfoValidator.is(thread)).toBe(true); }); it('should not validate incorrect thread', () => { expect( rawThreadInfoValidator.is({ ...thread, creationTime: undefined }), ).toBe(false); }); }); -describe('entry validation', () => { - const entry = { - id: '92860', - threadID: '85068', - text: 'text', - year: 2023, - month: 4, - day: 2, - creationTime: 1682082939882, - creatorID: '83853', - deleted: false, - }; +const entry = { + id: '92860', + threadID: '85068', + text: 'text', + year: 2023, + month: 4, + day: 2, + creationTime: 1682082939882, + creatorID: '83853', + deleted: false, +}; +describe('entry validation', () => { it('should validate correct entry', () => { expect(rawEntryInfoValidator.is(entry)).toBe(true); }); it('should not validate incorrect entry', () => { expect(rawEntryInfoValidator.is({ ...entry, threadID: 0 })).toBe(false); }); }); + +describe('server update validation', () => { + const updates = [ + { + type: updateTypes.DELETE_ACCOUNT, + id: '98424', + time: 1640870111106, + deletedUserID: '98262', + }, + { + type: updateTypes.UPDATE_THREAD, + id: '97948', + time: 1640868525494, + threadInfo: thread, + }, + { + type: updateTypes.UPDATE_THREAD_READ_STATUS, + id: '98002', + time: 1640869373326, + threadID: '83794', + unread: true, + }, + { + type: updateTypes.DELETE_THREAD, + id: '98208', + time: 1640869773339, + threadID: '97852', + }, + { + type: updateTypes.JOIN_THREAD, + id: '98126', + time: 1640869494461, + threadInfo: thread, + rawMessageInfos: messages, + truncationStatus: 'exhaustive', + rawEntryInfos: [entry], + }, + { + type: updateTypes.BAD_DEVICE_TOKEN, + id: '98208', + time: 1640869773495, + deviceToken: 'some-device-token', + }, + { + type: updateTypes.UPDATE_ENTRY, + id: '98233', + time: 1640869844908, + entryInfo: entry, + }, + { + type: updateTypes.UPDATE_CURRENT_USER, + id: '98237', + time: 1640869934058, + currentUserInfo: { + id: '256', + username: 'ashoat', + }, + }, + { + type: updateTypes.UPDATE_USER, + id: '97988', + time: 1640869211822, + updatedUserID: '86565', + }, + ]; + + const validatorByUpdateType = { + [updateTypes.DELETE_ACCOUNT]: accountDeletionUpdateInfoValidator, + [updateTypes.UPDATE_THREAD]: threadUpdateInfoValidator, + [updateTypes.UPDATE_THREAD_READ_STATUS]: + threadReadStatusUpdateInfoValidator, + [updateTypes.DELETE_THREAD]: threadDeletionUpdateInfoValidator, + [updateTypes.JOIN_THREAD]: threadJoinUpdateInfoValidator, + [updateTypes.BAD_DEVICE_TOKEN]: badDeviceTokenUpdateInfoValidator, + [updateTypes.UPDATE_ENTRY]: entryUpdateInfoValidator, + [updateTypes.UPDATE_CURRENT_USER]: serverCurrentUserUpdateInfoValidator, + [updateTypes.UPDATE_USER]: userUpdateInfoValidator, + }; + + for (const validatorUpdateType in validatorByUpdateType) { + const validator = validatorByUpdateType[validatorUpdateType]; + const validatorUpdateTypeName = _findKey( + e => e === Number(validatorUpdateType), + )(updateTypes); + + for (const update of updates) { + const updateTypeName = _findKey(e => e === update.type)(updateTypes); + + if (Number(validatorUpdateType) === update.type) { + it(`${validatorUpdateTypeName} should validate ${updateTypeName}`, () => { + expect(validator.is(update)).toBe(true); + }); + } else { + it(`${validatorUpdateTypeName} shouldn't validate ${updateTypeName}`, () => { + expect(validator.is(update)).toBe(false); + }); + } + } + } +});