Skip to content

Adding consentStringType to amp-consent metadata#28028

Merged
micajuine-ho merged 11 commits intoampproject:masterfrom
micajuine-ho:consent_type
Jun 2, 2020
Merged

Adding consentStringType to amp-consent metadata#28028
micajuine-ho merged 11 commits intoampproject:masterfrom
micajuine-ho:consent_type

Conversation

@micajuine-ho
Copy link
Copy Markdown
Contributor

@micajuine-ho micajuine-ho commented Apr 24, 2020

Closes #27907

After adding consentMetadata object in #28187, we are now allowing that object to contain consentStringType field.

  • consentMetadata is accepted from checkConsentHref and the external iframe consent flow's response. Accepted values of consentStringType are 1, 2, and 3 (mapping will be defined in the amp-consent.md after all changes hit prod. For now see src/consent-state.js).
{
   "consentMetadata": {
      "consentStringType": 1
   }
}
  • consentMetadata will be sent as a ConsentMetadataDef as part of the checkConsentHref and onUpdateHref requests, as well as part of the ClientInfo sent to external iframe flow.
  • consentMetadata is only valid if accompanied by a consentString,
  • consentMetadata will get converted to a ConsentMetadataDef stored within ConsentInfo in memory, and sent to the Consent State Manager.
  • When the Consent State Manager stores the ConsentInfo to local storage, ConsentMetadataDef will also get stored within it using the METADATA_STORAGE_KEY:
{'s':1, 'r':'consent-string', 'm':{'cst':1}}
  • ConsentMetadataDef will be accessed internally through src/consent#getConsentMetadata(), via the Consent Policy Manager

@zhouyx
Copy link
Copy Markdown
Contributor

zhouyx commented Apr 24, 2020

Thank you for the PR description. Very helpful.
Before I start review, could you please explain the design around the following points.

  1. consentType is strictly related to consentString. If so how the code address the relationship between consentState, consentString and consentType with code.
  2. consentType always comes with the consentString value. Where and how can it be specified and retrieved? (Endpoint, API)
  3. Is the design backward compatible?

Thank you

@micajuine-ho
Copy link
Copy Markdown
Contributor Author

micajuine-ho commented Apr 25, 2020

@zhouyx Thanks for your questions.

consentType is strictly related to consentString. If so how the code address the relationship between consentState, consentString and consentType with code.

consentType and consentString values are:

  • gathered from the response from checkConsentHref (and potentially iframe post message, see comment above)
  • always get updated together via the consent manager
  • stored together in
    • local storage
    • in memory within the policy manager for the consent instance
  • both retrieved from the policy manager

consentType always comes with the consentString value. Where and how can it be specified and retrieved? (Endpoint, API)

  • Specified from checkConsentHref response (amp-consent#syncRemoteConsentState_() => amp-consent#updateCacheIfNotNull())
  • Potentially specified from iframe post message (see above)?
  • Retrieved from src/consent#getPolicyTypeInfo()

Is the design backward compatible?

Yes, we've only added fields, and if the field isn't present, no values will be stored in the policy manager or local storage. Once we consolidate the API to retrieve these values will change, but since they're all inhouse APIs we can make the necessary changes.

@zhouyx
Copy link
Copy Markdown
Contributor

zhouyx commented Apr 29, 2020

Thanks! Sounds good. One more question, looking at the code one could have consentString undefined but consentType defined. How are we going to handle such corner case?

@micajuine-ho
Copy link
Copy Markdown
Contributor Author

How are we going to handle such corner case?

@zhouyx As of now, the consentType would get updated, regardless of the undefined consentString. I think it's a fair to add the restriction that if consentString is undefined, then we should treat consentType as undefined as well (and update accordingly).

WDYT?

@zhouyx
Copy link
Copy Markdown
Contributor

zhouyx commented Apr 29, 2020

I think it's a fair to add the restriction that if consentString is undefined, then we should treat consentType as undefined as well (and update accordingly).

Sounds good. I think the same rule should be applied to gdprApplies as well.

@micajuine-ho
Copy link
Copy Markdown
Contributor Author

Sounds good. I think the same rule should be applied to gdprApplies as well.

@zhouyx Applied the fix (+ test). PTAL

@zhouyx
Copy link
Copy Markdown
Contributor

zhouyx commented Apr 29, 2020

To better address the map between consent string. What do you think about renaming the variable consent_string_type?

@micajuine-ho
Copy link
Copy Markdown
Contributor Author

What do you think about renaming the variable consent_string_type?

I think this will definitely help clarify the mapping.

@lgtm-com
Copy link
Copy Markdown

lgtm-com bot commented May 21, 2020

This pull request introduces 1 alert when merging 15fe60e into f92fb89 - view on LGTM.com

new alerts:

  • 1 for Invocation of non-function

@micajuine-ho micajuine-ho force-pushed the consent_type branch 4 times, most recently from 5f6e131 to b11a080 Compare May 26, 2020 16:28
@micajuine-ho micajuine-ho changed the title Adding CONSENT_TYPE for TCF_V2 support Adding consentStringType to amp-consent metadata May 26, 2020
@micajuine-ho
Copy link
Copy Markdown
Contributor Author

@zhouyx I have update the PR description so it accurately reflects the PR.

qq: Should src/consent getConsentMetadata() have a real closure type? And if so, do we create a new one in src/metadata-type or can we import from amp-consent/0.1/consent-info?

@zhouyx
Copy link
Copy Markdown
Contributor

zhouyx commented May 27, 2020

qq: Should src/consent getConsentMetadata() have a real closure type? And if so, do we create a new one in src/metadata-type or can we import from amp-consent/0.1/consent-info?

My understanding is the real closure type doesn't help much because we need to keep the key name of each field. (You can't minimize 'consentStringType' to 'c' during compilation).
Keeping in within the amp-consent component is reasonable, because it's not a global extern.

instance.update(CONSENT_ITEM_STATE.ACCEPTED, 'test', {});
yield macroTask();
expect(storageSetSpy).to.be.calledTwice;
instance.update(CONSENT_ITEM_STATE.ACCEPTED, 'test');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

metadata {} and undefined is different?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, consentMetadata from server response could be undefined and {} resulting in undefined or empty ConsentMetadataDef respectfully. Should we treat these as the same (akaundefined response generates an empty ConsentMetadataDef)?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depends on if undefined and {} will be treated differently by vendors, and in localStorage.
My understanding is that the two value (and even null) means the same thing.

Copy link
Copy Markdown
Contributor Author

@micajuine-ho micajuine-ho May 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok do you think it's fine if I leave it as is, incase vendor does need that distinction?

expect(requestBody.consentString).to.equal('old');
expect(requestBody.consentMetadata).to.be.undefined;
yield instance.update(CONSENT_ITEM_STATE.ACCEPTED, 'new', {});
yield instance.update(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with this since you've already added the metadata to the test.
However I also find it unnecessary with this unit test and many tests above. The test here is to specifically cover consentString change, in the spirit of unit test consentMetadata value should not affect the test.
Ideally the optional value consentMetadata will only be added to related tests to keep the unit tests clean.
To add test coverage: It's great to add more unit tests target consentMetadata functionalities. And add the value to the integration test case.

Copy link
Copy Markdown
Contributor Author

@micajuine-ho micajuine-ho May 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I will be more selective in the places where I test future metadata functionality.

It's great to add more unit tests target consentMetadata functionalities

Are there particular functionalities I am missing? I think most of the functionality is handled by test-consent-info.js

And add the value to the integration test case.

In our e2e tests, we check the blocking behavior and but not the local storage values. Should this be changed so that we can check for the correct metadata?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test coverage on functionalities looks good to me.

Please remind me, I think we didn't check local storage value for a reason.
We can add e2e test coverage once we expose API to get metadata. (or even use analytics variable substitution)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remind me, I think we didn't check local storage value for a reason.

We felt that e2e test was not the place to access localstorage, and instead relied upon outcome of test (blocked elements vs non-blocked) as the indicator of localstorage values. We also used analytics substitutions to verify as that was an end behavior of the test.

We have now have the exposed API and once we finish all the metadata value implementations, I will create e2e cases to test (#28634)

@ampproject ampproject deleted a comment from lgtm-com bot May 29, 2020
expect(requestBody.consentString).to.equal('old');
expect(requestBody.consentMetadata).to.be.undefined;
yield instance.update(CONSENT_ITEM_STATE.ACCEPTED, 'new', {});
yield instance.update(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test coverage on functionalities looks good to me.

Please remind me, I think we didn't check local storage value for a reason.
We can add e2e test coverage once we expose API to get metadata. (or even use analytics variable substitution)

instance.update(CONSENT_ITEM_STATE.ACCEPTED, 'test', {});
yield macroTask();
expect(storageSetSpy).to.be.calledTwice;
instance.update(CONSENT_ITEM_STATE.ACCEPTED, 'test');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depends on if undefined and {} will be treated differently by vendors, and in localStorage.
My understanding is that the two value (and even null) means the same thing.

*/

import {
CONSENT_STRING_TYPE, // eslint-disable-line no-unused-vars
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: You should be able to get rid of this by using {../../../src/consent-state.CONSENT_STRING_TYPE}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm I don't see this anywhere in the codebase and I get an error when I do this... Anywhere I can see an example of this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove the eslint comment. we no longer need it

@zhouyx
Copy link
Copy Markdown
Contributor

zhouyx commented Jun 1, 2020

#28028 (comment)

Ok do you think it's fine if I leave it as is, incase vendor does need that distinction?

I can't reply to the origin comment thread 😢 Reply here

Sure if vendor does need the distinction. The tradeoff here is one need to check for the metadata value before accessing any field.

const metaData = getMetaData();
if (metaData && metaData['something'])

I'm good with whatever vendors think works best for them.

@micajuine-ho
Copy link
Copy Markdown
Contributor Author

micajuine-ho commented Jun 1, 2020

I'm good with whatever vendors think works best for them.

Ok, I will follow up, and make changes if necessary.

Copy link
Copy Markdown
Contributor

@zhouyx zhouyx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Let's see if we can get rid of the eslint-disable-line. LGTM

*/

import {
CONSENT_STRING_TYPE, // eslint-disable-line no-unused-vars
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

@zhouyx zhouyx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with one nit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow CMPs to pass in CONSENT_TYPE

4 participants