Skip to content

Commit

Permalink
✨amp-o2-player add handling consent data (ampproject#31005)
Browse files Browse the repository at this point in the history
* amp-o2-player add handling consent data

* am-o2-player added blank comment

* amp-o2 blank comment
  • Loading branch information
lironka authored and ed-bird committed Dec 10, 2020
1 parent 9b1111a commit 966de3b
Show file tree
Hide file tree
Showing 3 changed files with 285 additions and 1 deletion.
96 changes: 96 additions & 0 deletions extensions/amp-o2-player/0.1/amp-o2-player.js
Expand Up @@ -14,9 +14,16 @@
* limitations under the License.
*/

import {CONSENT_POLICY_STATE} from '../../../src/consent-state';
import {MessageType} from '../../../src/3p-frame-messaging';
import {Services} from '../../../src/services';
import {dict} from '../../../src/utils/object';
import {
getConsentPolicyInfo,
getConsentPolicyState,
} from '../../../src/consent';
import {isLayoutSizeDefined} from '../../../src/layout';
import {listenFor} from '../../../src/iframe-helper';
import {setIsMediaComponent} from '../../../src/video-interface';
import {userAssert} from '../../../src/log';

Expand Down Expand Up @@ -123,10 +130,99 @@ class AmpO2Player extends AMP.BaseElement {
iframe.src = this.src_;
this.iframe_ = /** @type {HTMLIFrameElement} */ (iframe);
this.applyFillContent(iframe);

listenFor(iframe, MessageType.SEND_CONSENT_DATA, (data, source, origin) => {
this.sendConsentData_(source, origin);
});

this.element.appendChild(iframe);
return this.loadPromise(iframe);
}

/**
* Requests consent data from consent module
* and forwards information to iframe
* @param {Window} source
* @param {string} origin
* @private
*/
sendConsentData_(source, origin) {
const consentPolicyId = super.getConsentPolicy() || 'default';
const consentStringPromise = this.getConsentString_(consentPolicyId);
const consentPolicyStatePromise = this.getConsentPolicyState_(
consentPolicyId
);

Promise.all([consentPolicyStatePromise, consentStringPromise]).then(
(consents) => {
let consentData;
switch (consents[0]) {
case CONSENT_POLICY_STATE.SUFFICIENT:
consentData = {
'gdprApplies': true,
'user_consent': 1,
'gdprString': consents[1],
};
break;
case CONSENT_POLICY_STATE.INSUFFICIENT:
case CONSENT_POLICY_STATE.UNKNOWN:
consentData = {
'gdprApplies': true,
'user_consent': 0,
'gdprString': consents[1],
};
break;
case CONSENT_POLICY_STATE.UNKNOWN_NOT_REQUIRED:
default:
consentData = {
'gdprApplies': false,
};
}

this.sendConsentDataToIframe_(
source,
origin,
dict({
'sentinel': 'amp',
'type': MessageType.CONSENT_DATA,
'consentData': consentData,
})
);
}
);
}

/**
* Send consent data to iframe
* @param {Window} source
* @param {string} origin
* @param {JsonObject} data
* @private
*/
sendConsentDataToIframe_(source, origin, data) {
source./*OK*/ postMessage(data, origin);
}

/**
* Get the consent string
* @param {string} consentPolicyId
* @private
* @return {Promise}
*/
getConsentString_(consentPolicyId = 'default') {
return getConsentPolicyInfo(this.element, consentPolicyId);
}

/**
* Get the consent policy state
* @param {string} consentPolicyId
* @private
* @return {Promise}
*/
getConsentPolicyState_(consentPolicyId = 'default') {
return getConsentPolicyState(this.element, consentPolicyId);
}

/** @override */
pauseCallback() {
if (this.iframe_ && this.iframe_.contentWindow) {
Expand Down
153 changes: 152 additions & 1 deletion extensions/amp-o2-player/0.1/test/test-amp-o2-player.js
Expand Up @@ -15,6 +15,9 @@
*/

import '../amp-o2-player';
import * as iframeHelper from '../../../../src/iframe-helper';
import {CONSENT_POLICY_STATE} from '../../../../src/consent-state';
import {MessageType} from '../../../../src/3p-frame-messaging';

describes.realWin(
'amp-o2-player',
Expand All @@ -31,7 +34,7 @@ describes.realWin(
doc = win.document;
});

async function getO2player(attributes, opt_responsive) {
async function getO2player(attributes, opt_responsive, implExtends) {
const o2 = doc.createElement('amp-o2-player');
for (const key in attributes) {
o2.setAttribute(key, attributes[key]);
Expand All @@ -42,6 +45,10 @@ describes.realWin(
o2.setAttribute('layout', 'responsive');
}
doc.body.appendChild(o2);

if (implExtends) {
implExtends(o2);
}
await o2.build();
await o2.layoutCallback();
return o2;
Expand Down Expand Up @@ -143,5 +150,149 @@ describes.realWin(
'https://delivery.dev.vidible.tv/htmlembed/pid=123/456.html'
);
});

describe('sends a consent-data', () => {
let sendConsentDataToIframe;
const resSource = 'my source';
const resOrigin = 'my origin';
const resConsentString = 'consent string';
let consentData = {
'gdprApplies': true,
'user_consent': 1,
'gdprString': resConsentString,
};
const resData = {
sentinel: 'amp',
type: MessageType.CONSENT_DATA,
};

it('sends a consent-data CONSENT_POLICY_STATE.SUFFICIENT message', async function () {
resData.consentData = consentData;

const implExtends = function (o2) {
env.sandbox
.stub(o2.implementation_, 'getConsentString_')
.resolves(resConsentString);

env.sandbox
.stub(o2.implementation_, 'getConsentPolicyState_')
.resolves(CONSENT_POLICY_STATE.SUFFICIENT);

sendConsentDataToIframe = env.sandbox.spy(
o2.implementation_,
'sendConsentDataToIframe_'
);
};

env.sandbox
.stub(iframeHelper, 'listenFor')
.callsFake((iframe, message, callback) => {
expect(message).to.equal(MessageType.SEND_CONSENT_DATA);
callback('', resSource, resOrigin);
});

await getO2player(
{
'data-pid': '123',
'data-bcid': '456',
},
null,
implExtends
);

expect(sendConsentDataToIframe).to.have.been.calledWith(
resSource,
resOrigin,
resData
);
});

it('sends a consent-data INSUFFICIENT or UNKNOWN message', async function () {
consentData['user_consent'] = 0;
resData.consentData = consentData;

const implExtends = function (o2) {
env.sandbox
.stub(o2.implementation_, 'getConsentString_')
.resolves(resConsentString);

env.sandbox
.stub(o2.implementation_, 'getConsentPolicyState_')
.resolves(CONSENT_POLICY_STATE.INSUFFICIENT);

sendConsentDataToIframe = env.sandbox.spy(
o2.implementation_,
'sendConsentDataToIframe_'
);
};

env.sandbox
.stub(iframeHelper, 'listenFor')
.callsFake((iframe, message, callback) => {
expect(message).to.equal(MessageType.SEND_CONSENT_DATA);
callback('', resSource, resOrigin);
});

await getO2player(
{
'data-pid': '123',
'data-bcid': '456',
},
null,
implExtends
);

expect(sendConsentDataToIframe).to.have.been.calledWith(
resSource,
resOrigin,
resData
);
});

it('sends a consent-data UNKNOWN_NOT_REQUIRED or default message', async function () {
consentData = {
'gdprApplies': false,
};

resData.consentData = consentData;

const implExtends = function (o2) {
env.sandbox
.stub(o2.implementation_, 'getConsentString_')
.resolves(resConsentString);

env.sandbox
.stub(o2.implementation_, 'getConsentPolicyState_')
.resolves(CONSENT_POLICY_STATE.UNKNOWN_NOT_REQUIRED);

sendConsentDataToIframe = env.sandbox.spy(
o2.implementation_,
'sendConsentDataToIframe_'
);
};

env.sandbox
.stub(iframeHelper, 'listenFor')
.callsFake((iframe, message, callback) => {
expect(message).to.equal(MessageType.SEND_CONSENT_DATA);
callback('', resSource, resOrigin);
});

await getO2player(
{
'data-pid': '123',
'data-bcid': '456',
},
null,
implExtends
);

expect(sendConsentDataToIframe).to.have.been.calledWith(
resSource,
resOrigin,
resData
);
});
});
}
);
37 changes: 37 additions & 0 deletions extensions/amp-o2-player/amp-o2-player.md
Expand Up @@ -100,3 +100,40 @@ The following lists validation errors specific to the `amp-o2-player` tag:
<td>Error thrown when invalid value is given for attributes <code>height</code> or <code>width</code>. For example, <code>height=auto</code> triggers this error for all supported layout types, with the exception of <code>NODISPLAY</code>.</td>
</tr>
</table>

## Consent Data

Iframe inside `amp-o2-player` can send a message to receive consent data if a CMP is present on `amp-o2-player` parents page.

Example request for consent data from iframe:

```javascript
window.parent.postMessage(
{
sentinel: 'amp',
type: 'send-consent-data',
},
'*'
);
```

Example receive response for consent data:

```javascript
function isAmpMessage(event, type) {
return (
event.source == window.parent &&
event.origin != window.location.origin &&
event.data &&
event.data.sentinel == 'amp' &&
event.data.type == type
);
}

window.addEventListener('message', function (event) {
if (!isAmpMessage(event, 'consent-data')) {
return;
}
console.log(event.data.consentData);
});
```

0 comments on commit 966de3b

Please sign in to comment.