Add configuration for admins to specify compliant email strategies (#20663)
* Add configuration for admins to specify compliant email strategies * Add keys for test
This commit is contained in:
parent
406e3fec4d
commit
f88784cc35
12 changed files with 122 additions and 41 deletions
|
|
@ -12,46 +12,60 @@ function removeExistingCSRF() {
|
|||
function fetchBaseData() {
|
||||
fetch('/async_info/base_data')
|
||||
.then((response) => response.json())
|
||||
.then(({ token, param, broadcast, user, creator }) => {
|
||||
if (token) {
|
||||
removeExistingCSRF();
|
||||
}
|
||||
.then(
|
||||
({
|
||||
token,
|
||||
param,
|
||||
broadcast,
|
||||
user,
|
||||
creator,
|
||||
client_geolocation,
|
||||
default_email_optin_allowed,
|
||||
}) => {
|
||||
if (token) {
|
||||
removeExistingCSRF();
|
||||
}
|
||||
|
||||
const newCsrfParamMeta = document.createElement('meta');
|
||||
newCsrfParamMeta.name = 'csrf-param';
|
||||
newCsrfParamMeta.content = param;
|
||||
document.head.appendChild(newCsrfParamMeta);
|
||||
const newCsrfParamMeta = document.createElement('meta');
|
||||
newCsrfParamMeta.name = 'csrf-param';
|
||||
newCsrfParamMeta.content = param;
|
||||
document.head.appendChild(newCsrfParamMeta);
|
||||
|
||||
const newCsrfTokenMeta = document.createElement('meta');
|
||||
newCsrfTokenMeta.name = 'csrf-token';
|
||||
newCsrfTokenMeta.content = token;
|
||||
document.head.appendChild(newCsrfTokenMeta);
|
||||
document.body.dataset.loaded = 'true';
|
||||
const newCsrfTokenMeta = document.createElement('meta');
|
||||
newCsrfTokenMeta.name = 'csrf-token';
|
||||
newCsrfTokenMeta.content = token;
|
||||
document.head.appendChild(newCsrfTokenMeta);
|
||||
document.body.dataset.loaded = 'true';
|
||||
|
||||
if (broadcast) {
|
||||
document.body.dataset.broadcast = broadcast;
|
||||
}
|
||||
if (broadcast) {
|
||||
document.body.dataset.broadcast = broadcast;
|
||||
}
|
||||
|
||||
if (checkUserLoggedIn()) {
|
||||
document.body.dataset.user = user;
|
||||
document.body.dataset.creator = creator;
|
||||
browserStoreCache('set', user);
|
||||
if (checkUserLoggedIn()) {
|
||||
document.body.dataset.user = user;
|
||||
document.body.dataset.creator = creator;
|
||||
document.body.dataset.clientGeolocation =
|
||||
JSON.stringify(client_geolocation);
|
||||
document.body.dataset.default_email_optin_allowed =
|
||||
default_email_optin_allowed;
|
||||
browserStoreCache('set', user);
|
||||
|
||||
setTimeout(() => {
|
||||
if (typeof ga === 'function') {
|
||||
ga('set', 'userId', JSON.parse(user).id);
|
||||
}
|
||||
if (typeof gtag === 'function') {
|
||||
gtag('set', 'user_Id', JSON.parse(user).id);
|
||||
}
|
||||
}, 400);
|
||||
} else {
|
||||
// Ensure user data is not exposed if no one is logged in
|
||||
delete document.body.dataset.user;
|
||||
delete document.body.dataset.creator;
|
||||
browserStoreCache('remove');
|
||||
}
|
||||
});
|
||||
setTimeout(() => {
|
||||
if (typeof ga === 'function') {
|
||||
ga('set', 'userId', JSON.parse(user).id);
|
||||
}
|
||||
if (typeof gtag === 'function') {
|
||||
gtag('set', 'user_Id', JSON.parse(user).id);
|
||||
}
|
||||
}, 400);
|
||||
} else {
|
||||
// Ensure user data is not exposed if no one is logged in
|
||||
delete document.body.dataset.user;
|
||||
delete document.body.dataset.creator;
|
||||
browserStoreCache('remove');
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function initializeBodyData() {
|
||||
|
|
|
|||
|
|
@ -278,6 +278,15 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
helper_method :client_geolocation
|
||||
|
||||
def default_email_optin_allowed?
|
||||
return false if Settings::General.geos_with_allowed_default_email_opt_in.blank?
|
||||
|
||||
Settings::General.geos_with_allowed_default_email_opt_in.any? do |geo|
|
||||
client_geolocation.to_s.starts_with?(geo)
|
||||
end
|
||||
end
|
||||
helper_method :default_email_optin_allowed?
|
||||
|
||||
def forward_to_app_config_domain
|
||||
# Let's only redirect get requests for this purpose.
|
||||
return unless request.get? &&
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ class AsyncInfoController < ApplicationController
|
|||
param: request_forgery_protection_token,
|
||||
token: form_authenticity_token,
|
||||
user: user_data,
|
||||
client_geolocation: client_geolocation,
|
||||
default_email_optin_allowed: default_email_optin_allowed?,
|
||||
creator: user_is_a_creator
|
||||
}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,10 +12,13 @@ export class FollowTags extends Component {
|
|||
this.handleClick = this.handleClick.bind(this);
|
||||
this.handleComplete = this.handleComplete.bind(this);
|
||||
|
||||
const emailState =
|
||||
document.body.dataset.defaultEmailOptinAllowed === 'true';
|
||||
|
||||
this.state = {
|
||||
allTags: [],
|
||||
selectedTags: [],
|
||||
email_digest_periodic: false,
|
||||
email_digest_periodic: emailState,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -231,4 +231,28 @@ describe('FollowTags', () => {
|
|||
expect(lastFetchUri).toEqual('/onboarding/notifications');
|
||||
});
|
||||
});
|
||||
|
||||
describe('emailDigestPeriodic state initialization', () => {
|
||||
it('should initialize email_digest_periodic to true when data-default-email-optin-allowed is true', async () => {
|
||||
// Simulate setting data-default-email-optin-allowed to true
|
||||
document.body.dataset.defaultEmailOptinAllowed = 'true';
|
||||
|
||||
const { container } = renderFollowTags();
|
||||
const checkbox = container.querySelector('#email_digest_periodic');
|
||||
|
||||
// Assert that the checkbox is checked, indicating email_digest_periodic state is true
|
||||
expect(checkbox.checked).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should initialize email_digest_periodic to false when data-default-email-optin-allowed is false', async () => {
|
||||
// Simulate setting data-default-email-optin-allowed to false
|
||||
document.body.dataset.defaultEmailOptinAllowed = 'false';
|
||||
|
||||
const { container } = renderFollowTags();
|
||||
const checkbox = container.querySelector('#email_digest_periodic');
|
||||
|
||||
// Assert that the checkbox is not checked, indicating email_digest_periodic state is false
|
||||
expect(checkbox.checked).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -109,6 +109,10 @@ module Constants
|
|||
description: I18n.t("lib.constants.settings.general.onboarding_newsletter_opt_in_subhead.description"),
|
||||
placeholder: I18n.t("lib.constants.settings.general.onboarding_newsletter_opt_in_subhead.placeholder")
|
||||
},
|
||||
geos_with_allowed_default_email_opt_in: {
|
||||
description: I18n.t("lib.constants.settings.general.geos_with_allowed_default_email_opt_in.description"),
|
||||
placeholder: I18n.t("lib.constants.settings.general.geos_with_allowed_default_email_opt_in.placeholder")
|
||||
},
|
||||
payment_pointer: {
|
||||
description: I18n.t("lib.constants.settings.general.payment.description"),
|
||||
placeholder: "$pay.somethinglikethis.co/value"
|
||||
|
|
|
|||
|
|
@ -139,6 +139,8 @@ module Settings
|
|||
setting :onboarding_newsletter_opt_in_head
|
||||
setting :onboarding_newsletter_opt_in_subhead
|
||||
|
||||
setting :geos_with_allowed_default_email_opt_in, type: :array, default: %w[]
|
||||
|
||||
setting :default_content_language, type: :string, default: "en",
|
||||
validates: { inclusion: Languages::Detection.codes }
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,13 @@
|
|||
class: "crayons-textfield",
|
||||
value: Settings::General.onboarding_newsletter_opt_in_subhead,
|
||||
placeholder: Constants::Settings::General.details[:onboarding_newsletter_opt_in_subhead][:placeholder] %>
|
||||
<% if FeatureFlag.enabled?(Geolocation::FEATURE_FLAG) %>
|
||||
<%= admin_config_label Constants::Settings::General.details[:geos_with_allowed_default_email_opt_in][:description] %>
|
||||
<%= f.text_field :geos_with_allowed_default_email_opt_in,
|
||||
class: "crayons-textfield",
|
||||
value: Settings::General.geos_with_allowed_default_email_opt_in,
|
||||
placeholder: Constants::Settings::General.details[:geos_with_allowed_default_email_opt_in][:placeholder] %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<fieldset>
|
||||
<div class="flex email_newsletter mt-5 pt-4 ">
|
||||
<div class="flex h-5 ml-3">
|
||||
<input type="checkbox" id="email_newsletter" name="email_newsletter" class="w-4 h-4 mt-1 crayons-checkbox">
|
||||
<input type="checkbox" id="email_newsletter" name="email_newsletter" class="w-4 h-4 mt-1 crayons-checkbox" <%= "checked".html_safe if default_email_optin_allowed? %>>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<label for="email_newsletter" class="font-medium text-gray-900 dark:text-gray-300">
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
<fieldset>
|
||||
<div class="flex email_newsletter mt-5 pt-3 ">
|
||||
<div class="flex h-5 ml-3">
|
||||
<input type="checkbox" id="email_newsletter" name="email_newsletter" class="w-4 h-4 mt-2 crayons-checkbox">
|
||||
<input type="checkbox" id="email_newsletter" name="email_newsletter" class="w-4 h-4 mt-2 crayons-checkbox" <%= "checked".html_safe if default_email_optin_allowed? %>>
|
||||
</div>
|
||||
<div class="ml-2">
|
||||
<label for="email_newsletter" class="font-medium text-gray-900 dark:text-gray-300">
|
||||
|
|
@ -52,10 +52,10 @@
|
|||
<legend>Email preferences</legend>
|
||||
<ul>
|
||||
<li class="checkbox-item">
|
||||
<label for="email_newsletter"><input type="checkbox" id="email_newsletter" name="email_newsletter">I want to receive weekly newsletter emails.</label>
|
||||
<label for="email_newsletter"><input type="checkbox" id="email_newsletter" name="email_newsletter" <%= "checked".html_safe if default_email_optin_allowed? %>>I want to receive weekly newsletter emails.</label>
|
||||
</li>
|
||||
<li class="checkbox-item">
|
||||
<label for="email_digest_periodic"><input type="checkbox" id="email_digest_periodic" name="email_digest_periodic">I want to receive a periodic digest of top posts from my tags.</label>
|
||||
<label for="email_digest_periodic"><input type="checkbox" id="email_digest_periodic" name="email_digest_periodic" <%= "checked".html_safe if default_email_optin_allowed? %>>I want to receive a periodic digest of top posts from my tags.</label>
|
||||
</li>
|
||||
</ul>
|
||||
</fieldset>
|
||||
|
|
|
|||
|
|
@ -157,6 +157,9 @@ en:
|
|||
onboarding_newsletter_opt_in_subhead:
|
||||
description: "Newsletter checkbox subheading"
|
||||
placeholder: "E.g., Rest assured, we respect your privacy. Your email will only be used for our newsletter and won't be shared with others."
|
||||
geos_with_allowed_default_email_opt_in:
|
||||
description: 'List of countries where the default email opt-in is allowed by admin'
|
||||
placeholder: 'List of valid countries: comma separated, letters only e.g. US,CA'
|
||||
payment:
|
||||
description: 'Used for site-wide web monetization. See: https://github.com/forem/forem/pull/6345'
|
||||
periodic:
|
||||
|
|
|
|||
|
|
@ -157,6 +157,9 @@ fr:
|
|||
onboarding_newsletter_opt_in_subhead:
|
||||
description: "Newsletter checkbox subheading"
|
||||
placeholder: "E.g., Rest assured, we respect your privacy. Your email will only be used for our newsletter and won't be shared with others."
|
||||
geos_with_allowed_default_email_opt_in:
|
||||
description: 'List of countries where the default email opt-in is allowed by admin'
|
||||
placeholder: 'List of valid countries: comma separated, letters only e.g. US,CA'
|
||||
payment:
|
||||
description: 'Used for site-wide web monetization. See: https://github.com/forem/forem/pull/6345'
|
||||
periodic:
|
||||
|
|
|
|||
|
|
@ -26,7 +26,17 @@ RSpec.describe "AsyncInfo" do
|
|||
sign_in create(:user)
|
||||
|
||||
get "/async_info/base_data"
|
||||
expect(response.parsed_body.keys).to match_array(%w[broadcast creator param token user])
|
||||
expect(response.parsed_body.keys).to match_array(%w[broadcast client_geolocation creator
|
||||
default_email_optin_allowed param token user])
|
||||
end
|
||||
|
||||
it "returns default_email_optin_allowed true if valid match with client geo" do
|
||||
sign_in create(:user)
|
||||
|
||||
allow(controller_instance).to receive(:client_geolocation).and_return("US-NY")
|
||||
allow(Settings::General).to receive(:geos_with_allowed_default_email_opt_in).and_return(["US"])
|
||||
get "/async_info/base_data"
|
||||
expect(response.parsed_body["default_email_optin_allowed"]).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue