0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00

🔥 Removed members/api/site

closes: https://github.com/TryGhost/Team/issues/1599

- remove the now unused members/api/site endpoint
- portal now talks to the content API instead
This commit is contained in:
Hannah Wolfe 2022-05-12 16:10:58 +01:00
parent 0d379a9264
commit 962971c436
No known key found for this signature in database
GPG key ID: AB586C3B5AE5C037
5 changed files with 0 additions and 214 deletions

View file

@ -4,12 +4,9 @@ const membersService = require('./service');
const models = require('../../models');
const offersService = require('../offers/service');
const urlUtils = require('../../../shared/url-utils');
const ghostVersion = require('@tryghost/version');
const settingsCache = require('../../../shared/settings-cache');
const {formattedMemberResponse} = require('./utils');
const labsService = require('../../../shared/labs');
const config = require('../../../shared/config');
const newslettersService = require('../newsletters');
// @TODO: This piece of middleware actually belongs to the frontend, not to the member app
// Need to figure a way to separate these things (e.g. frontend actually talks to members API)
@ -149,114 +146,6 @@ const updateMemberData = async function (req, res) {
}
};
const getPortalProductPrices = async function () {
const page = await membersService.api.productRepository.list({
withRelated: ['monthlyPrice', 'yearlyPrice', 'benefits']
});
const products = page.data.map((productModel) => {
const product = productModel.toJSON();
const productPrices = [];
if (product.monthlyPrice) {
productPrices.push(product.monthlyPrice);
}
if (product.yearlyPrice) {
productPrices.push(product.yearlyPrice);
}
return {
id: product.id,
name: product.name,
description: product.description || '',
monthlyPrice: product.monthlyPrice,
yearlyPrice: product.yearlyPrice,
benefits: product.benefits,
active: product.active,
type: product.type,
visibility: product.visibility,
prices: productPrices
};
}).filter((product) => {
return !!product.active;
});
const defaultProduct = products.find((product) => {
return product.type === 'paid';
});
const defaultPrices = defaultProduct ? defaultProduct.prices : [];
let portalProducts = defaultProduct ? [defaultProduct] : [];
if (labsService.isSet('multipleProducts')) {
portalProducts = products;
}
return {
prices: defaultPrices,
products: portalProducts
};
};
const getSiteNewsletters = async function () {
try {
return await newslettersService.browse({filter: 'status:active', limit: 'all'});
} catch (err) {
logging.warn('Failed to fetch site newsletters');
logging.warn(err.message);
return [];
}
};
const getMemberSiteData = async function (req, res) {
const isStripeConfigured = membersService.config.isStripeConnected();
const domain = urlUtils.urlFor('home', true).match(new RegExp('^https?://([^/:?#]+)(?:[/:?#]|$)', 'i'));
const firstpromoterId = settingsCache.get('firstpromoter') ? settingsCache.get('firstpromoter_id') : '';
const blogDomain = domain && domain[1];
let supportAddress = settingsCache.get('members_support_address') || 'noreply';
if (!supportAddress.includes('@')) {
supportAddress = `${supportAddress}@${blogDomain}`;
}
const {products = [], prices = []} = await getPortalProductPrices() || {};
const portalVersion = config.get('portal:version');
const newsletters = await getSiteNewsletters();
const response = {
title: settingsCache.get('title'),
description: settingsCache.get('description'),
logo: settingsCache.get('logo'),
icon: settingsCache.get('icon'),
accent_color: settingsCache.get('accent_color'),
url: urlUtils.urlFor('home', true),
version: ghostVersion.safe,
portal_version: portalVersion,
free_price_name: settingsCache.get('members_free_price_name'),
free_price_description: settingsCache.get('members_free_price_description'),
allow_self_signup: membersService.config.getAllowSelfSignup(),
members_signup_access: settingsCache.get('members_signup_access'),
is_stripe_configured: isStripeConfigured,
portal_button: settingsCache.get('portal_button'),
portal_name: settingsCache.get('portal_name'),
portal_plans: settingsCache.get('portal_plans'),
portal_button_icon: settingsCache.get('portal_button_icon'),
portal_button_signup_text: settingsCache.get('portal_button_signup_text'),
portal_button_style: settingsCache.get('portal_button_style'),
firstpromoter_id: firstpromoterId,
members_support_address: supportAddress,
prices,
products
};
if (labsService.isSet('multipleNewsletters')) {
response.newsletters = newsletters;
}
if (labsService.isSet('multipleProducts')) {
response.portal_products = settingsCache.get('portal_products');
}
if (config.get('portal_sentry') && !config.get('portal_sentry').disabled) {
response.portal_sentry = {
dsn: config.get('portal_sentry').dsn,
env: config.get('env')
};
}
res.json({site: response});
};
const createSessionFromMagicLink = async function (req, res, next) {
if (!req.url.includes('token=')) {
return next();
@ -334,6 +223,5 @@ module.exports = {
getOfferData,
updateMemberData,
updateMemberNewsletters,
getMemberSiteData,
deleteSession
};

View file

@ -44,7 +44,6 @@ module.exports = function setupMembersApp() {
membersApp.get('/api/session', middleware.getIdentityToken);
membersApp.get('/api/offers/:id', middleware.getOfferData);
membersApp.delete('/api/session', middleware.deleteSession);
membersApp.get('/api/site', middleware.getMemberSiteData);
// NOTE: this is wrapped in a function to ensure we always go via the getter
membersApp.post('/api/send-magic-link', bodyParser.json(), shared.middleware.brute.membersAuth, (req, res, next) => membersService.api.middleware.sendMagicLink(req, res, next));

View file

@ -53,11 +53,6 @@ describe('Members API', function () {
mockManager.restore();
});
it('Can communicate with the frontend Members API', async function () {
await membersAgent.get('/api/site/')
.expectStatus(200);
});
// @todo: Test what happens when a complementary subscription ends (should create comped -> free event)
// @todo: Test what happens when a complementary subscription starts a paid subscription

View file

@ -94,11 +94,6 @@ describe('Front-end members behaviour', function () {
.expect(204);
});
it('should serve member site endpoint', async function () {
await request.get('/members/api/site')
.expect(200);
});
it('should error for invalid data on member magic link endpoint', async function () {
await request.post('/members/api/send-magic-link')
.expect(400);

View file

@ -148,95 +148,4 @@ describe('Members Service Middleware', function () {
res.redirect.firstCall.args[0].should.eql('https://custom.com/paid/');
});
});
describe('getMemberSiteData', function () {
let req;
let res = {};
let next;
before(function () {
models.init();
sinon.stub(membersService, 'config').get(() => {
return {
isStripeConnected: () => {
return true;
},
getAllowSelfSignup: () => {
return true;
}
};
});
sinon.stub(membersService, 'api').get(() => {
return {
productRepository: {
list: () => {
return {
data: []
};
}
},
getAllowSelfSignup: () => {
return true;
}
};
});
sinon.stub(newslettersService, 'browse').returns(Promise.resolve([]));
sinon.stub(urlUtils, 'urlFor').returns('https://example.com');
sinon.stub(settingsCache, 'get');
sinon.stub(config, 'get');
config.get.withArgs('portal:version').returns('1.22');
settingsCache.get.withArgs('title').returns('Ghost');
settingsCache.get.withArgs('description').returns('site description');
settingsCache.get.withArgs('logo').returns('/content/images/site-logo.png');
settingsCache.get.withArgs('amp').returns(true);
settingsCache.get.returns('');
});
beforeEach(function () {
req = {};
res = {
json: sinon.spy()
};
next = sinon.stub();
sinon.stub(ghostVersion, 'safe').value('4.44');
});
afterEach(function () {
sinon.restore();
});
it('returns site data for portal', async function () {
await membersMiddleware.getMemberSiteData(req, res);
res.json.calledWith({
site: {
title: 'Ghost',
description: 'site description',
logo: '/content/images/site-logo.png',
icon: '',
accent_color: '',
url: 'https://example.com',
version: '4.44',
portal_version: '1.22',
free_price_name: '',
free_price_description: '',
allow_self_signup: true,
members_signup_access: '',
is_stripe_configured: true,
portal_button: '',
portal_name: '',
portal_plans: '',
portal_button_icon: '',
portal_button_signup_text: '',
portal_button_style: '',
firstpromoter_id: '',
members_support_address: 'noreply@example.com',
prices: [],
products: [],
portal_products: '',
newsletters: []
}
}).should.be.true();
});
});
});