-
Notifications
You must be signed in to change notification settings - Fork 7
fix(datatrak): RN-1819: detect descendant changes in permission group hierarchy #6708
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
7a02cd0
ef61d47
c110624
d4ddecb
96de25e
d8542cd
291aa7c
5f0f58b
54323c0
c95e34d
c1a1ec2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| import { type BaseDatabase, RECORDS } from '@tupaia/database'; | ||
| import type { UserAccount } from '@tupaia/types'; | ||
| import { getSnapshotTableName } from './manageSnapshotTable'; | ||
|
|
||
| /** | ||
| * Returns `true` if the sync snapshot for `sessionId` includes a change to a descendant of a | ||
| * permission_group the user already has access to. Does not detect new `permission_group`s granted | ||
| * to the user via `user_entity_permission`. | ||
| */ | ||
| export const hasDescendantPermissionChangeInSnapshot = async ( | ||
| database: BaseDatabase, | ||
| sessionId: string, | ||
| userId: UserAccount['id'], | ||
| ): Promise<boolean> => { | ||
| const snapshotTable = getSnapshotTableName(sessionId); | ||
|
|
||
| /** | ||
| * @privateRemarks `max(depth)` is tree height, plus headroom to account for tree height | ||
| * increasing since last sync. Choice of 10 is arbitrary. | ||
| */ | ||
| const maxDepth = database.connection.raw( | ||
| `( | ||
| WITH RECURSIVE tree AS ( | ||
| SELECT id, parent_id, 1 AS depth | ||
| FROM permission_group | ||
| WHERE parent_id IS NULL | ||
|
|
||
| UNION ALL | ||
|
|
||
| SELECT pg.id, pg.parent_id, t.depth + 1 | ||
| FROM permission_group pg | ||
| INNER JOIN tree t ON pg.parent_id = t.id | ||
| ) | ||
| SELECT max(depth) + :headroom AS height | ||
| FROM tree | ||
|
Comment on lines
+23
to
+35
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As of today, the maximum permission group tree height is 7 |
||
| )`, | ||
| { headroom: 10 }, | ||
| ); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Raw builder object used as named binding valueHigh Severity
Additional Locations (1)Reviewed by Cursor Bugbot for commit c1a1ec2. Configure here. |
||
|
|
||
| const [{ matches }] = await database.executeSql<[{ matches: boolean }]>( | ||
| ` | ||
| WITH RECURSIVE user_perm AS ( | ||
| SELECT DISTINCT permission_group_id | ||
| FROM user_entity_permission | ||
| WHERE user_id = :userId | ||
| ), | ||
| walk AS ( | ||
| SELECT DISTINCT (s.data ->> 'id') AS current_id, 0 AS depth | ||
| FROM ${snapshotTable} s | ||
| WHERE s.record_type = :recordType | ||
|
|
||
| UNION | ||
|
|
||
| SELECT pl.parent_id, w.depth + 1 | ||
| FROM walk w | ||
| INNER JOIN LATERAL ( | ||
| SELECT | ||
| coalesce( | ||
| (SELECT pg.parent_id FROM permission_group pg WHERE pg.id = w.current_id), | ||
| ( | ||
| SELECT NULLIF (s2.data ->> 'parent_id', '') | ||
| FROM ${snapshotTable} s2 | ||
| WHERE s2.record_type = :recordType AND s2.data ->> 'id' = w.current_id | ||
| LIMIT 1 | ||
| ) | ||
| ) AS parent_id | ||
| ) pl ON pl.parent_id IS NOT NULL | ||
| WHERE w.depth < :maxDepth | ||
| ) | ||
|
|
||
| SELECT EXISTS ( | ||
| SELECT 1 | ||
| FROM walk w | ||
| INNER JOIN user_perm u ON u.permission_group_id = w.current_id | ||
| ) AS matches | ||
| `, | ||
| { | ||
| userId, | ||
| recordType: RECORDS.PERMISSION_GROUP, | ||
| maxDepth, | ||
| }, | ||
| ); | ||
|
|
||
| return matches; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,16 @@ | ||
| export * from './waitForPendingEditsUsingSyncTick'; | ||
| export * from './bumpSyncTickForRepull'; | ||
| export * from './completeSyncSession'; | ||
| export * from './countSyncSnapshotRecords'; | ||
| export * from './findLastSuccessfulSyncedProjects'; | ||
| export * from './getDependencyOrder'; | ||
| export * from './getModelsForDirection'; | ||
| export * from './getSyncTicksOfPendingEdits'; | ||
| export { hasDescendantPermissionChangeInSnapshot } from './hasDescendantPermissionChangeInSnapshot'; | ||
|
jaskfla marked this conversation as resolved.
|
||
| export * from './incomingSyncHook'; | ||
| export * from './logMemory'; | ||
| export * from './manageSnapshotTable'; | ||
| export * from './countSyncSnapshotRecords'; | ||
| export * from './getDependencyOrder'; | ||
| export * from './saveIncomingChanges'; | ||
| export * from './completeSyncSession'; | ||
| export * from './sanitizeRecord'; | ||
| export * from './saveIncomingChanges'; | ||
| export * from './startSnapshotWhenCapacityAvailable'; | ||
| export * from './waitForPendingEditsUsingSyncTick'; | ||
| export * from './withDeferredSyncSafeguards'; | ||
| export * from './findLastSuccessfulSyncedProjects'; | ||
| export * from './incomingSyncHook'; | ||
| export * from './bumpSyncTickForRepull'; | ||
| export * from './logMemory'; | ||


Uh oh!
There was an error while loading. Please reload this page.