Commit 9e314a60 authored by Andrei Oprea's avatar Andrei Oprea
Browse files

Bug 1528953 - Add pref to opt out of recommended features r=k88hudson

To be reviewed together with https://github.com/mozilla/activity-stream/pull/4819

Differential Revision: https://phabricator.services.mozilla.com/D21408

--HG--
extra : moz-landing-system : lando
parent fb777266
......@@ -1302,7 +1302,7 @@ pref("browser.newtabpage.activity-stream.fxaccounts.endpoint", "https://accounts
pref("browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts", true);
// ASRouter provider configuration
pref("browser.newtabpage.activity-stream.asrouter.providers.cfr", "{\"id\":\"cfr\",\"enabled\":true,\"type\":\"local\",\"localProvider\":\"CFRMessageProvider\",\"frequency\":{\"custom\":[{\"period\":\"daily\",\"cap\":1}]}}");
pref("browser.newtabpage.activity-stream.asrouter.providers.cfr", "{\"id\":\"cfr\",\"enabled\":true,\"type\":\"local\",\"localProvider\":\"CFRMessageProvider\",\"frequency\":{\"custom\":[{\"period\":\"daily\",\"cap\":1}]},\"categories\":[\"cfrAddons\",\"cfrFeatures\"]}");
pref("browser.newtabpage.activity-stream.asrouter.providers.snippets", "{\"id\":\"snippets\",\"enabled\":true,\"type\":\"remote\",\"url\":\"https://snippets.cdn.mozilla.net/%STARTPAGE_VERSION%/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/\",\"updateCycleInMs\":14400000}");
// The pref controls if search hand-off is enabled for Activity Stream.
......
......@@ -328,7 +328,8 @@ var Policies = {
onBeforeAddons(manager, param) {
if (param) {
manager.disallowFeature("Shield");
setAndLockPref("browser.newtabpage.activity-stream.asrouter.userprefs.cfr", false);
setAndLockPref("browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons", false);
setAndLockPref("browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features", false);
}
},
},
......@@ -683,7 +684,8 @@ var Policies = {
setAndLockPref("xpinstall.enabled", param.Default);
if (!param.Default) {
blockAboutPage(manager, "about:debugging");
setAndLockPref("browser.newtabpage.activity-stream.asrouter.userprefs.cfr", false);
setAndLockPref("browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons", false);
setAndLockPref("browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features", false);
manager.disallowFeature("xpinstall");
}
}
......
......@@ -151,7 +151,8 @@ const POLICIES_TESTS = [
},
lockedPrefs: {
"xpinstall.enabled": false,
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr": false,
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons": false,
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features": false,
},
},
......@@ -263,7 +264,8 @@ const POLICIES_TESTS = [
"DisableFirefoxStudies": true,
},
lockedPrefs: {
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr": false,
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons": false,
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features": false,
},
},
];
......
......@@ -338,8 +338,13 @@ class _ASRouter {
// The provider should be enabled and not have a user preference set to false
...ASRouterPreferences.providers.filter(p => (
p.enabled &&
ASRouterPreferences.getUserPreference(p.id) !== false)
),
(
ASRouterPreferences.getUserPreference(p.id) !== false &&
// Provider is enabled or if provider has multiple categories
// check that at least one category is enabled
(!p.categories || p.categories.some(c => ASRouterPreferences.getUserPreference(c) !== false))
)
)),
].map(_provider => {
// make a copy so we don't modify the source of the pref
const provider = {..._provider};
......@@ -413,7 +418,8 @@ class _ASRouter {
let newState = {messages: [], providers: []};
for (const provider of this.state.providers) {
if (needsUpdate.includes(provider)) {
const {messages, lastUpdated} = await MessageLoaderUtils.loadMessagesForProvider(provider, this._storage);
let {messages, lastUpdated} = await MessageLoaderUtils.loadMessagesForProvider(provider, this._storage);
messages = messages.filter(({category}) => !category || ASRouterPreferences.getUserPreference(category));
newState.providers.push({...provider, lastUpdated});
newState.messages = [...newState.messages, ...messages];
} else {
......
......@@ -16,9 +16,15 @@ const DEFAULT_STATE = {
_devtoolsPref: DEVTOOLS_PREF,
};
const MIGRATE_PREFS = [
// Old pref, New pref
["browser.newtabpage.activity-stream.asrouter.userprefs.cfr", "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons"],
];
const USER_PREFERENCES = {
snippets: "browser.newtabpage.activity-stream.feeds.snippets",
cfr: "browser.newtabpage.activity-stream.asrouter.userprefs.cfr",
cfrAddons: "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons",
cfrFeatures: "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features",
};
const TEST_PROVIDER = {
......@@ -50,6 +56,24 @@ class _ASRouterPreferences {
}, []);
}
// XXX Bug 1531734
// Required for 67 when the pref change will happen
_migratePrefs() {
for (let [oldPref, newPref] of MIGRATE_PREFS) {
if (!Services.prefs.prefHasUserValue(oldPref)) {
continue;
}
if (Services.prefs.prefHasUserValue(newPref)) {
Services.prefs.clearUserPref(oldPref);
continue;
}
// If the pref was user modified we assume it was set to false
const oldValue = Services.prefs.getBoolPref(oldPref, false);
Services.prefs.clearUserPref(oldPref);
Services.prefs.setBoolPref(newPref, oldValue);
}
}
get providers() {
if (!this._initialized || this._providers === null) {
const config = this._getProviderConfig();
......@@ -144,6 +168,7 @@ class _ASRouterPreferences {
if (this._initialized) {
return;
}
this._migratePrefs();
Services.prefs.addObserver(this._providerPrefBranch, this);
Services.prefs.addObserver(this._devtoolsPref, this);
for (const id of Object.keys(USER_PREFERENCES)) {
......
......@@ -206,8 +206,12 @@ const PREFS_CONFIG = new Map([
title: "Are the asrouter devtools enabled?",
value: false,
}],
["asrouter.userprefs.cfr", {
title: "Does the user allow CFR recommendations?",
["asrouter.userprefs.cfr.addons", {
title: "Does the user allow CFR addon recommendations?",
value: true,
}],
["asrouter.userprefs.cfr.features", {
title: "Does the user allow CFR feature recommendations?",
value: true,
}],
["asrouter.providers.onboarding", {
......
......@@ -43,6 +43,7 @@ const CFR_MESSAGES = [
{
id: "FACEBOOK_CONTAINER_3",
template: "cfr_doorhanger",
category: "cfrAddons",
content: {
bucket_id: "CFR_M1",
notification_text: {string_id: "cfr-doorhanger-extension-notification"},
......@@ -78,7 +79,7 @@ const CFR_MESSAGES = [
label: {string_id: "cfr-doorhanger-extension-manage-settings-button"},
action: {
type: "OPEN_PREFERENCES_PAGE",
data: {category: "general-cfr", origin: "CFR"},
data: {category: "general-cfraddons", origin: "CFR"},
},
}],
},
......@@ -94,6 +95,7 @@ const CFR_MESSAGES = [
{
id: "GOOGLE_TRANSLATE_3",
template: "cfr_doorhanger",
category: "cfrAddons",
content: {
bucket_id: "CFR_M1",
notification_text: {string_id: "cfr-doorhanger-extension-notification"},
......@@ -129,7 +131,7 @@ const CFR_MESSAGES = [
label: {string_id: "cfr-doorhanger-extension-manage-settings-button"},
action: {
type: "OPEN_PREFERENCES_PAGE",
data: {category: "general-cfr", origin: "CFR"},
data: {category: "general-cfraddons", origin: "CFR"},
},
}],
},
......@@ -145,6 +147,7 @@ const CFR_MESSAGES = [
{
id: "YOUTUBE_ENHANCE_3",
template: "cfr_doorhanger",
category: "cfrAddons",
content: {
bucket_id: "CFR_M1",
notification_text: {string_id: "cfr-doorhanger-extension-notification"},
......@@ -180,7 +183,7 @@ const CFR_MESSAGES = [
label: {string_id: "cfr-doorhanger-extension-manage-settings-button"},
action: {
type: "OPEN_PREFERENCES_PAGE",
data: {category: "general-cfr", origin: "CFR"},
data: {category: "general-cfraddons", origin: "CFR"},
},
}],
},
......@@ -196,6 +199,7 @@ const CFR_MESSAGES = [
{
id: "WIKIPEDIA_CONTEXT_MENU_SEARCH_3",
template: "cfr_doorhanger",
category: "cfrAddons",
exclude: true,
content: {
bucket_id: "CFR_M1",
......@@ -232,7 +236,7 @@ const CFR_MESSAGES = [
label: {string_id: "cfr-doorhanger-extension-manage-settings-button"},
action: {
type: "OPEN_PREFERENCES_PAGE",
data: {category: "general-cfr", origin: "CFR"},
data: {category: "general-cfraddons", origin: "CFR"},
},
}],
},
......@@ -248,6 +252,7 @@ const CFR_MESSAGES = [
{
id: "REDDIT_ENHANCEMENT_3",
template: "cfr_doorhanger",
category: "cfrAddons",
exclude: true,
content: {
bucket_id: "CFR_M1",
......@@ -284,7 +289,7 @@ const CFR_MESSAGES = [
label: {string_id: "cfr-doorhanger-extension-manage-settings-button"},
action: {
type: "OPEN_PREFERENCES_PAGE",
data: {category: "general-cfr", origin: "CFR"},
data: {category: "general-cfraddons", origin: "CFR"},
},
}],
},
......@@ -300,6 +305,7 @@ const CFR_MESSAGES = [
{
id: "PIN_TAB",
template: "cfr_doorhanger",
category: "cfrFeatures",
exclude: true,
content: {
bucket_id: "CFR_PIN_TAB",
......@@ -326,7 +332,7 @@ const CFR_MESSAGES = [
label: {string_id: "cfr-doorhanger-extension-manage-settings-button"},
action: {
type: "OPEN_PREFERENCES_PAGE",
data: {category: "general-cfr", origin: "CFR"},
data: {category: "general-cfrfeatures", origin: "CFR"},
},
}],
},
......
......@@ -382,6 +382,44 @@ describe("ASRouter", () => {
assert.equal(Router.state.providers.length, 1);
assert.equal(Router.state.providers[0].id, providers[1].id);
});
it("should return provider `foo` because both categories are enabled", () => {
const providers = [
{id: "foo", enabled: true, categories: ["cfrFeatures", "cfrAddons"], type: "remote", url: "https://www.foo.com/"},
];
sandbox.stub(ASRouterPreferences, "providers").value(providers);
sandbox.stub(ASRouterPreferences, "getUserPreference")
.withArgs("cfrFeatures").returns(true)
.withArgs("cfrAddons")
.returns(true);
Router._updateMessageProviders();
assert.equal(Router.state.providers.length, 1);
assert.equal(Router.state.providers[0].id, providers[0].id);
});
it("should return provider `foo` because at least 1 category is enabled", () => {
const providers = [
{id: "foo", enabled: true, categories: ["cfrFeatures", "cfrAddons"], type: "remote", url: "https://www.foo.com/"},
];
sandbox.stub(ASRouterPreferences, "providers").value(providers);
sandbox.stub(ASRouterPreferences, "getUserPreference")
.withArgs("cfrFeatures").returns(false)
.withArgs("cfrAddons")
.returns(true);
Router._updateMessageProviders();
assert.equal(Router.state.providers.length, 1);
assert.equal(Router.state.providers[0].id, providers[0].id);
});
it("should not return provider `foo` because no categories are enabled", () => {
const providers = [
{id: "foo", enabled: true, categories: ["cfrFeatures", "cfrAddons"], type: "remote", url: "https://www.foo.com/"},
];
sandbox.stub(ASRouterPreferences, "providers").value(providers);
sandbox.stub(ASRouterPreferences, "getUserPreference")
.withArgs("cfrFeatures").returns(false)
.withArgs("cfrAddons")
.returns(false);
Router._updateMessageProviders();
assert.equal(Router.state.providers.length, 0);
});
});
describe("blocking", () => {
......
......@@ -4,15 +4,17 @@ const FAKE_PROVIDERS = [{id: "foo"}, {id: "bar"}];
const PROVIDER_PREF_BRANCH = "browser.newtabpage.activity-stream.asrouter.providers.";
const DEVTOOLS_PREF = "browser.newtabpage.activity-stream.asrouter.devtoolsEnabled";
const SNIPPETS_USER_PREF = "browser.newtabpage.activity-stream.feeds.snippets";
const CFR_USER_PREF = "browser.newtabpage.activity-stream.asrouter.userprefs.cfr";
const CFR_USER_PREF_ADDONS = "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons";
const CFR_USER_PREF_FEATURES = "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features";
/** NUMBER_OF_PREFS_TO_OBSERVE includes:
* 1. asrouter.providers. pref branch
* 2. asrouter.devtoolsEnabled
* 3. browser.newtabpage.activity-stream.feeds.snippets (user preference - snippets)
* 4. browser.newtabpage.activity-stream.asrouter.userprefs.cfr (user preference - cfr)
* 4. browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons (user preference - cfr)
* 4. browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features (user preference - cfr)
*/
const NUMBER_OF_PREFS_TO_OBSERVE = 4;
const NUMBER_OF_PREFS_TO_OBSERVE = 5;
describe("ASRouterPreferences", () => {
let ASRouterPreferences;
......@@ -187,9 +189,10 @@ describe("ASRouterPreferences", () => {
describe("#getAllUserPreferences", () => {
it("should return all user preferences", () => {
boolPrefStub.withArgs(SNIPPETS_USER_PREF).returns(true);
boolPrefStub.withArgs(CFR_USER_PREF).returns(false);
boolPrefStub.withArgs(CFR_USER_PREF_ADDONS).returns(false);
boolPrefStub.withArgs(CFR_USER_PREF_FEATURES).returns(true);
const result = ASRouterPreferences.getAllUserPreferences();
assert.deepEqual(result, {snippets: true, cfr: false});
assert.deepEqual(result, {snippets: true, cfrAddons: false, cfrFeatures: true});
});
});
describe("#enableOrDisableProvider", () => {
......@@ -242,7 +245,8 @@ describe("ASRouterPreferences", () => {
assert.calledWith(resetStub, getPrefNameForProvider(provider.id));
});
assert.calledWith(resetStub, SNIPPETS_USER_PREF);
assert.calledWith(resetStub, CFR_USER_PREF);
assert.calledWith(resetStub, CFR_USER_PREF_ADDONS);
assert.calledWith(resetStub, CFR_USER_PREF_FEATURES);
});
});
describe("observer, listeners", () => {
......@@ -303,4 +307,40 @@ describe("ASRouterPreferences", () => {
assert.notCalled(callback);
});
});
describe("_migratePrefs", () => {
beforeEach(() => {
sandbox.stub(global.Services.prefs, "setBoolPref");
sandbox.stub(global.Services.prefs, "clearUserPref");
});
it("should not do anything if userpref was not modified", () => {
ASRouterPreferences.init();
assert.notCalled(global.Services.prefs.getBoolPref);
assert.notCalled(global.Services.prefs.setBoolPref);
});
it("should not do migration if newPref was modified", () => {
sandbox.stub(global.Services.prefs, "prefHasUserValue").returns(true);
ASRouterPreferences.init();
assert.notCalled(global.Services.prefs.getBoolPref);
assert.notCalled(global.Services.prefs.setBoolPref);
assert.calledOnce(global.Services.prefs.clearUserPref);
assert.calledWith(global.Services.prefs.clearUserPref, "browser.newtabpage.activity-stream.asrouter.userprefs.cfr");
});
it("should migrate userprefs.cfr", () => {
const hasUserValueStub = sandbox.stub(global.Services.prefs, "prefHasUserValue");
hasUserValueStub.onCall(0).returns(true);
hasUserValueStub.returns(false);
ASRouterPreferences.init();
assert.calledOnce(global.Services.prefs.getBoolPref);
assert.calledWith(global.Services.prefs.getBoolPref, "browser.newtabpage.activity-stream.asrouter.userprefs.cfr");
assert.calledOnce(global.Services.prefs.setBoolPref);
assert.calledWith(global.Services.prefs.setBoolPref, CFR_USER_PREF_ADDONS, false);
assert.calledOnce(global.Services.prefs.clearUserPref);
assert.calledWith(global.Services.prefs.clearUserPref, "browser.newtabpage.activity-stream.asrouter.userprefs.cfr");
});
});
});
......@@ -11,7 +11,7 @@ const REGULAR_IDS = [
];
describe("CFRMessageProvider", () => {
it("should have a total of 4 messages", () => {
it("should have a total of 3 messages", () => {
assert.lengthOf(messages, 3);
});
it("should have one message each for the three regular addons", () => {
......
......@@ -110,7 +110,8 @@ Preferences.addAll([
{ id: "browser.ctrlTab.recentlyUsedOrder", type: "bool" },
// CFR
{id: "browser.newtabpage.activity-stream.asrouter.userprefs.cfr", type: "bool"},
{id: "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons", type: "bool"},
{id: "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features", type: "bool"},
// Fonts
{ id: "font.language.group", type: "wstring" },
......@@ -319,9 +320,11 @@ var gMainPane = {
gMainPane.initBrowserLocale();
}
let cfrLearnMoreLink = document.getElementById("cfrLearnMore");
let cfrLearnMoreUrl = Services.urlFormatter.formatURLPref("app.support.baseURL") + "extensionrecommendations";
cfrLearnMoreLink.setAttribute("href", cfrLearnMoreUrl);
for (const id of ["cfrLearnMore", "cfrFeaturesLearnMore"]) {
let link = document.getElementById(id);
link.setAttribute("href", cfrLearnMoreUrl);
}
if (AppConstants.platform == "win") {
// Functionality for "Show tabs in taskbar" on Windows 7 and up.
......
......@@ -635,13 +635,20 @@
<checkbox id="searchStartTyping"
data-l10n-id="browsing-search-on-start-typing"
preference="accessibility.typeaheadfind"/>
<hbox align="center" data-subcategory="cfr">
<hbox align="center" data-subcategory="cfraddons">
<checkbox id="cfrRecommendations"
class="tail-with-learn-more"
data-l10n-id="browsing-cfr-recommendations"
preference="browser.newtabpage.activity-stream.asrouter.userprefs.cfr"/>
preference="browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons"/>
<label id="cfrLearnMore" class="learnMore" data-l10n-id="browsing-cfr-recommendations-learn-more" is="text-link"/>
</hbox>
<hbox align="center" data-subcategory="cfrfeatures">
<checkbox id="cfrRecommendations-features"
class="tail-with-learn-more"
data-l10n-id="browsing-cfr-features"
preference="browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features"/>
<label id="cfrFeaturesLearnMore" class="learnMore" data-l10n-id="browsing-cfr-recommendations-learn-more" is="text-link"/>
</hbox>
</groupbox>
<hbox id="networkProxyCategory"
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment