FEATURE: use groups to control who sees ads" and all later

This commit is contained in:
Neil Lalonde 2019-04-17 15:40:50 -04:00
parent 50d258dc37
commit e6bcd96d8e
12 changed files with 252 additions and 108 deletions

View File

@ -0,0 +1,23 @@
import computed from "ember-addons/ember-computed-decorators";
export default Ember.Component.extend({
@computed()
showToGroups: function() {
const currentUser = Discourse.User.current();
if (
!currentUser ||
!currentUser.get("groups") ||
!this.siteSettings.no_ads_for_groups ||
this.siteSettings.no_ads_for_groups.length === 0
) {
return true;
}
const noAdsGroupNames = this.siteSettings.no_ads_for_groups.split("|");
return !currentUser
.get("groups")
.any(group => noAdsGroupNames.includes(group.name));
}
});

View File

@ -1,6 +1,9 @@
var currentUser = Discourse.User.current(); import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad_component";
import computed from "ember-addons/ember-computed-decorators";
var data = { const currentUser = Discourse.User.current();
const data = {
"topic-list-top": {}, "topic-list-top": {},
"topic-above-post-stream": {}, "topic-above-post-stream": {},
"topic-above-suggested": {}, "topic-above-suggested": {},
@ -119,10 +122,12 @@ if (
); );
} }
export default Ember.Component.extend({ export default AdComponent.extend({
classNames: ["amazon-product-links"], classNames: ["amazon-product-links"],
init: function() { showAd: Ember.computed.and("showToTrustLevel", "showToGroups"),
init() {
let placement = this.get("placement"); let placement = this.get("placement");
this.set("user_input", data[placement]["user_input"]); this.set("user_input", data[placement]["user_input"]);
this.set("amazon_width", data[placement]["amazon_width"]); this.set("amazon_width", data[placement]["amazon_width"]);
@ -133,35 +138,37 @@ export default Ember.Component.extend({
this._super(); this._super();
}, },
adWrapperStyle: function() { @computed("amazon_width", "amazon_height")
return `width: ${this.get("amazon_width")}px; height: ${this.get( adWrapperStyle(w, h) {
"amazon_height" return `width: ${w}px; height: ${h}px;`.htmlSafe();
)}px;`.htmlSafe(); },
}.property("amazon_width", "amazon_height"),
adWrapperStyleMobile: function() { @computed("mobile_amazon_width", "mobile_amazon_height")
return `width: ${this.get("mobile_amazon_width")}px; height: ${this.get( adWrapperStyleMobile(w, h) {
"mobile_amazon_height" return `width: ${w}px; height: ${h}px;`.htmlSafe();
)}px;`.htmlSafe(); },
}.property("mobile_amazon_width", "mobile_amazon_height"),
adTitleStyleMobile: function() { @computed("mobile_amazon_width")
return `width: ${this.get("mobile_amazon_width")}px;`.htmlSafe(); adTitleStyleMobile(w) {
}.property("mobile_amazon_width"), return `width: ${w}px;`.htmlSafe();
},
userInput: function() { @computed("user_input")
return `${this.get("user_input")}`.htmlSafe(); userInput(userInput) {
}.property("user_input"), return `${userInput}`.htmlSafe();
},
userInputMobile: function() { @computed("user_input_mobile")
return `${this.get("user_input_mobile")}`.htmlSafe(); userInputMobile(userInput) {
}.property("user_input_mobile"), return `${userInput}`.htmlSafe();
},
checkTrustLevels: function() { @computed()
showToTrustLevel() {
return !( return !(
currentUser && currentUser &&
currentUser.get("trust_level") > currentUser.get("trust_level") >
Discourse.SiteSettings.amazon_through_trust_level Discourse.SiteSettings.amazon_through_trust_level
); );
}.property("trust_level") }
}); });

View File

@ -1,3 +1,4 @@
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad_component";
import { import {
default as computed, default as computed,
observes observes
@ -7,21 +8,20 @@ const currentUser = Discourse.User.current(),
serve_id = Discourse.SiteSettings.carbonads_serve_id, serve_id = Discourse.SiteSettings.carbonads_serve_id,
placement = Discourse.SiteSettings.carbonads_placement; placement = Discourse.SiteSettings.carbonads_placement;
export default Ember.Component.extend({ export default AdComponent.extend({
init: function() { init() {
this.set("serve_id", serve_id); this.set("serve_id", serve_id);
this.set("placement", placement); this.set("placement", placement);
this._super(); this._super();
}, },
@computed("serve_id", "placement") @computed("serve_id", "placement")
url: function() { url(serveId, placement) {
return (`//cdn.carbonads.com/carbon.js?serve=${this.get("serve_id")}&placement=${this.get("placement")}`).htmlSafe(); return `//cdn.carbonads.com/carbon.js?serve=${serveId}&placement=${placement}`.htmlSafe();
}, },
@computed()
@computed("trust_level") showToTrustLevel() {
checkTrustLevels: function() {
return !( return !(
currentUser && currentUser &&
currentUser.get("trust_level") > currentUser.get("trust_level") >
@ -29,8 +29,8 @@ export default Ember.Component.extend({
); );
}, },
@computed("checkTrustLevels") @computed("showToTrustLevel", "showToGroups")
showAd: function(checkTrustLevels) { showAd(showToTrustLevel, showToGroups) {
return placement && serve_id && checkTrustLevels; return placement && serve_id && showToTrustLevel && showToGroups;
} }
}); });

View File

@ -1,11 +1,13 @@
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad_component";
import { import {
default as computed, default as computed,
observes observes
} from "ember-addons/ember-computed-decorators"; } from "ember-addons/ember-computed-decorators";
var _loaded = false, let _loaded = false,
_promise = null, _promise = null;
currentUser = Discourse.User.current(),
const currentUser = Discourse.User.current(),
propertyId = Discourse.SiteSettings.codefund_property_id; propertyId = Discourse.SiteSettings.codefund_property_id;
function loadCodeFund() { function loadCodeFund() {
@ -48,12 +50,23 @@ function loadCodeFund() {
return _promise; return _promise;
} }
export default Ember.Component.extend({ export default AdComponent.extend({
classNameBindings: [":codefund-ad"], classNameBindings: [":codefund-ad"],
propertyId: propertyId, propertyId: propertyId,
adRequested: false, adRequested: false,
adDetails: {}, adDetails: {},
displayPostBottom: Ember.computed.equal("placement", "post-bottom"),
displayTopicAbovePostStream: Ember.computed.equal(
"placement",
"topic-above-post-stream"
),
displayTopicAboveSuggested: Ember.computed.equal(
"placement",
"topic-above-suggested"
),
displayTopicListTop: Ember.computed.equal("placement", "topic-list-top"),
_triggerAds() { _triggerAds() {
if (!propertyId) return; if (!propertyId) return;
@ -83,7 +96,7 @@ export default Ember.Component.extend({
}, },
@observes("listLoading") @observes("listLoading")
waitForLoad: function() { waitForLoad() {
if (this.get("adRequested")) { if (this.get("adRequested")) {
return; return;
} // already requested that this ad unit be populated } // already requested that this ad unit be populated
@ -93,7 +106,7 @@ export default Ember.Component.extend({
}, },
@computed() @computed()
checkTrustLevels: function() { showToTrustLevel() {
return !( return !(
currentUser && currentUser &&
currentUser.get("trust_level") > currentUser.get("trust_level") >
@ -101,28 +114,12 @@ export default Ember.Component.extend({
); );
}, },
@computed("checkTrustLevels") @computed("showToTrustLevel", "showToGroups")
showAd: function(checkTrustLevels) { showAd(showToTrustLevel, showToGroups) {
return Discourse.SiteSettings.codefund_property_id && checkTrustLevels; return (
}, Discourse.SiteSettings.codefund_property_id &&
showToTrustLevel &&
@computed("placement") showToGroups
displayPostBottom: function(placement) { );
return placement === "post-bottom";
},
@computed("placement")
displayTopicAbovePostStream: function() {
return this.get("placement") === "topic-above-post-stream";
},
@computed("placement")
displayTopicAboveSuggested: function() {
return this.get("placement") === "topic-above-suggested";
},
@computed("placement")
displayTopicListTop: function() {
return this.get("placement") === "topic-list-top";
} }
}); });

View File

@ -1,3 +1,4 @@
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad_component";
import { import {
default as computed, default as computed,
observes observes
@ -146,7 +147,7 @@ if (Discourse.SiteSettings.adsense_publisher_code) {
} }
} }
export default Ember.Component.extend({ export default AdComponent.extend({
classNameBindings: [ classNameBindings: [
":google-adsense", ":google-adsense",
"classForSlot", "classForSlot",
@ -193,7 +194,7 @@ export default Ember.Component.extend({
}, },
@observes("listLoading") @observes("listLoading")
waitForLoad: function() { waitForLoad() {
if (this.get("adRequested")) { if (this.get("adRequested")) {
return; return;
} // already requested that this ad unit be populated } // already requested that this ad unit be populated
@ -203,34 +204,34 @@ export default Ember.Component.extend({
}, },
@computed("ad_width") @computed("ad_width")
isResponsive: function(adWidth) { isResponsive(adWidth) {
return adWidth === "auto"; return adWidth === "auto";
}, },
@computed("placement", "checkTrustLevels") @computed("placement", "showAd")
classForSlot: function(placement, shown) { classForSlot(placement, showAd) {
return shown ? `adsense-${placement}`.htmlSafe() : ""; return showAd ? `adsense-${placement}`.htmlSafe() : "";
}, },
@computed("isResponsive") @computed("isResponsive")
autoAdFormat: function(isResponsive) { autoAdFormat(isResponsive) {
return isResponsive ? "auto".htmlSafe() : false; return isResponsive ? "auto".htmlSafe() : false;
}, },
@computed("ad_width", "ad_height", "isResponsive") @computed("ad_width", "ad_height", "isResponsive")
adWrapperStyle: function(w, h, isResponsive) { adWrapperStyle(w, h, isResponsive) {
return (isResponsive ? "" : `width: ${w}; height: ${h};`).htmlSafe(); return (isResponsive ? "" : `width: ${w}; height: ${h};`).htmlSafe();
}, },
@computed("adWrapperStyle", "isResponsive") @computed("adWrapperStyle", "isResponsive")
adInsStyle: function(adWrapperStyle, isResponsive) { adInsStyle(adWrapperStyle, isResponsive) {
return `display: ${ return `display: ${
isResponsive ? "block" : "inline-block" isResponsive ? "block" : "inline-block"
}; ${adWrapperStyle}`.htmlSafe(); }; ${adWrapperStyle}`.htmlSafe();
}, },
@computed() @computed()
checkTrustLevels: function() { showToTrustLevel() {
return !( return !(
currentUser && currentUser &&
currentUser.get("trust_level") > currentUser.get("trust_level") >
@ -238,8 +239,12 @@ export default Ember.Component.extend({
); );
}, },
@computed("checkTrustLevels") @computed("showToTrustLevel", "showToGroups")
showAd: function(shown) { showAd(showToTrustLevel, showToGroups) {
return shown && Discourse.SiteSettings.adsense_publisher_code; return (
showToTrustLevel &&
showToGroups &&
Discourse.SiteSettings.adsense_publisher_code
);
} }
}); });

View File

@ -1,3 +1,9 @@
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad_component";
import {
default as computed,
observes,
on
} from "ember-addons/ember-computed-decorators";
import loadScript from "discourse/lib/load-script"; import loadScript from "discourse/lib/load-script";
var currentUser = Discourse.User.current(), var currentUser = Discourse.User.current(),
@ -198,51 +204,56 @@ function loadGoogle() {
return _promise; return _promise;
} }
export default Ember.Component.extend({ export default AdComponent.extend({
classNameBindings: ["adUnitClass"], classNameBindings: ["adUnitClass"],
classNames: ["google-dfp-ad"], classNames: ["google-dfp-ad"],
loadedGoogletag: false, loadedGoogletag: false,
refreshOnChange: null, refreshOnChange: null,
divId: function() { @computed("placement", "postNumber")
if (this.get("postNumber")) { divId(placement, postNumber) {
return ( if (postNumber) {
"div-gpt-ad-" + this.get("placement") + "-" + this.get("postNumber") return `div-gpt-ad-${placement}-${postNumber}`;
);
} else { } else {
return "div-gpt-ad-" + this.get("placement"); return `div-gpt-ad-${placement}`;
} }
}.property("placement", "postNumber"), },
adUnitClass: function() { @computed("placement", "showAd")
return "dfp-ad-" + this.get("placement"); adUnitClass(placement, showAd) {
}.property("placement"), return showAd ? `dfp-ad-${placement}` : "";
},
adWrapperStyle: function() { @computed("width", "height")
return `width: ${this.get("width")}px; height: ${this.get( adWrapperStyle(w, h) {
"height" return `width: ${w}px; height: ${h}px;`.htmlSafe();
)}px;`.htmlSafe(); },
}.property("width", "height"),
adTitleStyleMobile: function() { @computed("width")
return `width: ${this.get("width")}px;`.htmlSafe(); adTitleStyleMobile(w) {
}.property("width"), return `width: ${w}px;`.htmlSafe();
},
showAd: function() { @computed("showToTrustLevel", "showToGroups")
showAd(showToTrustLevel, showToGroups) {
return ( return (
Discourse.SiteSettings.dfp_publisher_id && this.get("checkTrustLevels") Discourse.SiteSettings.dfp_publisher_id &&
showToTrustLevel &&
showToGroups
); );
}.property("checkTrustLevels"), },
checkTrustLevels: function() { @computed()
showToTrustLevel() {
return !( return !(
currentUser && currentUser &&
currentUser.get("trust_level") > currentUser.get("trust_level") >
Discourse.SiteSettings.dfp_through_trust_level Discourse.SiteSettings.dfp_through_trust_level
); );
}.property("trust_level"), },
refreshAd: function() { @observes("refreshOnChange")
refreshAd() {
var slot = ads[this.get("divId")]; var slot = ads[this.get("divId")];
if (!(slot && slot.ad)) { if (!(slot && slot.ad)) {
return; return;
@ -260,9 +271,10 @@ export default Ember.Component.extend({
window.googletag.pubads().refresh([ad]); window.googletag.pubads().refresh([ad]);
}); });
} }
}.observes("refreshOnChange"), },
_initGoogleDFP: function() { @on("didInsertElement")
_initGoogleDFP() {
if (!this.get("showAd")) { if (!this.get("showAd")) {
return; return;
} }
@ -287,7 +299,7 @@ export default Ember.Component.extend({
} }
}); });
}); });
}.on("didInsertElement"), },
willRender() { willRender() {
this._super(...arguments); this._super(...arguments);
@ -300,7 +312,8 @@ export default Ember.Component.extend({
this.set("height", size.height); this.set("height", size.height);
}, },
cleanup: function() { @on("willDestroyElement")
cleanup() {
destroySlot(this.get("divId")); destroySlot(this.get("divId"));
}.on("willDestroyElement") }
}); });

View File

@ -1,4 +1,4 @@
{{#if checkTrustLevels}} {{#if showAd}}
{{#if site.mobileView}} {{#if site.mobileView}}
<div class="amazon-product-links-label" style={{adTitleStyleMobile}}><h2>{{i18n 'adplugin.advertisement_label'}}</h2></div> <div class="amazon-product-links-label" style={{adTitleStyleMobile}}><h2>{{i18n 'adplugin.advertisement_label'}}</h2></div>
<iframe style={{adWrapperStyleMobile}} marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src={{userInputMobile}}> <iframe style={{adWrapperStyleMobile}} marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src={{userInputMobile}}>

View File

@ -6,6 +6,7 @@ en:
admin: admin:
site_settings: site_settings:
categories: categories:
ad_plugin: 'Ad Plugin'
dfp_plugin: 'DFP/Ad Manager' dfp_plugin: 'DFP/Ad Manager'
adsense_plugin: 'AdSense' adsense_plugin: 'AdSense'
amazon_plugin: 'Amazon' amazon_plugin: 'Amazon'

View File

@ -1,5 +1,7 @@
en: en:
site_settings: site_settings:
no_ads_for_groups: "Don't show ads to users in these groups."
dfp_publisher_id: "Input your Google Ad Manager (formerly called DFP) network code, which is found in your network settings." dfp_publisher_id: "Input your Google Ad Manager (formerly called DFP) network code, which is found in your network settings."
dfp_through_trust_level: "Show your ads to users based on trust levels. Users with trust level higher than this value will not see ads." dfp_through_trust_level: "Show your ads to users based on trust levels. Users with trust level higher than this value will not see ads."

View File

@ -1,3 +1,11 @@
ad_plugin:
no_ads_for_groups:
client: true
default: ""
type: list
choices: "Group.pluck(:name)"
list_type: compact
adsense_plugin: adsense_plugin:
adsense_publisher_code: adsense_publisher_code:
client: true client: true

View File

@ -1,8 +1,10 @@
import { acceptance, replaceCurrentUser } from "helpers/qunit-helpers"; import { acceptance, replaceCurrentUser } from "helpers/qunit-helpers";
import groupFixtures from "fixtures/group-fixtures";
acceptance("AdSense", { acceptance("AdSense", {
loggedIn: true, loggedIn: true,
settings: { settings: {
no_ads_for_groups: "discourse",
adsense_publisher_code: "MYADSENSEID", adsense_publisher_code: "MYADSENSEID",
adsense_through_trust_level: 2, adsense_through_trust_level: 2,
adsense_topic_list_top_code: "list_top_ad_unit", adsense_topic_list_top_code: "list_top_ad_unit",
@ -54,3 +56,17 @@ test("no ads for trust level 3", async assert => {
"it should render 0 ads" "it should render 0 ads"
); );
}); });
QUnit.only("can omit ads based on groups", async assert => {
replaceCurrentUser({
staff: false,
trust_level: 1,
groups: [groupFixtures["/groups/discourse.json"].group]
});
await visit("/t/280");
assert.equal(
find(".google-adsense.adsense-post-bottom").length,
0,
"it should render 0 ads"
);
});

View File

@ -0,0 +1,72 @@
import { acceptance, replaceCurrentUser } from "helpers/qunit-helpers";
import groupFixtures from "fixtures/group-fixtures";
acceptance("DFP Ads", {
loggedIn: true,
settings: {
no_ads_for_groups: "discourse",
dfp_publisher_id: "MYdfpID",
dfp_through_trust_level: 2,
dfp_topic_list_top_code: "list_top_ad_unit",
dfp_topic_list_top_ad_sizes: "728*90 - leaderboard",
dfp_mobile_topic_list_top_code: "mobile_list_top_ad_unit",
dfp_mobile_topic_list_top_ad_size: "300*250 - medium rectangle",
dfp_post_bottom_code: "post_bottom_ad_unit",
dfp_post_bottom_ad_sizes: "728*90 - leaderboard",
dfp_mobile_post_bottom_code: "mobile_post_bottom_ad_unit",
dfp_mobile_post_bottom_ad_size: "300*250 - medium rectangle",
dfp_nth_post_code: 6
}
});
test("correct number of ads should show", async assert => {
replaceCurrentUser({ staff: false, trust_level: 1 });
await visit("/t/280"); // 20 posts
const ads = find(".google-dfp-ad.dfp-ad-post-bottom");
assert.equal(ads.length, 3, "it should render 3 ads");
assert.equal(
find("#post_6 + .widget-connector").find(
".google-dfp-ad.dfp-ad-post-bottom"
).length,
1,
"ad after 6th post"
);
assert.equal(
find("#post_12 + .widget-connector").find(
".google-dfp-ad.dfp-ad-post-bottom"
).length,
1,
"ad after 12th post"
);
assert.equal(
find("#post_18 + .widget-connector").find(
".google-dfp-ad.dfp-ad-post-bottom"
).length,
1,
"ad after 18th post"
);
});
test("no ads for trust level 3", async assert => {
replaceCurrentUser({ staff: false, trust_level: 3 });
await visit("/t/280");
assert.equal(
find(".google-dfp-ad.dfp-ad-post-bottom").length,
0,
"it should render 0 ads"
);
});
test("can omit ads based on groups", async assert => {
replaceCurrentUser({
staff: false,
trust_level: 1,
groups: [groupFixtures["/groups/discourse.json"].group]
});
await visit("/t/280");
assert.equal(
find(".google-dfp-ad.dfp-ad-post-bottom").length,
0,
"it should render 0 ads"
);
});