From dc24c82f4bb8573dc8ea8cee05b4731f199735d6 Mon Sep 17 00:00:00 2001 From: Atul Madhugiri Date: Mon, 6 Nov 2023 17:01:41 -0500 Subject: [PATCH] [lib] Introduce `MinimallyEncodedThreadCurrentUserInfo` and validator Summary: `ThreadCurrentUserInfo` type w/ `permissions` as string instead of `ThreadPermissions`. Next diffs: - Introduce `MinimallyEncodedRawThreadInfo` - Higher level utilities for translating back/forth from `RawThreadInfo` <=> `MinimallyEncodedRawThreadInfo`. Found this to be cleaner API than encoding/decoding `RawThreadInfo.currentUser.permissions` and `RawThreadInfo.members[memberID].permissions` "manually" a bunch of different places. - Native refactoring + migrations - Web refactoring - Flipping the switch --- Depends on D9731 Test Plan: Unit tests, will be tested implicitly in subsequent diffs as well. Reviewers: ashoat, rohan, ginsu, tomek Reviewed By: ashoat Subscribers: ashoat, tomek, wyilio Differential Revision: https://phab.comm.dev/D9734 --- .../minimally-encoded-thread-permissions.js | 20 ++++++++- ...nimally-encoded-thread-permissions.test.js | 41 +++++++++++++++++++ lib/types/thread-types.js | 13 +++--- 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/lib/permissions/minimally-encoded-thread-permissions.js b/lib/permissions/minimally-encoded-thread-permissions.js index 7ca586a1de..e93d343324 100644 --- a/lib/permissions/minimally-encoded-thread-permissions.js +++ b/lib/permissions/minimally-encoded-thread-permissions.js @@ -9,8 +9,11 @@ import type { ThreadPermissionsInfo, ThreadRolePermissionsBlob, } from '../types/thread-permission-types.js'; -import type { RoleInfo } from '../types/thread-types.js'; -import { roleInfoValidator } from '../types/thread-types.js'; +import type { RoleInfo, ThreadCurrentUserInfo } from '../types/thread-types.js'; +import { + roleInfoValidator, + threadCurrentUserInfoValidator, +} from '../types/thread-types.js'; import { entries, invertObjectToMap } from '../utils/objects.js'; import { tRegex, tShape } from '../utils/validation-utils.js'; import type { TRegex } from '../utils/validation-utils.js'; @@ -196,6 +199,18 @@ const minimallyEncodedRoleInfoValidator: TInterface = permissions: t.list(tHexEncodedRolePermission), }); +export type MinimallyEncodedThreadCurrentUserInfo = { + ...ThreadCurrentUserInfo, + +permissions: string, +}; + +const tHexEncodedPermissionsBitmask: TRegex = tRegex(/^[0-9a-fA-F]+$/); +const minimallyEncodedThreadCurrentUserInfoValidator: TInterface = + tShape({ + ...threadCurrentUserInfoValidator.meta.props, + permissions: tHexEncodedPermissionsBitmask, + }); + export { permissionsToBitmaskHex, hasPermission, @@ -204,4 +219,5 @@ export { threadRolePermissionsBlobToBitmaskArray, decodeThreadRolePermissionsBitmaskArray, minimallyEncodedRoleInfoValidator, + minimallyEncodedThreadCurrentUserInfoValidator, }; diff --git a/lib/permissions/minimally-encoded-thread-permissions.test.js b/lib/permissions/minimally-encoded-thread-permissions.test.js index cdced14b78..8d68e5c872 100644 --- a/lib/permissions/minimally-encoded-thread-permissions.test.js +++ b/lib/permissions/minimally-encoded-thread-permissions.test.js @@ -5,6 +5,7 @@ import { decodeThreadRolePermissionsBitmaskArray, hasPermission, minimallyEncodedRoleInfoValidator, + minimallyEncodedThreadCurrentUserInfoValidator, permissionsToBitmaskHex, rolePermissionToBitmaskHex, threadRolePermissionsBlobToBitmaskArray, @@ -282,3 +283,43 @@ describe('minimallyEncodedRoleInfoValidator', () => { ).toBe(false); }); }); + +describe('minimallyEncodedThreadCurrentUserInfoValidator', () => { + it('should validate correctly formed MinimallyEncodedThreadCurrentUserInfo', () => { + expect( + minimallyEncodedThreadCurrentUserInfoValidator.is({ + permissions: '100', + subscription: { home: true, pushNotifs: true }, + }), + ).toBe(true); + expect( + minimallyEncodedThreadCurrentUserInfoValidator.is({ + permissions: 'ABCDEFABCDEFABCD', + subscription: { home: true, pushNotifs: true }, + }), + ).toBe(true); + }); + + it('should NOT validate malformed MinimallyEncodedThreadCurrentUserInfo', () => { + expect( + minimallyEncodedThreadCurrentUserInfoValidator.is({ + permissions: 'INVALID', + subscription: { home: true, pushNotifs: true }, + }), + ).toBe(false); + + expect( + minimallyEncodedThreadCurrentUserInfoValidator.is({ + permissions: 'ABCDEF hello ABCDEFABCD', + subscription: { home: true, pushNotifs: true }, + }), + ).toBe(false); + + expect( + minimallyEncodedThreadCurrentUserInfoValidator.is({ + permissions: 100, + subscription: { home: true, pushNotifs: true }, + }), + ).toBe(false); + }); +}); diff --git a/lib/types/thread-types.js b/lib/types/thread-types.js index 2eef807bb1..7b77be6692 100644 --- a/lib/types/thread-types.js +++ b/lib/types/thread-types.js @@ -78,12 +78,13 @@ export type ThreadCurrentUserInfo = { +subscription: ThreadSubscription, +unread: ?boolean, }; -const threadCurrentUserInfoValidator = tShape({ - role: t.maybe(tID), - permissions: threadPermissionsInfoValidator, - subscription: threadSubscriptionValidator, - unread: t.maybe(t.Boolean), -}); +export const threadCurrentUserInfoValidator: TInterface = + tShape({ + role: t.maybe(tID), + permissions: threadPermissionsInfoValidator, + subscription: threadSubscriptionValidator, + unread: t.maybe(t.Boolean), + }); export type RawThreadInfo = { +id: string,