Skip to content

Commit 9b399f8

Browse files
tvandorteastandwestwindgilluminate
authored
Fix opt out all essential. (#5850)
Co-authored-by: eastandwestwind <[email protected]> Co-authored-by: Jason Gill <[email protected]>
1 parent c0f3d2b commit 9b399f8

File tree

5 files changed

+233
-14
lines changed

5 files changed

+233
-14
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ Changes can also be flagged with a GitHub label for tracking purposes. The URL o
3535

3636
### Fixed
3737
- Corrected the Tag color for some columns of the Privacy requests table. [#5848](https://github.com/ethyca/fides/pull/5848)
38+
- Addressed TCModel console error when opting into some purposes [#5850](https://github.com/ethyca/fides/pull/5850)
39+
- Opt out of all in TCF no longer affects "notice only" notices [#5850](https://github.com/ethyca/fides/pull/5850)
40+
3841

3942
## [2.56.1](https://github.com/ethyca/fides/compare/2.56.0...2.56.1)
4043

clients/fides-js/src/components/tcf/TcfOverlay.tsx

+10-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useCallback, useEffect, useMemo, useState } from "preact/hooks";
77
import { FidesEvent } from "../../docs/fides-event";
88
import {
99
ButtonType,
10+
ConsentMechanism,
1011
ConsentMethod,
1112
PrivacyExperience,
1213
PrivacyExperienceMinimal,
@@ -343,6 +344,7 @@ export const TcfOverlay = ({
343344
enabledIds,
344345
});
345346
}
347+
// Creates consent prefs to save for custom purposes consent
346348
const consentPreferencesToSave = createConsentPreferencesToSave(
347349
privacyNoticesWithBestTranslation,
348350
enabledIds.customPurposesConsent,
@@ -437,12 +439,18 @@ export const TcfOverlay = ({
437439

438440
const handleRejectAll = useCallback(
439441
(wasAutomated?: boolean) => {
442+
// Notice-only custom purposes should not be rejected
443+
const enabledIds: EnabledIds = EMPTY_ENABLED_IDS;
444+
enabledIds.customPurposesConsent =
445+
privacyNoticesWithBestTranslation
446+
.filter((n) => n.consent_mechanism === ConsentMechanism.NOTICE_ONLY)
447+
.map((n) => n.id) ?? EMPTY_ENABLED_IDS;
440448
handleUpdateAllPreferences(
441449
wasAutomated ? ConsentMethod.SCRIPT : ConsentMethod.REJECT,
442-
EMPTY_ENABLED_IDS,
450+
enabledIds,
443451
);
444452
},
445-
[handleUpdateAllPreferences],
453+
[handleUpdateAllPreferences, privacyNoticesWithBestTranslation],
446454
);
447455

448456
useEffect(() => {

clients/fides-js/src/components/tcf/TcfPurposes.tsx

+17-4
Original file line numberDiff line numberDiff line change
@@ -178,18 +178,31 @@ const TcfPurposes = ({
178178
]
179179
: activeData.enabledPurposeIds
180180
}
181-
onToggle={(newEnabledIds, item, toggleDetails) =>
181+
onToggle={(newEnabledIds, item: RecordListItem, toggleDetails) => {
182+
let filteredEnabledIds = newEnabledIds;
183+
if (item.bestTranslation) {
184+
// filter out tcf purpose consent since we are just dealing with custom purposes
185+
filteredEnabledIds = newEnabledIds.filter(
186+
(id) => !activeData.enabledPurposeIds.includes(id),
187+
);
188+
} else if (activeData.enabledCustomPurposeIds) {
189+
/// filter out custom purpose consent since we are just dealing with TCF purposes
190+
filteredEnabledIds = newEnabledIds.filter(
191+
(id) => !activeData.enabledCustomPurposeIds?.includes(id),
192+
);
193+
}
194+
182195
onChange(
183196
{
184-
newEnabledIds,
197+
newEnabledIds: filteredEnabledIds,
185198
// @ts-ignore
186199
modelType: item.bestTranslation
187200
? "customPurposesConsent"
188201
: activeData.purposeModelType,
189202
},
190203
toggleDetails,
191-
)
192-
}
204+
);
205+
}}
193206
renderToggleChild={(p, isCustomPurpose) => (
194207
<PurposeDetails
195208
type="purposes"

clients/fides-js/src/lib/tcf/utils.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ export const createTcfSavePayloadFromMinExp = ({
445445
*
446446
* @param oldCookie - The old Fides cookie.
447447
* @param tcf - The TCF save preferences representing the data sent to the backend.
448-
* @param enabledIds - The user's enabled IDs.
448+
* @param enabledIds - The user's enabled IDs. This could include both TCF and custom enabled IDs
449449
* @param experience - The full privacy experience.
450450
* @param consentPreferencesToSave - Any Custom Notice preferences to save.
451451
* @returns A promise that resolves to the updated Fides cookie.

clients/privacy-center/cypress/e2e/consent-banner-tcf-custom-notices.cy.ts

+202-7
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ describe("Fides-js TCF", () => {
566566
.is.eql(false);
567567
expect(cookieKeyConsent.consent)
568568
.property(PRIVACY_NOTICE_KEY_2)
569-
.is.eql(false);
569+
.is.eql(true);
570570
expect(cookieKeyConsent.consent)
571571
.property(PRIVACY_NOTICE_KEY_3)
572572
.is.eql(false);
@@ -1129,7 +1129,7 @@ describe("Fides-js TCF", () => {
11291129
.is.eql(false);
11301130
expect(cookieKeyConsent.consent)
11311131
.property(PRIVACY_NOTICE_KEY_2)
1132-
.is.eql(false);
1132+
.is.eql(true);
11331133
expect(cookieKeyConsent.consent)
11341134
.property(PRIVACY_NOTICE_KEY_3)
11351135
.is.eql(false);
@@ -1144,10 +1144,179 @@ describe("Fides-js TCF", () => {
11441144
});
11451145
});
11461146

1147-
// DEFER: can probably be removed
1148-
it.skip("can opt in to some and opt out of others", () => {
1149-
// todo- opt in to 1 custom notice, then test cookie and window.Fides obj
1147+
it("can opt in to some custom consent and some tcf consent", () => {
1148+
cy.getByTestId("consent-modal").within(() => {
1149+
// Custom notice should start off toggled off
1150+
cy.getByTestId("toggle-Advertising English").within(() => {
1151+
cy.get("input").should("not.be.checked");
1152+
});
1153+
// Opt-out notice should start toggled on
1154+
cy.getByTestId("toggle-Analytics").within(() => {
1155+
cy.get("input").should("be.checked");
1156+
});
1157+
// Notice-only should start off toggled on
1158+
cy.getByTestId("toggle-Essential").within(() => {
1159+
cy.get("input").should("be.checked");
1160+
});
1161+
// opt in to opt-in custom notice
1162+
cy.getByTestId(`toggle-Advertising English`).click();
1163+
// opt in to purpose 4
1164+
cy.getByTestId(`toggle-${PURPOSE_4.name}`).click();
1165+
cy.get("#fides-tab-features").click();
1166+
// opt in to special feat 1
1167+
cy.getByTestId(`toggle-${SPECIAL_FEATURE_1.name}`).click();
1168+
1169+
cy.get("#fides-tab-vendors").click();
1170+
cy.get("#fides-panel-vendors").within(() => {
1171+
cy.get("button").contains("Legitimate interest").click();
1172+
});
1173+
// opt out of system 1 (default is opt-in)
1174+
cy.getByTestId(`toggle-${SYSTEM_1.name}`).click();
1175+
cy.get("button").contains("Save").click();
1176+
cy.get("@FidesUIChanged").its("callCount").should("equal", 4);
1177+
cy.wait("@patchPrivacyPreference").then((interception) => {
1178+
const { body } = interception.request;
1179+
expect(interception.request.body.method).to.eql(ConsentMethod.SAVE);
1180+
expect(body.preferences).to.eql([
1181+
{
1182+
preference: "opt_in",
1183+
privacy_notice_history_id:
1184+
"pri_notice-history-advertising-en-000",
1185+
},
1186+
{
1187+
preference: "opt_in",
1188+
privacy_notice_history_id:
1189+
"pri_notice-history-analytics-en-000",
1190+
},
1191+
{
1192+
preference: "acknowledge",
1193+
privacy_notice_history_id:
1194+
"pri_notice-history-essential-en-000",
1195+
},
1196+
]);
1197+
expect(body.purpose_consent_preferences).to.eql([
1198+
{
1199+
id: PURPOSE_4.id,
1200+
preference: "opt_in",
1201+
},
1202+
{
1203+
id: PURPOSE_6.id,
1204+
preference: "opt_out",
1205+
},
1206+
{
1207+
id: PURPOSE_7.id,
1208+
preference: "opt_out",
1209+
},
1210+
{
1211+
id: PURPOSE_9.id,
1212+
preference: "opt_out",
1213+
},
1214+
]);
1215+
expect(body.purpose_legitimate_interests_preferences).to.eql([
1216+
{
1217+
id: PURPOSE_2.id,
1218+
preference: "opt_in",
1219+
},
1220+
]);
1221+
expect(body.special_purpose_preferences).to.eql(undefined);
1222+
expect(body.feature_preferences).to.eql(undefined);
1223+
expect(body.special_feature_preferences).to.eql([
1224+
{
1225+
id: SPECIAL_FEATURE_1.id,
1226+
preference: "opt_in",
1227+
},
1228+
]);
1229+
expect(body.vendor_consent_preferences).to.eql([
1230+
{
1231+
id: VENDOR_1.id,
1232+
preference: "opt_out",
1233+
},
1234+
]);
1235+
expect(body.vendor_legitimate_interests_preferences).to.eql([]);
1236+
expect(body.system_legitimate_interests_preferences).to.eql([
1237+
{
1238+
id: SYSTEM_1.id,
1239+
preference: "opt_out",
1240+
},
1241+
]);
1242+
expect(body.system_consent_preferences).to.eql([]);
1243+
});
1244+
});
1245+
// Verify the cookie on save
1246+
cy.getCookie(CONSENT_COOKIE_NAME).then((cookie) => {
1247+
const cookieKeyConsent: FidesCookie = JSON.parse(
1248+
decodeURIComponent(cookie!.value),
1249+
);
1250+
expect(cookieKeyConsent.fides_meta.consentMethod).to.eql(
1251+
ConsentMethod.SAVE,
1252+
);
1253+
expect(cookieKeyConsent.consent)
1254+
.property(PRIVACY_NOTICE_KEY_1)
1255+
.is.eql(true);
1256+
expect(cookieKeyConsent.consent)
1257+
.property(PRIVACY_NOTICE_KEY_2)
1258+
.is.eql(true);
1259+
expect(cookieKeyConsent.consent)
1260+
.property(PRIVACY_NOTICE_KEY_3)
1261+
.is.eql(true);
1262+
assertTcOptIns({
1263+
cookie: cookieKeyConsent,
1264+
modelType: "purposeConsents",
1265+
ids: [PURPOSE_4.id],
1266+
});
1267+
assertTcOptIns({
1268+
cookie: cookieKeyConsent,
1269+
modelType: "purposeLegitimateInterests",
1270+
ids: [PURPOSE_2.id],
1271+
});
1272+
assertTcOptIns({
1273+
cookie: cookieKeyConsent,
1274+
modelType: "specialFeatureOptins",
1275+
ids: [SPECIAL_FEATURE_1.id],
1276+
});
1277+
assertTcOptIns({
1278+
cookie: cookieKeyConsent,
1279+
modelType: "vendorConsents",
1280+
ids: [],
1281+
});
1282+
assertTcOptIns({
1283+
cookie: cookieKeyConsent,
1284+
modelType: "vendorLegitimateInterests",
1285+
ids: [],
1286+
});
1287+
expect(
1288+
cookieKeyConsent.tcf_consent
1289+
.system_legitimate_interests_preferences,
1290+
)
1291+
.property(`${SYSTEM_1.id}`)
1292+
.is.eql(false);
1293+
expect(
1294+
cookieKeyConsent.tcf_consent.system_consent_preferences,
1295+
).to.eql({});
1296+
// Confirm vendors_disclosed section does not exist
1297+
expect(cookieKeyConsent.fides_string).to.not.contain(
1298+
vendorsDisclosed,
1299+
);
1300+
});
1301+
});
1302+
1303+
it("can opt out of some custom consent and some tcf consent", () => {
11501304
cy.getByTestId("consent-modal").within(() => {
1305+
// Custom notice should start off toggled off
1306+
cy.getByTestId("toggle-Advertising English").within(() => {
1307+
cy.get("input").should("not.be.checked");
1308+
});
1309+
// Opt-out notice should start toggled on
1310+
cy.getByTestId("toggle-Analytics").within(() => {
1311+
cy.get("input").should("be.checked");
1312+
});
1313+
cy.getByTestId("toggle-Advertising English").click();
1314+
// Notice-only should start off toggled on
1315+
cy.getByTestId("toggle-Essential").within(() => {
1316+
cy.get("input").should("be.checked");
1317+
});
1318+
// opt out to opt-out custom notice
1319+
cy.getByTestId(`toggle-Analytics`).click();
11511320
// opt in to purpose 4
11521321
cy.getByTestId(`toggle-${PURPOSE_4.name}`).click();
11531322
cy.get("#fides-tab-features").click();
@@ -1161,10 +1330,27 @@ describe("Fides-js TCF", () => {
11611330
// opt out of system 1 (default is opt-in)
11621331
cy.getByTestId(`toggle-${SYSTEM_1.name}`).click();
11631332
cy.get("button").contains("Save").click();
1164-
cy.get("@FidesUIChanged").its("callCount").should("equal", 3);
1333+
cy.get("@FidesUIChanged").its("callCount").should("equal", 5);
11651334
cy.wait("@patchPrivacyPreference").then((interception) => {
11661335
const { body } = interception.request;
11671336
expect(interception.request.body.method).to.eql(ConsentMethod.SAVE);
1337+
expect(body.preferences).to.eql([
1338+
{
1339+
preference: "opt_in",
1340+
privacy_notice_history_id:
1341+
"pri_notice-history-advertising-en-000",
1342+
},
1343+
{
1344+
preference: "opt_out",
1345+
privacy_notice_history_id:
1346+
"pri_notice-history-analytics-en-000",
1347+
},
1348+
{
1349+
preference: "acknowledge",
1350+
privacy_notice_history_id:
1351+
"pri_notice-history-essential-en-000",
1352+
},
1353+
]);
11681354
expect(body.purpose_consent_preferences).to.eql([
11691355
{
11701356
id: PURPOSE_4.id,
@@ -1221,6 +1407,15 @@ describe("Fides-js TCF", () => {
12211407
expect(cookieKeyConsent.fides_meta.consentMethod).to.eql(
12221408
ConsentMethod.SAVE,
12231409
);
1410+
expect(cookieKeyConsent.consent)
1411+
.property(PRIVACY_NOTICE_KEY_1)
1412+
.is.eql(true);
1413+
expect(cookieKeyConsent.consent)
1414+
.property(PRIVACY_NOTICE_KEY_2)
1415+
.is.eql(true);
1416+
expect(cookieKeyConsent.consent)
1417+
.property(PRIVACY_NOTICE_KEY_3)
1418+
.is.eql(false);
12241419
assertTcOptIns({
12251420
cookie: cookieKeyConsent,
12261421
modelType: "purposeConsents",
@@ -2653,7 +2848,7 @@ describe("Fides-js TCF", () => {
26532848
const { body } = interception.request;
26542849
expect(body.preferences[0].preference).to.eql("opt_out");
26552850
expect(body.preferences[1].preference).to.eql("opt_out");
2656-
expect(body.preferences[2].preference).to.eql("opt_out");
2851+
expect(body.preferences[2].preference).to.eql("acknowledge"); // notice-only
26572852
// check a few to see they are empty arrays
26582853
expect(body.purpose_consent_preferences).to.eql([]);
26592854
expect(body.purpose_legitimate_interests_preferences).to.eql([]);

0 commit comments

Comments
 (0)