diff --git a/lib/permissions/minimally-encoded-raw-thread-info-validators.js b/lib/permissions/minimally-encoded-raw-thread-info-validators.js index 48ac03cae..770f80c9f 100644 --- a/lib/permissions/minimally-encoded-raw-thread-info-validators.js +++ b/lib/permissions/minimally-encoded-raw-thread-info-validators.js @@ -1,122 +1,135 @@ // @flow import t, { type TInterface, type TUnion } from 'tcomb'; import { tHexEncodedPermissionsBitmask, tHexEncodedRolePermission, } from './minimally-encoded-thread-permissions.js'; import { specialRoleValidator } from './special-roles.js'; import type { MemberInfoWithPermissions, ThreadCurrentUserInfo, RawThreadInfo, RoleInfo, RoleInfoWithoutSpecialRole, RawThreadInfoWithoutSpecialRole, MinimallyEncodedThickMemberInfo, + MemberInfoSansPermissions, } from '../types/minimally-encoded-thread-permissions-types.js'; import { threadSubscriptionValidator } from '../types/subscription-types.js'; import { type LegacyRawThreadInfo, legacyMemberInfoValidator, legacyRawThreadInfoValidator, legacyThreadCurrentUserInfoValidator, } from '../types/thread-types.js'; import { tBool, tID, tShape, tUserID } from '../utils/validation-utils.js'; const threadCurrentUserInfoValidator: TInterface = tShape({ ...legacyThreadCurrentUserInfoValidator.meta.props, minimallyEncoded: tBool(true), permissions: tHexEncodedPermissionsBitmask, }); const roleInfoValidatorBase = { id: tID, name: t.String, minimallyEncoded: tBool(true), permissions: t.list(tHexEncodedRolePermission), }; const roleInfoValidator: TInterface = tShape({ ...roleInfoValidatorBase, specialRole: t.maybe(specialRoleValidator), }); type RoleInfoPossiblyWithIsDefaultField = $ReadOnly<{ ...RoleInfo, +isDefault?: boolean, }>; // This validator is to be used in `convertClientDBThreadInfoToRawThreadInfo` // which validates the persisted JSON blob BEFORE any migrations are run. // `roleInfoValidator` will fail for persisted `RoleInfo`s that include // the `isDefault` field. Figured it made sense to create a separate validator // instead of adding complexity to `roleInfoValidator` which should maintain // 1:1 correspondance with the `RoleInfo` type. const persistedRoleInfoValidator: TInterface = tShape({ id: tID, name: t.String, minimallyEncoded: tBool(true), permissions: t.list(tHexEncodedRolePermission), specialRole: t.maybe(specialRoleValidator), isDefault: t.maybe(t.Boolean), }); const memberInfoWithPermissionsValidator: TInterface = tShape({ ...legacyMemberInfoValidator.meta.props, minimallyEncoded: tBool(true), permissions: tHexEncodedPermissionsBitmask, }); +const memberInfoSansPermissionsValidator: TInterface = + tShape({ + id: tUserID, + role: t.maybe(tID), + isSender: t.Boolean, + minimallyEncoded: tBool(true), + }); + const minimallyEncodedThickMemberInfoValidator: TInterface = tShape({ minimallyEncoded: tBool(true), id: tUserID, role: t.maybe(tID), permissions: tHexEncodedPermissionsBitmask, isSender: t.Boolean, subscription: threadSubscriptionValidator, }); const rawThreadInfoValidator: TInterface = tShape( { ...legacyRawThreadInfoValidator.meta.props, minimallyEncoded: tBool(true), - members: t.list(memberInfoWithPermissionsValidator), + members: t.union([ + t.list(memberInfoWithPermissionsValidator), + t.list(memberInfoSansPermissionsValidator), + ]), roles: t.dict(tID, roleInfoValidator), currentUser: threadCurrentUserInfoValidator, }, ); const roleInfoWithoutSpecialRolesValidator: TInterface = tShape({ ...roleInfoValidatorBase, isDefault: t.maybe(t.Boolean), }); const rawThreadInfoWithoutSpecialRoles: TInterface = tShape({ ...rawThreadInfoValidator.meta.props, roles: t.dict(tID, roleInfoWithoutSpecialRolesValidator), }); const mixedRawThreadInfoValidator: TUnion< LegacyRawThreadInfo | RawThreadInfo | RawThreadInfoWithoutSpecialRole, > = t.union([ legacyRawThreadInfoValidator, rawThreadInfoValidator, rawThreadInfoWithoutSpecialRoles, ]); export { memberInfoWithPermissionsValidator, + memberInfoSansPermissionsValidator, minimallyEncodedThickMemberInfoValidator, roleInfoValidator, persistedRoleInfoValidator, threadCurrentUserInfoValidator, rawThreadInfoValidator, mixedRawThreadInfoValidator, }; diff --git a/lib/permissions/minimally-encoded-raw-thread-info-validators.test.js b/lib/permissions/minimally-encoded-raw-thread-info-validators.test.js new file mode 100644 index 000000000..01f77f781 --- /dev/null +++ b/lib/permissions/minimally-encoded-raw-thread-info-validators.test.js @@ -0,0 +1,30 @@ +// @flow + +import { memberInfoSansPermissionsValidator } from './minimally-encoded-raw-thread-info-validators.js'; + +describe('memberInfoSansPermissionsValidator should validate correctly formed MemberInfoSansPermissions', () => { + test('should validate correctly formed MemberInfoSansPermissions', () => { + const memberInfoSansPermissions = { + id: '1', + role: '2', + isSender: true, + minimallyEncoded: true, + }; + + expect( + memberInfoSansPermissionsValidator.is(memberInfoSansPermissions), + ).toBe(true); + }); + + test('should NOT validate MemberInfoSansPermissions without id', () => { + const memberInfoSansPermissions = { + role: '2', + isSender: true, + minimallyEncoded: true, + }; + + expect( + memberInfoSansPermissionsValidator.is(memberInfoSansPermissions), + ).toBe(false); + }); +});