diff --git a/core/frontend/helpers/ghost_head.js b/core/frontend/helpers/ghost_head.js index 127d55d67b..9701018d8c 100644 --- a/core/frontend/helpers/ghost_head.js +++ b/core/frontend/helpers/ghost_head.js @@ -2,7 +2,7 @@ // Usage: `{{ghost_head}}` // // Outputs scripts and other assets at the top of a Ghost theme -const {metaData, escapeExpression, SafeString, logging, settingsCache, config, blogIcon, labs, urlUtils} = require('../services/proxy'); +const {metaData, escapeExpression, SafeString, logging, settingsCache, config, blogIcon, urlUtils} = require('../services/proxy'); const _ = require('lodash'); const debug = require('ghost-ignition').debug('ghost_head'); const templateStyles = require('./tpl/styles'); @@ -167,7 +167,7 @@ module.exports = function ghost_head(options) { // eslint-disable-line camelcase } } - if (!_.includes(context, 'amp') && labs.isSet('members')) { + if (!_.includes(context, 'amp')) { head.push(getMembersHelper()); } } diff --git a/core/frontend/services/routing/controllers/unsubscribe.js b/core/frontend/services/routing/controllers/unsubscribe.js index fc70841d0d..f788850f75 100644 --- a/core/frontend/services/routing/controllers/unsubscribe.js +++ b/core/frontend/services/routing/controllers/unsubscribe.js @@ -1,16 +1,11 @@ const debug = require('ghost-ignition').debug('services:routing:controllers:unsubscribe'); const path = require('path'); const megaService = require('../../../../server/services/mega'); -const labsService = require('../../../../server/services/labs'); const helpers = require('../../../services/routing/helpers'); -module.exports = async function unsubscribeController(req, res, next) { +module.exports = async function unsubscribeController(req, res) { debug('unsubscribeController'); - if (!labsService.isSet('members')) { - return next(); - } - let data = {}; try { diff --git a/core/server/api/canary/utils/serializers/output/utils/post-gating.js b/core/server/api/canary/utils/serializers/output/utils/post-gating.js index 92c14e4546..fddc98e9cf 100644 --- a/core/server/api/canary/utils/serializers/output/utils/post-gating.js +++ b/core/server/api/canary/utils/serializers/output/utils/post-gating.js @@ -1,5 +1,4 @@ const membersService = require('../../../../../../services/members'); -const labs = require('../../../../../../services/labs'); // @TODO: reconsider the location of this - it's part of members and adds a property to the API const forPost = (attrs, frame) => { @@ -8,21 +7,18 @@ const forPost = (attrs, frame) => { attrs.access = true; } - // Handle members being enabled - if (labs.isSet('members')) { - const memberHasAccess = membersService.contentGating.checkPostAccess(attrs, frame.original.context.member); + const memberHasAccess = membersService.contentGating.checkPostAccess(attrs, frame.original.context.member); - if (!memberHasAccess) { - ['plaintext', 'html'].forEach((field) => { - if (attrs[field] !== undefined) { - attrs[field] = ''; - } - }); - } + if (!memberHasAccess) { + ['plaintext', 'html'].forEach((field) => { + if (attrs[field] !== undefined) { + attrs[field] = ''; + } + }); + } - if (!Object.prototype.hasOwnProperty.call(frame.options, 'columns') || (frame.options.columns.includes('access'))) { - attrs.access = memberHasAccess; - } + if (!Object.prototype.hasOwnProperty.call(frame.options, 'columns') || (frame.options.columns.includes('access'))) { + attrs.access = memberHasAccess; } return attrs; diff --git a/core/server/api/v2/utils/serializers/output/utils/post-gating.js b/core/server/api/v2/utils/serializers/output/utils/post-gating.js index 0511856d40..7fd3d015fb 100644 --- a/core/server/api/v2/utils/serializers/output/utils/post-gating.js +++ b/core/server/api/v2/utils/serializers/output/utils/post-gating.js @@ -1,17 +1,14 @@ const membersService = require('../../../../../../services/members'); -const labs = require('../../../../../../services/labs'); const forPost = (attrs, frame) => { - if (labs.isSet('members')) { - const memberHasAccess = membersService.contentGating.checkPostAccess(attrs, frame.original.context.member); + const memberHasAccess = membersService.contentGating.checkPostAccess(attrs, frame.original.context.member); - if (!memberHasAccess) { - ['plaintext', 'html'].forEach((field) => { - if (attrs[field] !== undefined) { - attrs[field] = ''; - } - }); - } + if (!memberHasAccess) { + ['plaintext', 'html'].forEach((field) => { + if (attrs[field] !== undefined) { + attrs[field] = ''; + } + }); } return attrs; diff --git a/core/server/api/v3/utils/serializers/output/utils/post-gating.js b/core/server/api/v3/utils/serializers/output/utils/post-gating.js index 92c14e4546..fddc98e9cf 100644 --- a/core/server/api/v3/utils/serializers/output/utils/post-gating.js +++ b/core/server/api/v3/utils/serializers/output/utils/post-gating.js @@ -1,5 +1,4 @@ const membersService = require('../../../../../../services/members'); -const labs = require('../../../../../../services/labs'); // @TODO: reconsider the location of this - it's part of members and adds a property to the API const forPost = (attrs, frame) => { @@ -8,21 +7,18 @@ const forPost = (attrs, frame) => { attrs.access = true; } - // Handle members being enabled - if (labs.isSet('members')) { - const memberHasAccess = membersService.contentGating.checkPostAccess(attrs, frame.original.context.member); + const memberHasAccess = membersService.contentGating.checkPostAccess(attrs, frame.original.context.member); - if (!memberHasAccess) { - ['plaintext', 'html'].forEach((field) => { - if (attrs[field] !== undefined) { - attrs[field] = ''; - } - }); - } + if (!memberHasAccess) { + ['plaintext', 'html'].forEach((field) => { + if (attrs[field] !== undefined) { + attrs[field] = ''; + } + }); + } - if (!Object.prototype.hasOwnProperty.call(frame.options, 'columns') || (frame.options.columns.includes('access'))) { - attrs.access = memberHasAccess; - } + if (!Object.prototype.hasOwnProperty.call(frame.options, 'columns') || (frame.options.columns.includes('access'))) { + attrs.access = memberHasAccess; } return attrs; diff --git a/core/server/models/post.js b/core/server/models/post.js index 5610b775aa..96d441e0e4 100644 --- a/core/server/models/post.js +++ b/core/server/models/post.js @@ -45,7 +45,7 @@ Post = ghostBookshelf.Model.extend({ defaults: function defaults() { let visibility = 'public'; - if (settingsCache.get('labs') && (settingsCache.get('labs').members === true) && settingsCache.get('default_content_visibility')) { + if (settingsCache.get('default_content_visibility')) { visibility = settingsCache.get('default_content_visibility'); } diff --git a/core/server/models/settings.js b/core/server/models/settings.js index f13f3250a0..1bccc06cf9 100644 --- a/core/server/models/settings.js +++ b/core/server/models/settings.js @@ -8,7 +8,6 @@ const ghostBookshelf = require('./base'); const {i18n} = require('../lib/common'); const errors = require('@tryghost/errors'); const validation = require('../data/validation'); -const settingsCache = require('../services/settings/cache'); const internalContext = {context: {internal: true}}; let Settings; let defaultSettings; @@ -298,25 +297,6 @@ Settings = ghostBookshelf.Model.extend({ }, permissible: function permissible(modelId, action, context, unsafeAttrs, loadedPermissions, hasUserPermission, hasApiKeyPermission) { - let isEdit = (action === 'edit'); - let isOwner; - - function isChangingMembers() { - if (unsafeAttrs && unsafeAttrs.key === 'labs') { - let editedValue = JSON.parse(unsafeAttrs.value); - if (editedValue.members !== undefined) { - return editedValue.members !== settingsCache.get('labs').members; - } - } - } - - isOwner = loadedPermissions.user && _.some(loadedPermissions.user.roles, {name: 'Owner'}); - - if (isEdit && isChangingMembers()) { - // Only allow owner to toggle members flag - hasUserPermission = isOwner; - } - if (hasUserPermission && hasApiKeyPermission) { return Promise.resolve(); } diff --git a/core/server/services/auth/authorize.js b/core/server/services/auth/authorize.js index 542f206ada..cfbfe439c2 100644 --- a/core/server/services/auth/authorize.js +++ b/core/server/services/auth/authorize.js @@ -1,4 +1,3 @@ -const labs = require('../labs'); const errors = require('@tryghost/errors'); const {i18n} = require('../../lib/common'); @@ -9,7 +8,7 @@ const authorize = { if (hasApiKey) { return next(); } - if (labs.isSet('members') && hasMember) { + if (hasMember) { return next(); } return next(new errors.NoPermissionError({ diff --git a/core/server/services/auth/members/index.js b/core/server/services/auth/members/index.js index af395b7e54..3621b7294f 100644 --- a/core/server/services/auth/members/index.js +++ b/core/server/services/auth/members/index.js @@ -1,18 +1,11 @@ const jwt = require('express-jwt'); const membersService = require('../../members'); -const labs = require('../../labs'); const config = require('../../../../shared/config'); let UNO_MEMBERINO; module.exports = { get authenticateMembersToken() { - if (!labs.isSet('members')) { - return function (req, res, next) { - return next(); - }; - } - if (!UNO_MEMBERINO) { const url = require('url'); const {protocol, host} = url.parse(config.get('url')); diff --git a/core/server/services/members/config.js b/core/server/services/members/config.js index f03cf3f0db..80013271e3 100644 --- a/core/server/services/members/config.js +++ b/core/server/services/members/config.js @@ -1,5 +1,6 @@ const {URL} = require('url'); const crypto = require('crypto'); +const createKeypair = require('keypair'); const path = require('path'); const COMPLIMENTARY_PLAN = { @@ -230,10 +231,20 @@ class MembersConfigProvider { this._urlUtils.urlFor('admin', true) ); + let privateKey = this._settingsCache.get('members_private_key'); + let publicKey = this._settingsCache.get('members_public_key'); + + if (!privateKey || !publicKey) { + this._logging.warn('Could not find members_private_key, using dynamically generated keypair'); + const keypair = createKeypair({bits: 1024}); + privateKey = keypair.private; + publicKey = keypair.public; + } + return { issuer: membersApiUrl, - publicKey: this._settingsCache.get('members_public_key'), - privateKey: this._settingsCache.get('members_private_key') + publicKey, + privateKey }; } diff --git a/core/server/services/members/middleware.js b/core/server/services/members/middleware.js index e7b404ffef..4956769e13 100644 --- a/core/server/services/members/middleware.js +++ b/core/server/services/members/middleware.js @@ -1,6 +1,5 @@ const _ = require('lodash'); const logging = require('../../../shared/logging'); -const labsService = require('../labs'); const membersService = require('./index'); const urlUtils = require('../../../shared/url-utils'); const ghostVersion = require('../../lib/ghost-version'); @@ -10,10 +9,6 @@ const {formattedMemberResponse} = require('./utils'); // @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) const loadMemberSession = async function (req, res, next) { - if (!labsService.isSet('members')) { - req.member = null; - return next(); - } try { const member = await membersService.ssr.getMemberDataFromSession(req, res); Object.assign(req, {member}); diff --git a/core/server/web/api/canary/admin/routes.js b/core/server/web/api/canary/admin/routes.js index 4e60fed8fb..34671219c1 100644 --- a/core/server/web/api/canary/admin/routes.js +++ b/core/server/web/api/canary/admin/routes.js @@ -88,31 +88,30 @@ module.exports = function apiRoutes() { router.del('/tags/:id', mw.authAdminApi, http(apiCanary.tags.destroy)); // ## Members - router.get('/members', shared.middlewares.labs.members, mw.authAdminApi, http(apiCanary.members.browse)); - router.post('/members', shared.middlewares.labs.members, mw.authAdminApi, http(apiCanary.members.add)); + router.get('/members', mw.authAdminApi, http(apiCanary.members.browse)); + router.post('/members', mw.authAdminApi, http(apiCanary.members.add)); - router.get('/members/stats', shared.middlewares.labs.members, mw.authAdminApi, http(apiCanary.members.stats)); + router.get('/members/stats', mw.authAdminApi, http(apiCanary.members.stats)); - router.get('/members/upload', shared.middlewares.labs.members, mw.authAdminApi, http(apiCanary.members.exportCSV)); + router.get('/members/upload', mw.authAdminApi, http(apiCanary.members.exportCSV)); router.post('/members/upload', - shared.middlewares.labs.members, mw.authAdminApi, apiMw.upload.single('membersfile'), apiMw.upload.validation({type: 'members'}), http(apiCanary.members.importCSV) ); - router.get('/members/hasActiveStripeSubscriptions', shared.middlewares.labs.members, mw.authAdminApi, http(apiCanary.members.hasActiveStripeSubscriptions)); + router.get('/members/hasActiveStripeSubscriptions', mw.authAdminApi, http(apiCanary.members.hasActiveStripeSubscriptions)); - router.get('/members/stripe_connect', shared.middlewares.labs.members, mw.authAdminApi, http(apiCanary.membersStripeConnect.auth)); + router.get('/members/stripe_connect', mw.authAdminApi, http(apiCanary.membersStripeConnect.auth)); - router.get('/members/:id', shared.middlewares.labs.members, mw.authAdminApi, http(apiCanary.members.read)); - router.put('/members/:id', shared.middlewares.labs.members, mw.authAdminApi, http(apiCanary.members.edit)); - router.del('/members/:id', shared.middlewares.labs.members, mw.authAdminApi, http(apiCanary.members.destroy)); + router.get('/members/:id', mw.authAdminApi, http(apiCanary.members.read)); + router.put('/members/:id', mw.authAdminApi, http(apiCanary.members.edit)); + router.del('/members/:id', mw.authAdminApi, http(apiCanary.members.destroy)); - router.put('/members/:id/subscriptions/:subscription_id', shared.middlewares.labs.members, mw.authAdminApi, http(apiCanary.members.editSubscription)); + router.put('/members/:id/subscriptions/:subscription_id', mw.authAdminApi, http(apiCanary.members.editSubscription)); - router.get('/members/:id/signin_urls', shared.middlewares.labs.members, mw.authAdminApi, http(apiCanary.memberSigninUrls.read)); + router.get('/members/:id/signin_urls', mw.authAdminApi, http(apiCanary.memberSigninUrls.read)); // ## Labels router.get('/labels', mw.authAdminApi, http(apiCanary.labels.browse)); diff --git a/core/server/web/api/v3/admin/routes.js b/core/server/web/api/v3/admin/routes.js index b218360e76..299aef2883 100644 --- a/core/server/web/api/v3/admin/routes.js +++ b/core/server/web/api/v3/admin/routes.js @@ -88,31 +88,30 @@ module.exports = function apiRoutes() { router.del('/tags/:id', mw.authAdminApi, http(api.tags.destroy)); // ## Members - router.get('/members', shared.middlewares.labs.members, mw.authAdminApi, http(api.members.browse)); - router.post('/members', shared.middlewares.labs.members, mw.authAdminApi, http(api.members.add)); + router.get('/members', mw.authAdminApi, http(api.members.browse)); + router.post('/members', mw.authAdminApi, http(api.members.add)); - router.get('/members/stats', shared.middlewares.labs.members, mw.authAdminApi, http(api.members.stats)); + router.get('/members/stats', mw.authAdminApi, http(api.members.stats)); - router.get('/members/upload', shared.middlewares.labs.members, mw.authAdminApi, http(api.members.exportCSV)); + router.get('/members/upload', mw.authAdminApi, http(api.members.exportCSV)); router.post('/members/upload', - shared.middlewares.labs.members, mw.authAdminApi, apiMw.upload.single('membersfile'), apiMw.upload.validation({type: 'members'}), http(api.members.importCSV) ); - router.get('/members/hasActiveStripeSubscriptions', shared.middlewares.labs.members, mw.authAdminApi, http(api.members.hasActiveStripeSubscriptions)); + router.get('/members/hasActiveStripeSubscriptions', mw.authAdminApi, http(api.members.hasActiveStripeSubscriptions)); - router.get('/members/stripe_connect', shared.middlewares.labs.members, mw.authAdminApi, http(api.membersStripeConnect.auth)); + router.get('/members/stripe_connect', mw.authAdminApi, http(api.membersStripeConnect.auth)); - router.get('/members/:id', shared.middlewares.labs.members, mw.authAdminApi, http(api.members.read)); - router.put('/members/:id', shared.middlewares.labs.members, mw.authAdminApi, http(api.members.edit)); - router.del('/members/:id', shared.middlewares.labs.members, mw.authAdminApi, http(api.members.destroy)); + router.get('/members/:id', mw.authAdminApi, http(api.members.read)); + router.put('/members/:id', mw.authAdminApi, http(api.members.edit)); + router.del('/members/:id', mw.authAdminApi, http(api.members.destroy)); - router.put('/members/:id/subscriptions/:subscription_id', shared.middlewares.labs.members, mw.authAdminApi, http(api.members.editSubscription)); + router.put('/members/:id/subscriptions/:subscription_id', mw.authAdminApi, http(api.members.editSubscription)); - router.get('/members/:id/signin_urls', shared.middlewares.labs.members, mw.authAdminApi, http(api.memberSigninUrls.read)); + router.get('/members/:id/signin_urls', mw.authAdminApi, http(api.memberSigninUrls.read)); // ## Labels router.get('/labels', mw.authAdminApi, http(api.labels.browse)); diff --git a/core/server/web/members/app.js b/core/server/web/members/app.js index 2ec4efb470..0a2e299156 100644 --- a/core/server/web/members/app.js +++ b/core/server/web/members/app.js @@ -15,9 +15,6 @@ module.exports = function setupMembersApp() { // send 503 json response in case of maintenance membersApp.use(shared.middlewares.maintenance); - // Entire app is behind labs flag - membersApp.use(shared.middlewares.labs.members); - // Support CORS for requests from the frontend const siteUrl = new URL(urlUtils.getSiteUrl()); membersApp.use(cors(siteUrl.origin)); diff --git a/core/server/web/shared/middlewares/labs.js b/core/server/web/shared/middlewares/labs.js index ff429dd268..0c1b926f76 100644 --- a/core/server/web/shared/middlewares/labs.js +++ b/core/server/web/shared/middlewares/labs.js @@ -9,6 +9,4 @@ const labs = flag => (req, res, next) => { } }; -labs.members = labs('members'); - module.exports = labs; diff --git a/test/frontend-acceptance/members_spec.js b/test/frontend-acceptance/members_spec.js index c34c7bc50c..66566c6c60 100644 --- a/test/frontend-acceptance/members_spec.js +++ b/test/frontend-acceptance/members_spec.js @@ -16,155 +16,78 @@ describe('Basic Members Routes', function () { request = supertest.agent(configUtils.config.get('url')); }); - describe('Members enabled', function () { - before(function () { - const originalSettingsCacheGetFn = settingsCache.get; + before(function () { + const originalSettingsCacheGetFn = settingsCache.get; - sinon.stub(settingsCache, 'get').callsFake(function (key, options) { - if (key === 'labs') { - return {members: true}; - } + sinon.stub(settingsCache, 'get').callsFake(function (key, options) { + if (key === 'labs') { + return {members: true}; + } - return originalSettingsCacheGetFn(key, options); - }); - }); - - after(function () { - sinon.restore(); - }); - - describe('Routes', function () { - it('should error serving webhook endpoint without any parameters', async function () { - await request.post('/members/webhooks/stripe') - .expect(400); - }); - - it('should error when invalid member token is passed into session', async function () { - await request.get('/members/api/session') - .expect(400); - }); - - it('should return no content when removing member sessions', async function () { - await request.del('/members/api/session') - .expect(204); - }); - - it('should error for invalid member token on member data endpoint', async function () { - await request.get('/members/api/member') - .expect(400); - }); - - 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); - }); - - it('should error for invalid data on members create checkout session endpoint', async function () { - await request.post('/members/api/create-stripe-checkout-session') - .expect(400); - }); - - it('should error for invalid data on members create update session endpoint', async function () { - await request.post('/members/api/create-stripe-update-session') - .expect(400); - }); - - it('should error for invalid data on members subscription endpoint', async function () { - await request.put('/members/api/subscriptions/123') - .expect(400); - }); - - it('should serve theme 404 on members endpoint', async function () { - await request.get('/members/') - .expect(404) - .expect('Content-Type', 'text/html; charset=utf-8'); - }); - - it('should redirect invalid token on members endpoint', async function () { - await request.get('/members/?token=abc&action=signup') - .expect(302) - .expect('Location', '/?action=signup&success=false'); - }); + return originalSettingsCacheGetFn(key, options); }); }); - describe('Members disabled', function () { - before(function () { - const originalSettingsCacheGetFn = settingsCache.get; + after(function () { + sinon.restore(); + }); - sinon.stub(settingsCache, 'get').callsFake(function (key, options) { - if (key === 'labs') { - return {members: false}; - } - - return originalSettingsCacheGetFn(key, options); - }); + describe('Routes', function () { + it('should error serving webhook endpoint without any parameters', async function () { + await request.post('/members/webhooks/stripe') + .expect(400); }); - after(function () { - sinon.restore(); + it('should error when invalid member token is passed into session', async function () { + await request.get('/members/api/session') + .expect(400); }); - describe('Routes', function () { - it('should not serve webhook endpoint', async function () { - await request.post('/members/webhooks/stripe') - .expect(404); - }); + it('should return no content when removing member sessions', async function () { + await request.del('/members/api/session') + .expect(204); + }); - it('should not serve session endpoint', async function () { - await request.get('/members/api/session') - .expect(404); - }); + it('should error for invalid member token on member data endpoint', async function () { + await request.get('/members/api/member') + .expect(400); + }); - it('should not serve session removal endpoint', async function () { - await request.del('/members/api/session') - .expect(404); - }); + it('should serve member site endpoint', async function () { + await request.get('/members/api/site') + .expect(200); + }); - it('should not serve member data endpoint', async function () { - await request.get('/members/api/member') - .expect(404); - }); + it('should error for invalid data on member magic link endpoint', async function () { + await request.post('/members/api/send-magic-link') + .expect(400); + }); - it('should not serve member site endpoint', async function () { - await request.get('/members/api/site') - .expect(404); - }); + it('should error for invalid data on members create checkout session endpoint', async function () { + await request.post('/members/api/create-stripe-checkout-session') + .expect(400); + }); - it('should not serve member magic link endpoint', async function () { - await request.post('/members/api/send-magic-link') - .expect(404); - }); + it('should error for invalid data on members create update session endpoint', async function () { + await request.post('/members/api/create-stripe-update-session') + .expect(400); + }); - it('should not serve members create checkout session endpoint', async function () { - await request.post('/members/api/create-stripe-checkout-session') - .expect(404); - }); + it('should error for invalid data on members subscription endpoint', async function () { + await request.put('/members/api/subscriptions/123') + .expect(400); + }); - it('should not serve members create update session endpoint', async function () { - await request.post('/members/api/create-stripe-update-session') - .expect(404); - }); + it('should serve theme 404 on members endpoint', async function () { + await request.get('/members/') + .expect(404) + .expect('Content-Type', 'text/html; charset=utf-8'); + }); - it('should not serve members subscription endpoint', async function () { - await request.put('/members/api/subscriptions/123') - .expect(404); - }); - - it('should serve 404 on members endpoint', async function () { - await request.get('/members/') - .expect(404); - }); - - it('should not redirect members endpoint with token', async function () { - await request.get('/members/?token=abc&action=signup') - .expect(404); - }); + it('should redirect invalid token on members endpoint', async function () { + await request.get('/members/?token=abc&action=signup') + .expect(302) + .expect('Location', '/?action=signup&success=false'); }); }); }); diff --git a/test/regression/api/canary/admin/settings_spec.js b/test/regression/api/canary/admin/settings_spec.js index fc35df69fa..bb571ba3ed 100644 --- a/test/regression/api/canary/admin/settings_spec.js +++ b/test/regression/api/canary/admin/settings_spec.js @@ -363,43 +363,6 @@ describe('Settings API (canary)', function () { }); }); - it('can toggle member setting', function () { - return request.get(localUtils.API.getApiQuery('settings/')) - .set('Origin', config.get('url')) - .expect('Content-Type', /json/) - .expect('Cache-Control', testUtils.cacheRules.private) - .then(function (res) { - const jsonResponse = res.body; - - const settingToChange = { - settings: [ - { - key: 'labs', - value: '{"subscribers":false,"members":false}' - } - ] - }; - - should.exist(jsonResponse); - should.exist(jsonResponse.settings); - - return request.put(localUtils.API.getApiQuery('settings/')) - .set('Origin', config.get('url')) - .send(settingToChange) - .expect('Content-Type', /json/) - .expect('Cache-Control', testUtils.cacheRules.private) - .expect(200) - .then(function ({body, headers}) { - const putBody = body; - headers['x-cache-invalidate'].should.eql('/*'); - should.exist(putBody); - - putBody.settings[0].key.should.eql('labs'); - putBody.settings[0].value.should.eql(JSON.stringify({subscribers: false, members: false})); - }); - }); - }); - it('can\'t edit permalinks', function (done) { const settingToChange = { settings: [{key: 'permalinks', value: '/:primary_author/:slug/'}] @@ -521,31 +484,6 @@ describe('Settings API (canary)', function () { return localUtils.doAuth(request); }); }); - - it('cannot toggle member setting', function (done) { - const settingToChange = { - settings: [ - { - key: 'labs', - value: '{"subscribers":false,"members":true}' - } - ] - }; - - request.put(localUtils.API.getApiQuery('settings/')) - .set('Origin', config.get('url')) - .send(settingToChange) - .expect('Content-Type', /json/) - .expect('Cache-Control', testUtils.cacheRules.private) - .expect(403) - .end(function (err, res) { - if (err) { - return done(err); - } - - done(); - }); - }); }); describe('As Editor', function () { diff --git a/test/regression/api/v2/admin/settings_spec.js b/test/regression/api/v2/admin/settings_spec.js index fc483e0c4b..3320f678e9 100644 --- a/test/regression/api/v2/admin/settings_spec.js +++ b/test/regression/api/v2/admin/settings_spec.js @@ -368,44 +368,6 @@ describe('Settings API (v2)', function () { }); }); - it('can toggle member setting', function () { - return request.get(localUtils.API.getApiQuery('settings/')) - .set('Origin', config.get('url')) - .expect('Content-Type', /json/) - .expect('Cache-Control', testUtils.cacheRules.private) - .then(function (res) { - const jsonResponse = res.body; - const changedValue = []; - - const settingToChange = { - settings: [ - { - key: 'labs', - value: '{"subscribers":false,"members":false}' - } - ] - }; - - should.exist(jsonResponse); - should.exist(jsonResponse.settings); - - return request.put(localUtils.API.getApiQuery('settings/')) - .set('Origin', config.get('url')) - .send(settingToChange) - .expect('Content-Type', /json/) - .expect('Cache-Control', testUtils.cacheRules.private) - .expect(200) - .then(function ({body, headers}) { - const putBody = body; - headers['x-cache-invalidate'].should.eql('/*'); - should.exist(putBody); - - putBody.settings[0].key.should.eql('labs'); - putBody.settings[0].value.should.eql(JSON.stringify({subscribers: false, members: false})); - }); - }); - }); - it('can\'t edit permalinks', function (done) { const settingToChange = { settings: [{key: 'permalinks', value: '/:primary_author/:slug/'}] @@ -524,31 +486,6 @@ describe('Settings API (v2)', function () { return localUtils.doAuth(request); }); }); - - it('cannot toggle member setting', function (done) { - const settingToChange = { - settings: [ - { - key: 'labs', - value: '{"subscribers":false,"members":true}' - } - ] - }; - - request.put(localUtils.API.getApiQuery('settings/')) - .set('Origin', config.get('url')) - .send(settingToChange) - .expect('Content-Type', /json/) - .expect('Cache-Control', testUtils.cacheRules.private) - .expect(403) - .end(function (err, res) { - if (err) { - return done(err); - } - - done(); - }); - }); }); describe('As Editor', function () { diff --git a/test/regression/api/v3/admin/settings_spec.js b/test/regression/api/v3/admin/settings_spec.js index 52025233aa..c60796a867 100644 --- a/test/regression/api/v3/admin/settings_spec.js +++ b/test/regression/api/v3/admin/settings_spec.js @@ -408,43 +408,6 @@ describe('Settings API (v3)', function () { }); }); - it('can toggle member setting', function () { - return request.get(localUtils.API.getApiQuery('settings/')) - .set('Origin', config.get('url')) - .expect('Content-Type', /json/) - .expect('Cache-Control', testUtils.cacheRules.private) - .then(function (res) { - const jsonResponse = res.body; - - const settingToChange = { - settings: [ - { - key: 'labs', - value: '{"subscribers":false,"members":false}' - } - ] - }; - - should.exist(jsonResponse); - should.exist(jsonResponse.settings); - - return request.put(localUtils.API.getApiQuery('settings/')) - .set('Origin', config.get('url')) - .send(settingToChange) - .expect('Content-Type', /json/) - .expect('Cache-Control', testUtils.cacheRules.private) - .expect(200) - .then(function ({body, headers}) { - const putBody = body; - headers['x-cache-invalidate'].should.eql('/*'); - should.exist(putBody); - - putBody.settings[0].key.should.eql('labs'); - putBody.settings[0].value.should.eql(JSON.stringify({subscribers: false, members: false})); - }); - }); - }); - it('can\'t edit permalinks', function (done) { const settingToChange = { settings: [{key: 'permalinks', value: '/:primary_author/:slug/'}] @@ -566,31 +529,6 @@ describe('Settings API (v3)', function () { return localUtils.doAuth(request); }); }); - - it('cannot toggle member setting', function (done) { - const settingToChange = { - settings: [ - { - key: 'labs', - value: '{"subscribers":false,"members":true}' - } - ] - }; - - request.put(localUtils.API.getApiQuery('settings/')) - .set('Origin', config.get('url')) - .send(settingToChange) - .expect('Content-Type', /json/) - .expect('Cache-Control', testUtils.cacheRules.private) - .expect(403) - .end(function (err, res) { - if (err) { - return done(err); - } - - done(); - }); - }); }); describe('As Editor', function () { diff --git a/test/unit/api/canary/utils/serializers/output/utils/mapper_spec.js b/test/unit/api/canary/utils/serializers/output/utils/mapper_spec.js index 35d63cadf0..f3f0e0238a 100644 --- a/test/unit/api/canary/utils/serializers/output/utils/mapper_spec.js +++ b/test/unit/api/canary/utils/serializers/output/utils/mapper_spec.js @@ -39,6 +39,9 @@ describe('Unit: canary/utils/serializers/output/utils/mapper', function () { it('calls mapper on relations', function () { const frame = { + original: { + context: {} + }, options: { withRelated: ['tags', 'authors'], context: {} diff --git a/test/unit/api/canary/utils/serializers/output/utils/post-gating_spec.js b/test/unit/api/canary/utils/serializers/output/utils/post-gating_spec.js index c4803d92b2..5efdd660f3 100644 --- a/test/unit/api/canary/utils/serializers/output/utils/post-gating_spec.js +++ b/test/unit/api/canary/utils/serializers/output/utils/post-gating_spec.js @@ -1,137 +1,115 @@ const should = require('should'); -const sinon = require('sinon'); -const labs = require('../../../../../../../../core/server/services/labs'); const gating = require('../../../../../../../../core/server/api/canary/utils/serializers/output/utils/post-gating'); describe('Unit: canary/utils/serializers/output/utils/post-gating', function () { describe('for post', function () { - it('does not modify attributes when members is disabled', function () { + it('should NOT hide content attributes when visibility is public', function () { const attrs = { + visibility: 'public', plaintext: 'no touching', html: '

I am here to stay

' }; const frame = { - options: {} + options: {}, + original: { + context: {} + } }; + gating.forPost(attrs, frame); attrs.plaintext.should.eql('no touching'); }); - describe('labs.members enabled', function () { - before(function () { - sinon.stub(labs, 'isSet').returns(true); - }); + it('should hide content attributes when visibility is "members"', function () { + const attrs = { + visibility: 'members', + plaintext: 'no touching. secret stuff', + html: '

I am here to stay

' + }; - it('should NOT hide content attributes when visibility is public', function () { - const attrs = { - visibility: 'public', - plaintext: 'no touching', - html: '

I am here to stay

' - }; + const frame = { + options: {}, + original: { + context: {} + } + }; - const frame = { - options: {}, - original: { - context: {} + gating.forPost(attrs, frame); + + attrs.plaintext.should.eql(''); + attrs.html.should.eql(''); + }); + + it('should NOT hide content attributes when visibility is "members" and member is present', function () { + const attrs = { + visibility: 'members', + plaintext: 'I see dead people', + html: '

What\'s the matter?

' + }; + + const frame = { + options: {}, + original: { + context: { + member: {} } - }; + } + }; - gating.forPost(attrs, frame); + gating.forPost(attrs, frame); - attrs.plaintext.should.eql('no touching'); - }); + attrs.plaintext.should.eql('I see dead people'); + attrs.html.should.eql('

What\'s the matter?

'); + }); - it('should hide content attributes when visibility is "members"', function () { - const attrs = { - visibility: 'members', - plaintext: 'no touching. secret stuff', - html: '

I am here to stay

' - }; + it('should hide content attributes when visibility is "paid" and member has status of "free"', function () { + const attrs = { + visibility: 'paid', + plaintext: 'I see dead people', + html: '

What\'s the matter?

' + }; - const frame = { - options: {}, - original: { - context: {} - } - }; - - gating.forPost(attrs, frame); - - attrs.plaintext.should.eql(''); - attrs.html.should.eql(''); - }); - - it('should NOT hide content attributes when visibility is "members" and member is present', function () { - const attrs = { - visibility: 'members', - plaintext: 'I see dead people', - html: '

What\'s the matter?

' - }; - - const frame = { - options: {}, - original: { - context: { - member: {} + const frame = { + options: {}, + original: { + context: { + member: { + status: 'free' } } - }; + } + }; - gating.forPost(attrs, frame); + gating.forPost(attrs, frame); - attrs.plaintext.should.eql('I see dead people'); - attrs.html.should.eql('

What\'s the matter?

'); - }); + attrs.plaintext.should.eql(''); + attrs.html.should.eql(''); + }); - it('should hide content attributes when visibility is "paid" and member has status of "free"', function () { - const attrs = { - visibility: 'paid', - plaintext: 'I see dead people', - html: '

What\'s the matter?

' - }; + it('should NOT hide content attributes when visibility is "paid" and member has status of "paid"', function () { + const attrs = { + visibility: 'paid', + plaintext: 'Secret paid content', + html: '

Can read this

' + }; - const frame = { - options: {}, - original: { - context: { - member: { - status: 'free' - } + const frame = { + options: {}, + original: { + context: { + member: { + status: 'paid' } } - }; + } + }; - gating.forPost(attrs, frame); + gating.forPost(attrs, frame); - attrs.plaintext.should.eql(''); - attrs.html.should.eql(''); - }); - - it('should NOT hide content attributes when visibility is "paid" and member has status of "paid"', function () { - const attrs = { - visibility: 'paid', - plaintext: 'Secret paid content', - html: '

Can read this

' - }; - - const frame = { - options: {}, - original: { - context: { - member: { - status: 'paid' - } - } - } - }; - - gating.forPost(attrs, frame); - - attrs.plaintext.should.eql('Secret paid content'); - attrs.html.should.eql('

Can read this

'); - }); + attrs.plaintext.should.eql('Secret paid content'); + attrs.html.should.eql('

Can read this

'); }); }); }); diff --git a/test/unit/api/v2/utils/serializers/output/utils/mapper_spec.js b/test/unit/api/v2/utils/serializers/output/utils/mapper_spec.js index c938993048..c6b2fb67c5 100644 --- a/test/unit/api/v2/utils/serializers/output/utils/mapper_spec.js +++ b/test/unit/api/v2/utils/serializers/output/utils/mapper_spec.js @@ -39,6 +39,9 @@ describe('Unit: v2/utils/serializers/output/utils/mapper', function () { it('calls mapper on relations', function () { const frame = { + original: { + context: {} + }, options: { withRelated: ['tags', 'authors'], context: {} diff --git a/test/unit/api/v2/utils/serializers/output/utils/post-gating_spec.js b/test/unit/api/v2/utils/serializers/output/utils/post-gating_spec.js index 3cebdb7628..fba19e81c4 100644 --- a/test/unit/api/v2/utils/serializers/output/utils/post-gating_spec.js +++ b/test/unit/api/v2/utils/serializers/output/utils/post-gating_spec.js @@ -1,133 +1,132 @@ const should = require('should'); -const sinon = require('sinon'); -const labs = require('../../../../../../../../core/server/services/labs'); const gating = require('../../../../../../../../core/server/api/v2/utils/serializers/output/utils/post-gating'); describe('Unit: v2/utils/serializers/output/utils/post-gating', function () { describe('for post', function () { - it('does not modify attributes when members is disabled', function () { + it('should NOT hide content attributes when visibility is public', function () { const attrs = { + visibility: 'public', plaintext: 'no touching', html: '

I am here to stay

' }; const frame = { - options: {} + original: { + context: {} + } }; + gating.forPost(attrs, frame); attrs.plaintext.should.eql('no touching'); }); - describe('labs.members enabled', function () { - before(function () { - sinon.stub(labs, 'isSet').returns(true); - }); + it('should hide content attributes when visibility is "members"', function () { + const attrs = { + visibility: 'members', + plaintext: 'no touching. secret stuff', + html: '

I am here to stay

' + }; - it('should NOT hide content attributes when visibility is public', function () { - const attrs = { - visibility: 'public', - plaintext: 'no touching', - html: '

I am here to stay

' - }; + const frame = { + original: { + context: {} + } + }; - const frame = { - original: { - context: {} + gating.forPost(attrs, frame); + + attrs.plaintext.should.eql(''); + attrs.html.should.eql(''); + }); + + it('should NOT hide content attributes when visibility is "members" and member is present', function () { + const attrs = { + visibility: 'members', + plaintext: 'I see dead people', + html: '

What\'s the matter?

' + }; + + const frame = { + original: { + context: { + member: {} } - }; + } + }; - gating.forPost(attrs, frame); + gating.forPost(attrs, frame); - attrs.plaintext.should.eql('no touching'); - }); + attrs.plaintext.should.eql('I see dead people'); + attrs.html.should.eql('

What\'s the matter?

'); + }); - it('should hide content attributes when visibility is "members"', function () { - const attrs = { - visibility: 'members', - plaintext: 'no touching. secret stuff', - html: '

I am here to stay

' - }; + it('should hide content attributes when visibility is "paid" and member has no subscription', function () { + const attrs = { + visibility: 'paid', + plaintext: 'I see dead people', + html: '

What\'s the matter?

' + }; - const frame = { - original: { - context: {} + const frame = { + original: { + context: { + member: {} } - }; + } + }; - gating.forPost(attrs, frame); + gating.forPost(attrs, frame); - attrs.plaintext.should.eql(''); - attrs.html.should.eql(''); - }); + attrs.plaintext.should.eql(''); + attrs.html.should.eql(''); + }); - it('should NOT hide content attributes when visibility is "members" and member is present', function () { - const attrs = { - visibility: 'members', - plaintext: 'I see dead people', - html: '

What\'s the matter?

' - }; + it('should hide content attributes when visibility is "paid" and member has status of "free"', function () { + const attrs = { + visibility: 'paid', + plaintext: 'I see dead people', + html: '

What\'s the matter?

' + }; - const frame = { - original: { - context: { - member: {} + const frame = { + original: { + context: { + member: { + status: 'free' } } - }; + } + }; - gating.forPost(attrs, frame); + gating.forPost(attrs, frame); - attrs.plaintext.should.eql('I see dead people'); - attrs.html.should.eql('

What\'s the matter?

'); - }); + attrs.plaintext.should.eql(''); + attrs.html.should.eql(''); + }); - it('should hide content attributes when visibility is "paid" and member has status of "free"', function () { - const attrs = { - visibility: 'paid', - plaintext: 'I see dead people', - html: '

What\'s the matter?

' - }; + it('should NOT hide content attributes when visibility is "paid" and member has status of "paid"', function () { + const attrs = { + visibility: 'paid', + plaintext: 'Secret paid content', + html: '

Can read this

' + }; - const frame = { - original: { - context: { - member: { - status: 'free' - } + const frame = { + options: {}, + original: { + context: { + member: { + status: 'paid' } } - }; + } + }; - gating.forPost(attrs, frame); + gating.forPost(attrs, frame); - attrs.plaintext.should.eql(''); - attrs.html.should.eql(''); - }); - - it('should NOT hide content attributes when visibility is "paid" and member has status of "paid"', function () { - const attrs = { - visibility: 'paid', - plaintext: 'Secret paid content', - html: '

Can read this

' - }; - - const frame = { - options: {}, - original: { - context: { - member: { - status: 'paid' - } - } - } - }; - - gating.forPost(attrs, frame); - - attrs.plaintext.should.eql('Secret paid content'); - attrs.html.should.eql('

Can read this

'); - }); + attrs.plaintext.should.eql('Secret paid content'); + attrs.html.should.eql('

Can read this

'); }); }); }); diff --git a/test/unit/api/v3/utils/serializers/output/utils/mapper_spec.js b/test/unit/api/v3/utils/serializers/output/utils/mapper_spec.js index 1866791994..5bc005e416 100644 --- a/test/unit/api/v3/utils/serializers/output/utils/mapper_spec.js +++ b/test/unit/api/v3/utils/serializers/output/utils/mapper_spec.js @@ -39,6 +39,9 @@ describe('Unit: v3/utils/serializers/output/utils/mapper', function () { it('calls mapper on relations', function () { const frame = { + original: { + context: {} + }, options: { withRelated: ['tags', 'authors'], context: {}