-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6b61ec6
commit 5074289
Showing
22 changed files
with
1,659 additions
and
578 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Binary file added
BIN
+2.64 KB
.yarn/cache/@types-deep-equal-in-any-order-npm-1.0.1-94ef7dc492-09a7620343.zip
Binary file not shown.
Binary file added
BIN
+2.85 KB
.yarn/cache/deep-equal-in-any-order-npm-1.1.20-9c0bb76c30-3fd4a57126.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
93 changes: 93 additions & 0 deletions
93
src/preference-management/checkIfPendingPreferenceUpdatesAreNoOp.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { | ||
PreferenceQueryResponseItem, | ||
PreferenceStorePurposeResponse, | ||
PreferenceTopicType, | ||
} from '@transcend-io/privacy-types'; | ||
import { PreferenceTopic } from '../graphql'; | ||
|
||
/** | ||
* Check if the pending set of updates are exactly the same as the current consent record. | ||
* | ||
* @param options - Options | ||
* @returns Whether the pending updates already exist in the preference store | ||
*/ | ||
export function checkIfPendingPreferenceUpdatesAreNoOp({ | ||
currentConsentRecord, | ||
pendingUpdates, | ||
preferenceTopics, | ||
}: { | ||
/** The current consent record */ | ||
currentConsentRecord: PreferenceQueryResponseItem; | ||
/** The pending updates */ | ||
pendingUpdates: { | ||
[purposeName in string]: Omit<PreferenceStorePurposeResponse, 'purpose'>; | ||
}; | ||
/** The preference topic configurations */ | ||
preferenceTopics: PreferenceTopic[]; | ||
}): boolean { | ||
// Check each update | ||
return Object.entries(pendingUpdates).every( | ||
([purposeName, { preferences = [], enabled }]) => { | ||
// Ensure the purpose exists | ||
const currentPurpose = currentConsentRecord.purposes.find( | ||
(existingPurpose) => existingPurpose.purpose === purposeName, | ||
); | ||
|
||
// Ensure purpose.enabled is in sync | ||
// Also false if the purpose does not exist | ||
const enabledIsInSync = | ||
!!currentPurpose && currentPurpose.enabled === enabled; | ||
if (!enabledIsInSync) { | ||
return false; | ||
} | ||
|
||
// Compare the preferences are in sync | ||
return preferences.every( | ||
({ topic, choice }) => | ||
// ensure preferences exist on record | ||
currentPurpose.preferences && | ||
currentPurpose.preferences.find((existingPreference) => { | ||
// find matching topic | ||
if (existingPreference.topic !== topic) { | ||
return false; | ||
} | ||
|
||
// Determine type of preference topic | ||
const preferenceTopic = preferenceTopics.find( | ||
(x) => x.slug === topic && x.purpose.trackingType === purposeName, | ||
); | ||
if (!preferenceTopic) { | ||
throw new Error(`Could not find preference topic for ${topic}`); | ||
} | ||
|
||
// Handle comparison based on type | ||
switch (preferenceTopic.type) { | ||
case PreferenceTopicType.Boolean: | ||
return ( | ||
existingPreference.choice.booleanValue === choice.booleanValue | ||
); | ||
case PreferenceTopicType.Select: | ||
return ( | ||
existingPreference.choice.selectValue === choice.selectValue | ||
); | ||
case PreferenceTopicType.MultiSelect: | ||
// eslint-disable-next-line no-case-declarations | ||
const sortedCurrentValues = ( | ||
existingPreference.choice.selectValues || [] | ||
).sort(); | ||
// eslint-disable-next-line no-case-declarations | ||
const sortedNewValues = (choice.selectValues || []).sort(); | ||
return ( | ||
sortedCurrentValues.length === sortedNewValues.length && | ||
sortedCurrentValues.every((x, i) => x === sortedNewValues[i]) | ||
); | ||
default: | ||
throw new Error( | ||
`Unknown preference topic type: ${preferenceTopic.type}`, | ||
); | ||
} | ||
}), | ||
); | ||
}, | ||
); | ||
} |
94 changes: 94 additions & 0 deletions
94
src/preference-management/checkIfPendingPreferenceUpdatesCauseConflict.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { | ||
PreferenceQueryResponseItem, | ||
PreferenceStorePurposeResponse, | ||
PreferenceTopicType, | ||
} from '@transcend-io/privacy-types'; | ||
import { PreferenceTopic } from '../graphql'; | ||
|
||
/** | ||
* Check if the pending set of updates will result in a change of | ||
* value to an existing purpose or preference in the preference store. | ||
* | ||
* @param options - Options | ||
* @returns True if conflict, false if no conflict and just adding new data for first time | ||
*/ | ||
export function checkIfPendingPreferenceUpdatesCauseConflict({ | ||
currentConsentRecord, | ||
pendingUpdates, | ||
preferenceTopics, | ||
}: { | ||
/** The current consent record */ | ||
currentConsentRecord: PreferenceQueryResponseItem; | ||
/** The pending updates */ | ||
pendingUpdates: { | ||
[purposeName in string]: Omit<PreferenceStorePurposeResponse, 'purpose'>; | ||
}; | ||
/** The preference topic configurations */ | ||
preferenceTopics: PreferenceTopic[]; | ||
}): boolean { | ||
// Check if any update has conflict | ||
return !!Object.entries(pendingUpdates).find( | ||
([purposeName, { preferences = [], enabled }]) => { | ||
// Ensure the purpose exists | ||
const currentPurpose = currentConsentRecord.purposes.find( | ||
(existingPurpose) => existingPurpose.purpose === purposeName, | ||
); | ||
|
||
// If no purpose exists, then it is not a conflict | ||
if (!currentPurpose) { | ||
return false; | ||
} | ||
|
||
// If purpose.enabled value is off, this is a conflict | ||
if (currentPurpose.enabled !== enabled) { | ||
return true; | ||
} | ||
|
||
// Check if any preferences are out of sync | ||
return !!preferences.find(({ topic, choice }) => { | ||
// find matching topic | ||
const currentPreference = (currentPurpose.preferences || []).find( | ||
(existingPreference) => existingPreference.topic === topic, | ||
); | ||
|
||
// if no topic exists, no conflict | ||
if (!currentPreference) { | ||
return false; | ||
} | ||
|
||
// Determine type of preference topic | ||
const preferenceTopic = preferenceTopics.find( | ||
(x) => x.slug === topic && x.purpose.trackingType === purposeName, | ||
); | ||
if (!preferenceTopic) { | ||
throw new Error(`Could not find preference topic for ${topic}`); | ||
} | ||
|
||
// Handle comparison based on type | ||
switch (preferenceTopic.type) { | ||
case PreferenceTopicType.Boolean: | ||
return ( | ||
currentPreference.choice.booleanValue !== choice.booleanValue | ||
); | ||
case PreferenceTopicType.Select: | ||
return currentPreference.choice.selectValue !== choice.selectValue; | ||
case PreferenceTopicType.MultiSelect: | ||
// eslint-disable-next-line no-case-declarations | ||
const sortedCurrentValues = ( | ||
currentPreference.choice.selectValues || [] | ||
).sort(); | ||
// eslint-disable-next-line no-case-declarations | ||
const sortedNewValues = (choice.selectValues || []).sort(); | ||
return ( | ||
sortedCurrentValues.length !== sortedNewValues.length || | ||
!sortedCurrentValues.every((x, i) => x === sortedNewValues[i]) | ||
); | ||
default: | ||
throw new Error( | ||
`Unknown preference topic type: ${preferenceTopic.type}`, | ||
); | ||
} | ||
}); | ||
}, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.