mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-04-15 03:01:37 -05:00
Cleaned up members & stripe settings (#11957)
* Updated members default settings ref #10318 This pulls out the members_subscription_settings & stripe_connect_intgration settings into separate keys * Updated usage of members_from_address * Updated stripe_connect usage * Updated members config to use new settings * Updated members middleware to use isStripeConnected * Updated members service to reload correctly We reload the members-api instance when the related settings change, so this makes sure we're listening to the correct settings changes * Updated ghost_head helper to use new settings * Updated theme middleware to use new settings * Renamed members_allow_signup -> members_allow_free_signup * Fixed tests after settings refactor * Removed from direct key settings key * Fixed regression tests for settings api
This commit is contained in:
parent
3aa68b95e7
commit
ee786aaa5d
14 changed files with 313 additions and 247 deletions
|
@ -37,19 +37,15 @@ function finaliseStructuredData(metaData) {
|
|||
}
|
||||
|
||||
function getMembersHelper() {
|
||||
const stripePaymentProcessor = settingsCache.get('members_subscription_settings').paymentProcessors.find(
|
||||
paymentProcessor => paymentProcessor.adapter === 'stripe'
|
||||
);
|
||||
const stripeSecretToken = stripePaymentProcessor.config.secret_token;
|
||||
const stripePublicToken = stripePaymentProcessor.config.public_token;
|
||||
|
||||
const stripeConnectIntegration = settingsCache.get('stripe_connect_integration');
|
||||
const stripeDirectSecretKey = settingsCache.get('stripe_secret_key');
|
||||
const stripeDirectPublishableKey = settingsCache.get('stripe_publishable_key');
|
||||
const stripeConnectAccountId = settingsCache.get('stripe_connect_account_id');
|
||||
|
||||
let membersHelper = `<script defer src="${getAssetUrl('public/members.js', true)}"></script>`;
|
||||
if (config.get('enableDeveloperExperiments')) {
|
||||
membersHelper += `<script defer src="https://unpkg.com/@tryghost/members-js@latest/umd/members.min.js" data-ghost="${urlUtils.getSiteUrl()}"></script>`;
|
||||
}
|
||||
if ((!!stripeSecretToken && !!stripePublicToken) || !!stripeConnectIntegration.account_id) {
|
||||
if ((!!stripeDirectSecretKey && !!stripeDirectPublishableKey) || !!stripeConnectAccountId) {
|
||||
membersHelper += '<script src="https://js.stripe.com/v3/"></script>';
|
||||
}
|
||||
return membersHelper;
|
||||
|
|
|
@ -61,12 +61,9 @@ function haxGetMembersPriceData() {
|
|||
};
|
||||
|
||||
try {
|
||||
const membersSettings = settingsCache.get('members_subscription_settings');
|
||||
const stripeProcessor = membersSettings.paymentProcessors.find(
|
||||
processor => processor.adapter === 'stripe'
|
||||
);
|
||||
const stripePlans = settingsCache.get('stripe_plans');
|
||||
|
||||
const priceData = stripeProcessor.config.plans.reduce((prices, plan) => {
|
||||
const priceData = stripePlans.reduce((prices, plan) => {
|
||||
const numberAmount = 0 + plan.amount;
|
||||
const dollarAmount = numberAmount ? Math.round(numberAmount / 100) : 0;
|
||||
return Object.assign(prices, {
|
||||
|
@ -74,7 +71,7 @@ function haxGetMembersPriceData() {
|
|||
});
|
||||
}, {});
|
||||
|
||||
priceData.currency = String.prototype.toUpperCase.call(stripeProcessor.config.currency || 'usd');
|
||||
priceData.currency = stripePlans[0].currency;
|
||||
priceData.currency_symbol = CURRENCY_SYMBOLS[priceData.currency];
|
||||
|
||||
if (Number.isInteger(priceData.monthly) && Number.isInteger(priceData.yearly)) {
|
||||
|
|
|
@ -92,12 +92,9 @@ module.exports = {
|
|||
try {
|
||||
const updatedFromAddress = membersService.settings.getEmailFromToken({token: frame.options.token});
|
||||
if (updatedFromAddress) {
|
||||
let subscriptionSetting = settingsCache.get('members_subscription_settings', {resolve: false});
|
||||
const settingsValue = subscriptionSetting.value ? JSON.parse(subscriptionSetting.value) : {};
|
||||
settingsValue.fromAddress = updatedFromAddress;
|
||||
return models.Settings.edit({
|
||||
key: 'members_subscription_settings',
|
||||
value: JSON.stringify(settingsValue)
|
||||
key: 'members_from_address',
|
||||
value: updatedFromAddress
|
||||
}).then(() => {
|
||||
// Redirect to Ghost-Admin settings page
|
||||
const adminLink = membersService.settings.getAdminRedirectLink();
|
||||
|
@ -155,10 +152,22 @@ module.exports = {
|
|||
});
|
||||
}
|
||||
|
||||
return models.Settings.edit({
|
||||
key: 'stripe_connect_integration',
|
||||
value: '{}'
|
||||
}, frame.options);
|
||||
return models.Settings.edit([{
|
||||
key: 'stripe_connect_publishable_key',
|
||||
value: null
|
||||
}, {
|
||||
key: 'stripe_connect_secret_key',
|
||||
value: null
|
||||
}, {
|
||||
key: 'stripe_connect_livemode',
|
||||
value: null
|
||||
}, {
|
||||
key: 'stripe_connect_display_name',
|
||||
value: null
|
||||
}, {
|
||||
key: 'stripe_connect_account_id',
|
||||
value: null
|
||||
}], frame.options);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -187,9 +196,8 @@ module.exports = {
|
|||
const stripeConnectIntegrationToken = frame.data.settings.find(setting => setting.key === 'stripe_connect_integration_token');
|
||||
|
||||
// The `stripe_connect_integration_token` "setting" is only used to set the `stripe_connect_integration` setting.
|
||||
// The `stripe_connect_integration` setting is not allowed to be set directly.
|
||||
const settings = frame.data.settings.filter((setting) => {
|
||||
return !['stripe_connect_integration', 'stripe_connect_integration_token'].includes(setting.key);
|
||||
return !['stripe_connect_integration_token'].includes(setting.key);
|
||||
});
|
||||
|
||||
const getSetting = setting => settingsCache.get(setting.key, {resolve: false});
|
||||
|
@ -218,8 +226,24 @@ module.exports = {
|
|||
try {
|
||||
const data = await membersService.stripeConnect.getStripeConnectTokenData(stripeConnectIntegrationToken.value, getSessionProp);
|
||||
settings.push({
|
||||
key: 'stripe_connect_integration',
|
||||
value: JSON.stringify(data)
|
||||
key: 'stripe_connect_publishable_key',
|
||||
value: data.public_key
|
||||
});
|
||||
settings.push({
|
||||
key: 'stripe_connect_secret_key',
|
||||
value: data.secret_key
|
||||
});
|
||||
settings.push({
|
||||
key: 'stripe_connect_livemode',
|
||||
value: data.livemode
|
||||
});
|
||||
settings.push({
|
||||
key: 'stripe_connect_display_name',
|
||||
value: data.display_name
|
||||
});
|
||||
settings.push({
|
||||
key: 'stripe_connect_account_id',
|
||||
value: data.account_id
|
||||
});
|
||||
} catch (err) {
|
||||
throw new BadRequestError({
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
const _ = require('lodash');
|
||||
const url = require('./utils/url');
|
||||
const typeGroupMapper = require('./utils/settings-type-group-mapper');
|
||||
const settingsCache = require('../../../../../services/settings/cache');
|
||||
|
||||
module.exports = {
|
||||
browse(apiConfig, frame) {
|
||||
|
@ -85,17 +84,6 @@ module.exports = {
|
|||
const {apiKey = '', domain = '', baseUrl = '', provider = 'mailgun'} = setting.value ? JSON.parse(setting.value) : {};
|
||||
setting.value = JSON.stringify({apiKey, domain, baseUrl, provider});
|
||||
}
|
||||
|
||||
//CASE: Ensure we don't update fromAddress for member as that goes through magic link flow
|
||||
if (setting.key === 'members_subscription_settings') {
|
||||
const memberSubscriptionSettings = setting.value ? JSON.parse(setting.value) : {};
|
||||
|
||||
let subscriptionSettingCache = settingsCache.get('members_subscription_settings', {resolve: false});
|
||||
const settingsCacheValue = subscriptionSettingCache.value ? JSON.parse(subscriptionSettingCache.value) : {};
|
||||
memberSubscriptionSettings.fromAddress = settingsCacheValue.fromAddress;
|
||||
|
||||
setting.value = JSON.stringify(memberSubscriptionSettings);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -125,10 +125,8 @@ class SettingsImporter extends BaseImporter {
|
|||
}
|
||||
|
||||
// CASE: we do not import "from address" for members settings as that needs to go via validation with magic link
|
||||
if (obj.key === 'members_subscription_settings' && obj.value) {
|
||||
const oldMemberSettings = _.find(this.existingData, {key: 'members_subscription_settings'}) || {};
|
||||
const oldMemberSettingsVal = oldMemberSettings.value ? JSON.parse(oldMemberSettings.value) : {};
|
||||
obj.value = JSON.stringify(_.assign({}, JSON.parse(obj.value), {fromAddress: oldMemberSettingsVal.fromAddress}));
|
||||
if (obj.key === 'members_from_address') {
|
||||
obj.value = null;
|
||||
}
|
||||
|
||||
// CASE: export files might contain "0" or "1" for booleans. Model layer needs real booleans.
|
||||
|
|
|
@ -183,11 +183,38 @@
|
|||
"default_content_visibility": {
|
||||
"defaultValue": "public"
|
||||
},
|
||||
"members_subscription_settings": {
|
||||
"defaultValue": "{\"fromAddress\":\"noreply\",\"allowSelfSignup\":true,\"paymentProcessors\":[{\"adapter\":\"stripe\",\"config\":{\"secret_token\":\"\",\"public_token\":\"\",\"product\":{\"name\":\"Ghost Subscription\"},\"plans\":[{\"name\":\"Monthly\",\"currency\":\"usd\",\"interval\":\"month\",\"amount\":\"\"},{\"name\":\"Yearly\",\"currency\":\"usd\",\"interval\":\"year\",\"amount\":\"\"}]}}]}"
|
||||
"members_allow_free_signup": {
|
||||
"defaultValue": true
|
||||
},
|
||||
"stripe_connect_integration": {
|
||||
"defaultValue": "{}"
|
||||
"members_from_address": {
|
||||
"defaultValue": null
|
||||
},
|
||||
"stripe_product_name": {
|
||||
"defaultValue": "Ghost Subscription"
|
||||
},
|
||||
"stripe_secret_key": {
|
||||
"defaultValue": null
|
||||
},
|
||||
"stripe_publishable_key": {
|
||||
"defaultValue": null
|
||||
},
|
||||
"stripe_plans": {
|
||||
"defaultValue": "[{\"name\":\"Monthly\",\"currency\":\"usd\",\"interval\":\"month\",\"amount\":5},{\"name\":\"Yearly\",\"currency\":\"usd\",\"interval\":\"year\",\"amount\":50}]"
|
||||
},
|
||||
"stripe_connect_publishable_key": {
|
||||
"defaultValue": null
|
||||
},
|
||||
"stripe_connect_secret_key": {
|
||||
"defaultValue": null
|
||||
},
|
||||
"stripe_connect_livemode": {
|
||||
"defaultValue": null
|
||||
},
|
||||
"stripe_connect_display_name": {
|
||||
"defaultValue": null
|
||||
},
|
||||
"stripe_connect_account_id": {
|
||||
"defaultValue": null
|
||||
}
|
||||
},
|
||||
"portal" : {
|
||||
|
|
|
@ -34,11 +34,8 @@ class MembersConfigProvider {
|
|||
return domain && domain[1];
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
getEmailFromAddress() {
|
||||
const subscriptionSettings = this._settingsCache.get('members_subscription_settings') || {};
|
||||
const fromAddress = subscriptionSettings.fromAddress || 'noreply';
|
||||
const fromAddress = this._settingsCache.get('members_from_address') || 'noreply';
|
||||
|
||||
// Any fromAddress without domain uses site domain, like default setting `noreply`
|
||||
if (fromAddress.indexOf('@') < 0) {
|
||||
|
@ -56,18 +53,18 @@ class MembersConfigProvider {
|
|||
EUR: '€',
|
||||
INR: '₹'
|
||||
};
|
||||
|
||||
const defaultPriceData = {
|
||||
monthly: 0,
|
||||
yearly: 0
|
||||
yearly: 0,
|
||||
currency: 'USD',
|
||||
currency_symbol: CURRENCY_SYMBOLS.USD
|
||||
};
|
||||
|
||||
try {
|
||||
const membersSettings = this._settingsCache.get('members_subscription_settings');
|
||||
const stripeProcessor = membersSettings.paymentProcessors.find(
|
||||
processor => processor.adapter === 'stripe'
|
||||
);
|
||||
const plans = this._settingsCache.get('stripe_plans');
|
||||
|
||||
const priceData = stripeProcessor.config.plans.reduce((prices, plan) => {
|
||||
const priceData = plans.reduce((prices, plan) => {
|
||||
const numberAmount = 0 + plan.amount;
|
||||
const dollarAmount = numberAmount ? Math.round(numberAmount / 100) : 0;
|
||||
return Object.assign(prices, {
|
||||
|
@ -75,7 +72,7 @@ class MembersConfigProvider {
|
|||
});
|
||||
}, {});
|
||||
|
||||
priceData.currency = String.prototype.toUpperCase.call(stripeProcessor.config.currency || 'usd');
|
||||
priceData.currency = plans[0].currency || 'USD';
|
||||
priceData.currency_symbol = CURRENCY_SYMBOLS[priceData.currency];
|
||||
|
||||
if (Number.isInteger(priceData.monthly) && Number.isInteger(priceData.yearly)) {
|
||||
|
@ -89,52 +86,51 @@ class MembersConfigProvider {
|
|||
}
|
||||
|
||||
/**
|
||||
* @function getStripeAPIKeys
|
||||
* @desc Gets the stripe api keys from settings, respecting the stripeDirect config
|
||||
*
|
||||
* @param {string} publicKey - The publicKey to use if stripeDirect is enabled
|
||||
* @param {string} secretKey - The secretKey to use if stripeDirect is enabled
|
||||
*
|
||||
* @returns {{publicKey: string, secretKey: string}}
|
||||
* @param {'direct' | 'connect'} type - The "type" of keys to fetch from settings
|
||||
* @returns {{publicKey: string, secretKey: string} | null}
|
||||
*/
|
||||
getStripeAPIKeys(publicKey, secretKey) {
|
||||
const stripeDirect = this._config.get('stripeDirect');
|
||||
const stripeConnectIntegration = this._settingsCache.get('stripe_connect_integration');
|
||||
const hasStripeConnectKeys = stripeConnectIntegration.secret_key && stripeConnectIntegration.public_key;
|
||||
|
||||
if (stripeDirect || !hasStripeConnectKeys) {
|
||||
return {
|
||||
publicKey,
|
||||
secretKey
|
||||
};
|
||||
getStripeKeys(type) {
|
||||
if (type !== 'direct' && type !== 'connect') {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
return {
|
||||
publicKey: stripeConnectIntegration.public_key,
|
||||
secretKey: stripeConnectIntegration.secret_key
|
||||
};
|
||||
}
|
||||
const secretKey = this._settingsCache.get(`stripe_${type === 'connect' ? 'connect_' : ''}secret_key`);
|
||||
const publicKey = this._settingsCache.get(`stripe_${type === 'connect' ? 'connect_' : ''}publishable_key`);
|
||||
|
||||
isStripeConnected() {
|
||||
const paymentConfig = this.getStripePaymentConfig();
|
||||
|
||||
return (paymentConfig && paymentConfig.publicKey && paymentConfig.secretKey);
|
||||
}
|
||||
|
||||
getStripePaymentConfig() {
|
||||
const subscriptionSettings = this._settingsCache.get('members_subscription_settings');
|
||||
|
||||
const stripePaymentProcessor = subscriptionSettings.paymentProcessors.find(
|
||||
paymentProcessor => paymentProcessor.adapter === 'stripe'
|
||||
);
|
||||
|
||||
if (!stripePaymentProcessor || !stripePaymentProcessor.config) {
|
||||
if (!secretKey || !publicKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// NOTE: "Complimentary" plan has to be first in the queue so it is created even if regular plans are not configured
|
||||
stripePaymentProcessor.config.plans.unshift(COMPLIMENTARY_PLAN);
|
||||
return {
|
||||
secretKey,
|
||||
publicKey
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {{publicKey: string, secretKey: string} | null}
|
||||
*/
|
||||
getActiveStripeKeys() {
|
||||
const stripeDirect = this._config.get('stripeDirect');
|
||||
|
||||
if (stripeDirect) {
|
||||
return this.getStripeKeys('direct');
|
||||
}
|
||||
|
||||
const connectKeys = this.getStripeKeys('connect');
|
||||
|
||||
if (!connectKeys) {
|
||||
return this.getStripeKeys('direct');
|
||||
}
|
||||
|
||||
return connectKeys;
|
||||
}
|
||||
|
||||
isStripeConnected() {
|
||||
return this.getActiveStripeKeys() !== null;
|
||||
}
|
||||
|
||||
getStripeUrlConfig() {
|
||||
const siteUrl = this._urlUtils.getSiteUrl();
|
||||
|
||||
const webhookHandlerUrl = new URL('/members/webhooks/stripe', siteUrl);
|
||||
|
@ -149,25 +145,39 @@ class MembersConfigProvider {
|
|||
const billingCancelUrl = new URL(siteUrl);
|
||||
billingCancelUrl.searchParams.set('stripe', 'billing-update-cancel');
|
||||
|
||||
const stripeApiKeys = this.getStripeAPIKeys(
|
||||
stripePaymentProcessor.config.public_token,
|
||||
stripePaymentProcessor.config.secret_token
|
||||
);
|
||||
return {
|
||||
checkoutSuccess: checkoutSuccessUrl.href,
|
||||
checkoutCancel: checkoutCancelUrl.href,
|
||||
billingSuccess: billingSuccessUrl.href,
|
||||
billingCancel: billingCancelUrl.href,
|
||||
webhookHandler: webhookHandlerUrl.href
|
||||
};
|
||||
}
|
||||
|
||||
if (!stripeApiKeys.publicKey || !stripeApiKeys.secretKey) {
|
||||
getStripePaymentConfig() {
|
||||
if (!this.isStripeConnected()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const stripeApiKeys = this.getActiveStripeKeys();
|
||||
const urls = this.getStripeUrlConfig();
|
||||
|
||||
if (!stripeApiKeys) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
publicKey: stripeApiKeys.publicKey,
|
||||
secretKey: stripeApiKeys.secretKey,
|
||||
checkoutSuccessUrl: checkoutSuccessUrl.href,
|
||||
checkoutCancelUrl: checkoutCancelUrl.href,
|
||||
billingSuccessUrl: billingSuccessUrl.href,
|
||||
billingCancelUrl: billingCancelUrl.href,
|
||||
webhookHandlerUrl: webhookHandlerUrl.href,
|
||||
product: stripePaymentProcessor.config.product,
|
||||
plans: stripePaymentProcessor.config.plans,
|
||||
checkoutSuccessUrl: urls.checkoutSuccess,
|
||||
checkoutCancelUrl: urls.checkoutCancel,
|
||||
billingSuccessUrl: urls.billingSuccess,
|
||||
billingCancelUrl: urls.billingCancel,
|
||||
webhookHandlerUrl: urls.webhookHandler,
|
||||
product: {
|
||||
name: this._settingsCache.get('stripe_product_name')
|
||||
},
|
||||
plans: [COMPLIMENTARY_PLAN].concat(this._settingsCache.get('stripe_plans')),
|
||||
appInfo: {
|
||||
name: 'Ghost',
|
||||
partner_id: 'pp_partner_DKmRVtTs4j9pwZ',
|
||||
|
@ -192,8 +202,7 @@ class MembersConfigProvider {
|
|||
}
|
||||
|
||||
getAllowSelfSignup() {
|
||||
const subscriptionSettings = this._settingsCache.get('members_subscription_settings');
|
||||
return subscriptionSettings.allowSelfSignup;
|
||||
return this._settingsCache.get('members_allow_free_signup');
|
||||
}
|
||||
|
||||
getTokenConfig() {
|
||||
|
|
|
@ -23,7 +23,19 @@ let membersSettings;
|
|||
|
||||
// Bind to events to automatically keep subscription info up-to-date from settings
|
||||
events.on('settings.edited', function updateSettingFromModel(settingModel) {
|
||||
if (!['members_subscription_settings', 'stripe_connect_integration'].includes(settingModel.get('key'))) {
|
||||
if (![
|
||||
'members_allow_free_signup',
|
||||
'members_from_address',
|
||||
'stripe_publishable_key',
|
||||
'stripe_secret_key',
|
||||
'stripe_product_name',
|
||||
'stripe_plans',
|
||||
'stripe_connect_publishable_key',
|
||||
'stripe_connect_secret_key',
|
||||
'stripe_connect_livemode',
|
||||
'stripe_connect_display_name',
|
||||
'stripe_connect_account_id'
|
||||
].includes(settingModel.get('key'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,14 +84,8 @@ const updateMemberData = async function (req, res) {
|
|||
};
|
||||
|
||||
const getMemberSiteData = async function (req, res) {
|
||||
const stripePaymentProcessor = settingsCache.get('members_subscription_settings').paymentProcessors.find(
|
||||
paymentProcessor => paymentProcessor.adapter === 'stripe'
|
||||
);
|
||||
const stripeSecretToken = stripePaymentProcessor && stripePaymentProcessor.config.secret_token;
|
||||
const stripePublicToken = stripePaymentProcessor && stripePaymentProcessor.config.public_token;
|
||||
const stripeConnectIntegration = settingsCache.get('stripe_connect_integration');
|
||||
const isStripeConfigured = membersService.config.isStripeConnected();
|
||||
|
||||
const isStripeConfigured = (!!stripeSecretToken && !!stripePublicToken) || !!(stripeConnectIntegration && stripeConnectIntegration.account_id);
|
||||
const response = {
|
||||
title: settingsCache.get('title'),
|
||||
description: settingsCache.get('description'),
|
||||
|
|
|
@ -9,45 +9,54 @@ const ghost = testUtils.startGhost;
|
|||
// NOTE: in future iterations these fields should be fetched from a central module.
|
||||
// Have put a list as is here for the lack of better place for it.
|
||||
const defaultSettingsKeyTypes = [
|
||||
{key: 'title',type: 'blog'},
|
||||
{key: 'description',type: 'blog'},
|
||||
{key: 'logo',type: 'blog'},
|
||||
{key: 'cover_image',type: 'blog'},
|
||||
{key: 'icon',type: 'blog'},
|
||||
{key: 'lang',type: 'blog'},
|
||||
{key: 'timezone',type: 'blog'},
|
||||
{key: 'codeinjection_head',type: 'blog'},
|
||||
{key: 'codeinjection_foot',type: 'blog'},
|
||||
{key: 'facebook',type: 'blog'},
|
||||
{key: 'twitter',type: 'blog'},
|
||||
{key: 'navigation',type: 'blog'},
|
||||
{key: 'secondary_navigation',type: 'blog'},
|
||||
{key: 'meta_title',type: 'blog'},
|
||||
{key: 'meta_description',type: 'blog'},
|
||||
{key: 'og_image',type: 'blog'},
|
||||
{key: 'og_title',type: 'blog'},
|
||||
{key: 'og_description',type: 'blog'},
|
||||
{key: 'twitter_image',type: 'blog'},
|
||||
{key: 'twitter_title',type: 'blog'},
|
||||
{key: 'twitter_description',type: 'blog'},
|
||||
{key: 'active_theme',type: 'theme'},
|
||||
{key: 'is_private',type: 'private'},
|
||||
{key: 'password',type: 'private'},
|
||||
{key: 'public_hash',type: 'private'},
|
||||
{key: 'default_content_visibility',type: 'members'},
|
||||
{key: 'members_subscription_settings',type: 'members'},
|
||||
{key: 'stripe_connect_integration',type: 'members'},
|
||||
{key: 'portal_name',type: 'portal'},
|
||||
{key: 'portal_button',type: 'portal'},
|
||||
{key: 'portal_plans',type: 'portal'},
|
||||
{key: 'bulk_email_settings',type: 'bulk_email'},
|
||||
{key: 'amp',type: 'blog'},
|
||||
{key: 'labs',type: 'blog'},
|
||||
{key: 'slack',type: 'blog'},
|
||||
{key: 'unsplash',type: 'blog'},
|
||||
{key: 'shared_views',type: 'blog'},
|
||||
{key: 'active_timezone',type: 'blog'},
|
||||
{key: 'default_locale',type: 'blog'}
|
||||
{key: 'title', type: 'blog'},
|
||||
{key: 'description', type: 'blog'},
|
||||
{key: 'logo', type: 'blog'},
|
||||
{key: 'cover_image', type: 'blog'},
|
||||
{key: 'icon', type: 'blog'},
|
||||
{key: 'lang', type: 'blog'},
|
||||
{key: 'timezone', type: 'blog'},
|
||||
{key: 'codeinjection_head', type: 'blog'},
|
||||
{key: 'codeinjection_foot', type: 'blog'},
|
||||
{key: 'facebook', type: 'blog'},
|
||||
{key: 'twitter', type: 'blog'},
|
||||
{key: 'navigation', type: 'blog'},
|
||||
{key: 'secondary_navigation', type: 'blog'},
|
||||
{key: 'meta_title', type: 'blog'},
|
||||
{key: 'meta_description', type: 'blog'},
|
||||
{key: 'og_image', type: 'blog'},
|
||||
{key: 'og_title', type: 'blog'},
|
||||
{key: 'og_description', type: 'blog'},
|
||||
{key: 'twitter_image', type: 'blog'},
|
||||
{key: 'twitter_title', type: 'blog'},
|
||||
{key: 'twitter_description', type: 'blog'},
|
||||
{key: 'active_theme', type: 'theme'},
|
||||
{key: 'is_private', type: 'private'},
|
||||
{key: 'password', type: 'private'},
|
||||
{key: 'public_hash', type: 'private'},
|
||||
{key: 'default_content_visibility', type: 'members'},
|
||||
{key: 'members_allow_free_signup', type: 'members'},
|
||||
{key: 'members_from_address', type: 'members'},
|
||||
{key: 'stripe_product_name', type: 'members'},
|
||||
{key: 'stripe_plans', type: 'members'},
|
||||
{key: 'stripe_secret_key', type: 'members'},
|
||||
{key: 'stripe_publishable_key', type: 'members'},
|
||||
{key: 'stripe_connect_secret_key', type: 'members'},
|
||||
{key: 'stripe_connect_publishable_key', type: 'members'},
|
||||
{key: 'stripe_connect_account_id', type: 'members'},
|
||||
{key: 'stripe_connect_display_name', type: 'members'},
|
||||
{key: 'stripe_connect_livemode', type: 'members'},
|
||||
{key: 'portal_name', type: 'portal'},
|
||||
{key: 'portal_button', type: 'portal'},
|
||||
{key: 'portal_plans', type: 'portal'},
|
||||
{key: 'bulk_email_settings', type: 'bulk_email'},
|
||||
{key: 'amp', type: 'blog'},
|
||||
{key: 'labs', type: 'blog'},
|
||||
{key: 'slack', type: 'blog'},
|
||||
{key: 'unsplash', type: 'blog'},
|
||||
{key: 'shared_views', type: 'blog'},
|
||||
{key: 'active_timezone', type: 'blog'},
|
||||
{key: 'default_locale', type: 'blog'}
|
||||
];
|
||||
|
||||
describe('Settings API (canary)', function () {
|
||||
|
@ -82,8 +91,12 @@ describe('Settings API (canary)', function () {
|
|||
jsonResponse.settings.should.be.an.Object();
|
||||
const settings = jsonResponse.settings;
|
||||
|
||||
Object.keys(settings).length.should.equal(39);
|
||||
settings.map(s => ({key: s.key, type: s.type})).should.deepEqual(defaultSettingsKeyTypes);
|
||||
should.equal(settings.length, defaultSettingsKeyTypes.length);
|
||||
for (const defaultSetting of defaultSettingsKeyTypes) {
|
||||
should.exist(settings.find((setting) => {
|
||||
return setting.key === defaultSetting.key && setting.type === defaultSetting.type;
|
||||
}));
|
||||
}
|
||||
|
||||
localUtils.API.checkResponse(jsonResponse, 'settings');
|
||||
});
|
||||
|
|
|
@ -8,45 +8,54 @@ const ghost = testUtils.startGhost;
|
|||
// NOTE: in future iterations these fields should be fetched from a central module.
|
||||
// Have put a list as is here for the lack of better place for it.
|
||||
const defaultSettingsKeyTypes = [
|
||||
{key: 'title',type: 'blog'},
|
||||
{key: 'description',type: 'blog'},
|
||||
{key: 'logo',type: 'blog'},
|
||||
{key: 'cover_image',type: 'blog'},
|
||||
{key: 'icon',type: 'blog'},
|
||||
{key: 'codeinjection_head',type: 'blog'},
|
||||
{key: 'codeinjection_foot',type: 'blog'},
|
||||
{key: 'facebook',type: 'blog'},
|
||||
{key: 'twitter',type: 'blog'},
|
||||
{key: 'navigation',type: 'blog'},
|
||||
{key: 'secondary_navigation',type: 'blog'},
|
||||
{key: 'meta_title',type: 'blog'},
|
||||
{key: 'meta_description',type: 'blog'},
|
||||
{key: 'og_image',type: 'blog'},
|
||||
{key: 'og_title',type: 'blog'},
|
||||
{key: 'og_description',type: 'blog'},
|
||||
{key: 'twitter_image',type: 'blog'},
|
||||
{key: 'twitter_title',type: 'blog'},
|
||||
{key: 'twitter_description',type: 'blog'},
|
||||
{key: 'active_theme',type: 'theme'},
|
||||
{key: 'is_private',type: 'private'},
|
||||
{key: 'password',type: 'private'},
|
||||
{key: 'public_hash',type: 'private'},
|
||||
{key: 'default_content_visibility',type: 'members'},
|
||||
{key: 'members_subscription_settings',type: 'members'},
|
||||
{key: 'stripe_connect_integration',type: 'members'},
|
||||
{key: 'portal_name',type: 'portal'},
|
||||
{key: 'portal_button',type: 'portal'},
|
||||
{key: 'portal_plans',type: 'portal'},
|
||||
{key: 'bulk_email_settings',type: 'bulk_email'},
|
||||
{key: 'amp',type: 'blog'},
|
||||
{key: 'labs',type: 'blog'},
|
||||
{key: 'slack',type: 'blog'},
|
||||
{key: 'unsplash',type: 'blog'},
|
||||
{key: 'shared_views',type: 'blog'},
|
||||
{key: 'ghost_head',type: 'blog'},
|
||||
{key: 'ghost_foot',type: 'blog'},
|
||||
{key: 'active_timezone',type: 'blog'},
|
||||
{key: 'default_locale',type: 'blog'}
|
||||
{key: 'title', type: 'blog'},
|
||||
{key: 'description', type: 'blog'},
|
||||
{key: 'logo', type: 'blog'},
|
||||
{key: 'cover_image', type: 'blog'},
|
||||
{key: 'icon', type: 'blog'},
|
||||
{key: 'codeinjection_head', type: 'blog'},
|
||||
{key: 'codeinjection_foot', type: 'blog'},
|
||||
{key: 'facebook', type: 'blog'},
|
||||
{key: 'twitter', type: 'blog'},
|
||||
{key: 'navigation', type: 'blog'},
|
||||
{key: 'secondary_navigation', type: 'blog'},
|
||||
{key: 'meta_title', type: 'blog'},
|
||||
{key: 'meta_description', type: 'blog'},
|
||||
{key: 'og_image', type: 'blog'},
|
||||
{key: 'og_title', type: 'blog'},
|
||||
{key: 'og_description', type: 'blog'},
|
||||
{key: 'twitter_image', type: 'blog'},
|
||||
{key: 'twitter_title', type: 'blog'},
|
||||
{key: 'twitter_description', type: 'blog'},
|
||||
{key: 'active_theme', type: 'theme'},
|
||||
{key: 'is_private', type: 'private'},
|
||||
{key: 'password', type: 'private'},
|
||||
{key: 'public_hash', type: 'private'},
|
||||
{key: 'default_content_visibility', type: 'members'},
|
||||
{key: 'members_allow_free_signup', type: 'members'},
|
||||
{key: 'members_from_address', type: 'members'},
|
||||
{key: 'stripe_product_name', type: 'members'},
|
||||
{key: 'stripe_plans', type: 'members'},
|
||||
{key: 'stripe_secret_key', type: 'members'},
|
||||
{key: 'stripe_publishable_key', type: 'members'},
|
||||
{key: 'stripe_connect_secret_key', type: 'members'},
|
||||
{key: 'stripe_connect_publishable_key', type: 'members'},
|
||||
{key: 'stripe_connect_account_id', type: 'members'},
|
||||
{key: 'stripe_connect_display_name', type: 'members'},
|
||||
{key: 'stripe_connect_livemode', type: 'members'},
|
||||
{key: 'portal_name', type: 'portal'},
|
||||
{key: 'portal_button', type: 'portal'},
|
||||
{key: 'portal_plans', type: 'portal'},
|
||||
{key: 'bulk_email_settings', type: 'bulk_email'},
|
||||
{key: 'amp', type: 'blog'},
|
||||
{key: 'labs', type: 'blog'},
|
||||
{key: 'slack', type: 'blog'},
|
||||
{key: 'unsplash', type: 'blog'},
|
||||
{key: 'shared_views', type: 'blog'},
|
||||
{key: 'ghost_head', type: 'blog'},
|
||||
{key: 'ghost_foot', type: 'blog'},
|
||||
{key: 'active_timezone', type: 'blog'},
|
||||
{key: 'default_locale', type: 'blog'}
|
||||
];
|
||||
|
||||
describe('Settings API (v2)', function () {
|
||||
|
@ -81,8 +90,12 @@ describe('Settings API (v2)', function () {
|
|||
jsonResponse.settings.should.be.an.Object();
|
||||
const settings = jsonResponse.settings;
|
||||
|
||||
Object.keys(settings).length.should.equal(39);
|
||||
settings.map(s => ({key: s.key, type: s.type})).should.deepEqual(defaultSettingsKeyTypes);
|
||||
should.equal(settings.length, defaultSettingsKeyTypes.length);
|
||||
for (const defaultSetting of defaultSettingsKeyTypes) {
|
||||
should.exist(settings.find((setting) => {
|
||||
return setting.key === defaultSetting.key && setting.type === defaultSetting.type;
|
||||
}));
|
||||
}
|
||||
|
||||
localUtils.API.checkResponse(jsonResponse, 'settings');
|
||||
});
|
||||
|
|
|
@ -35,8 +35,17 @@ const defaultSettingsKeys = [
|
|||
'password',
|
||||
'public_hash',
|
||||
'default_content_visibility',
|
||||
'members_subscription_settings',
|
||||
'stripe_connect_integration',
|
||||
'members_allow_free_signup',
|
||||
'members_from_address',
|
||||
'stripe_product_name',
|
||||
'stripe_plans',
|
||||
'stripe_secret_key',
|
||||
'stripe_publishable_key',
|
||||
'stripe_connect_secret_key',
|
||||
'stripe_connect_publishable_key',
|
||||
'stripe_connect_account_id',
|
||||
'stripe_connect_display_name',
|
||||
'stripe_connect_livemode',
|
||||
'portal_name',
|
||||
'portal_button',
|
||||
'portal_plans',
|
||||
|
@ -82,8 +91,7 @@ describe('Settings API (v3)', function () {
|
|||
jsonResponse.settings.should.be.an.Object();
|
||||
const settings = jsonResponse.settings;
|
||||
|
||||
Object.keys(settings).length.should.equal(39);
|
||||
settings.map(s => s.key).should.deepEqual(defaultSettingsKeys);
|
||||
settings.map(s => s.key).sort().should.deepEqual(defaultSettingsKeys.sort());
|
||||
|
||||
localUtils.API.checkResponse(jsonResponse, 'settings');
|
||||
});
|
||||
|
|
|
@ -42,19 +42,17 @@ describe('SettingsImporter', function () {
|
|||
|
||||
it('Does not overwrite members from address', function () {
|
||||
const fakeSettings = [{
|
||||
key: 'members_subscription_settings',
|
||||
value: '{"fromAddress":"newemail@example.com"}'
|
||||
key: 'members_from_address',
|
||||
value: 'newemail@example.com'
|
||||
}];
|
||||
|
||||
const importer = new SettingsImporter({settings: fakeSettings}, {dataKeyToImport: 'settings'});
|
||||
|
||||
importer.beforeImport();
|
||||
|
||||
const membersetting = find(importer.dataToImport, {key: 'members_subscription_settings'});
|
||||
const membersSettingsVal = JSON.parse(membersetting.value);
|
||||
const membersFromAddress = membersSettingsVal.fromAddress;
|
||||
const membersFromAddress = find(importer.dataToImport, {key: 'members_from_address'});
|
||||
|
||||
should.not.exist(membersFromAddress);
|
||||
should.not.exist(membersFromAddress.value);
|
||||
});
|
||||
|
||||
it('Adds a problem if the existing data is_private is false, and new data is_private is true', function () {
|
||||
|
|
|
@ -21,42 +21,31 @@ function createConfigMock({stripeDirectValue}) {
|
|||
*/
|
||||
|
||||
function createSettingsMock({setDirect, setConnect}) {
|
||||
const membersSubscriptionSettings = {
|
||||
fromAddress: 'noreply',
|
||||
allowSelfSignup: true,
|
||||
paymentProcessors: [{
|
||||
adapter: 'stripe',
|
||||
config: {
|
||||
secret_token: setDirect ? 'direct_secret' : null,
|
||||
public_token: setDirect ? 'direct_public' : null,
|
||||
product: {
|
||||
name: 'Test'
|
||||
},
|
||||
plans: [{
|
||||
name: 'Monthly',
|
||||
currency: 'usd',
|
||||
interval: 'month',
|
||||
amount: 1000
|
||||
}, {
|
||||
name: 'Yearly',
|
||||
currency: 'usd',
|
||||
interval: 'year',
|
||||
amount: 10000
|
||||
}]
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
const stripeConnectIntegration = {
|
||||
secret_key: setConnect ? 'connect_secret' : null,
|
||||
public_key: setConnect ? 'connect_public' : null,
|
||||
livemode: true
|
||||
};
|
||||
|
||||
const getStub = sinon.stub();
|
||||
|
||||
getStub.withArgs('members_subscription_settings').returns(membersSubscriptionSettings);
|
||||
getStub.withArgs('stripe_connect_integration').returns(stripeConnectIntegration);
|
||||
getStub.withArgs('members_from_address').returns('noreply');
|
||||
getStub.withArgs('members_allow_free_signup').returns(true);
|
||||
getStub.withArgs('stripe_secret_key').returns(setDirect ? 'direct_secret' : null);
|
||||
getStub.withArgs('stripe_publishable_key').returns(setDirect ? 'direct_publishable' : null);
|
||||
getStub.withArgs('stripe_product_name').returns('Test');
|
||||
getStub.withArgs('stripe_plans').returns([{
|
||||
name: 'Monthly',
|
||||
currency: 'usd',
|
||||
interval: 'month',
|
||||
amount: 1000
|
||||
}, {
|
||||
name: 'Yearly',
|
||||
currency: 'usd',
|
||||
interval: 'year',
|
||||
amount: 10000
|
||||
}]);
|
||||
|
||||
getStub.withArgs('stripe_connect_secret_key').returns(setConnect ? 'connect_secret' : null);
|
||||
getStub.withArgs('stripe_connect_publishable_key').returns(setConnect ? 'connect_publishable' : null);
|
||||
getStub.withArgs('stripe_connect_livemode').returns(true);
|
||||
getStub.withArgs('stripe_connect_display_name').returns('Test');
|
||||
getStub.withArgs('stripe_connect_account_id').returns('ac_XXXXXXXXXXXXX');
|
||||
|
||||
return {
|
||||
get: getStub
|
||||
};
|
||||
|
@ -77,7 +66,7 @@ describe('Members - config', function () {
|
|||
|
||||
const paymentConfig = membersConfig.getStripePaymentConfig();
|
||||
|
||||
should.equal(paymentConfig.publicKey, 'direct_public');
|
||||
should.equal(paymentConfig.publicKey, 'direct_publishable');
|
||||
should.equal(paymentConfig.secretKey, 'direct_secret');
|
||||
});
|
||||
|
||||
|
@ -112,7 +101,7 @@ describe('Members - config', function () {
|
|||
|
||||
const paymentConfig = membersConfig.getStripePaymentConfig();
|
||||
|
||||
should.equal(paymentConfig.publicKey, 'connect_public');
|
||||
should.equal(paymentConfig.publicKey, 'connect_publishable');
|
||||
should.equal(paymentConfig.secretKey, 'connect_secret');
|
||||
});
|
||||
|
||||
|
@ -130,7 +119,7 @@ describe('Members - config', function () {
|
|||
|
||||
const paymentConfig = membersConfig.getStripePaymentConfig();
|
||||
|
||||
should.equal(paymentConfig.publicKey, 'direct_public');
|
||||
should.equal(paymentConfig.publicKey, 'direct_publishable');
|
||||
should.equal(paymentConfig.secretKey, 'direct_secret');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue