mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-04-08 02:52:39 -05:00
Enabled Members for all sites (#12582)
no-issue This removes all references to the members labs setting, any code that was run conditionally behind this flag now runs unconditionally. * Removed usage of Members labs flag * Removed tests for Members disabled * Added dynamic keypair generation for when setting is missing
This commit is contained in:
parent
26ee648397
commit
73f6fd8c51
24 changed files with 298 additions and 621 deletions
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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'));
|
||||
|
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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});
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -9,6 +9,4 @@ const labs = flag => (req, res, next) => {
|
|||
}
|
||||
};
|
||||
|
||||
labs.members = labs('members');
|
||||
|
||||
module.exports = labs;
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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 () {
|
||||
|
|
|
@ -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 () {
|
||||
|
|
|
@ -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 () {
|
||||
|
|
|
@ -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: {}
|
||||
|
|
|
@ -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: '<p>I am here to stay</p>'
|
||||
};
|
||||
|
||||
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: '<p>I am here to stay</p>'
|
||||
};
|
||||
|
||||
it('should NOT hide content attributes when visibility is public', function () {
|
||||
const attrs = {
|
||||
visibility: 'public',
|
||||
plaintext: 'no touching',
|
||||
html: '<p>I am here to stay</p>'
|
||||
};
|
||||
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: '<p>What\'s the matter?</p>'
|
||||
};
|
||||
|
||||
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('<p>What\'s the matter?</p>');
|
||||
});
|
||||
|
||||
it('should hide content attributes when visibility is "members"', function () {
|
||||
const attrs = {
|
||||
visibility: 'members',
|
||||
plaintext: 'no touching. secret stuff',
|
||||
html: '<p>I am here to stay</p>'
|
||||
};
|
||||
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: '<p>What\'s the matter?</p>'
|
||||
};
|
||||
|
||||
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: '<p>What\'s the matter?</p>'
|
||||
};
|
||||
|
||||
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('<p>What\'s the matter?</p>');
|
||||
});
|
||||
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: '<p>What\'s the matter?</p>'
|
||||
};
|
||||
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: '<p>Can read this</p>'
|
||||
};
|
||||
|
||||
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: '<p>Can read this</p>'
|
||||
};
|
||||
|
||||
const frame = {
|
||||
options: {},
|
||||
original: {
|
||||
context: {
|
||||
member: {
|
||||
status: 'paid'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
gating.forPost(attrs, frame);
|
||||
|
||||
attrs.plaintext.should.eql('Secret paid content');
|
||||
attrs.html.should.eql('<p>Can read this</p>');
|
||||
});
|
||||
attrs.plaintext.should.eql('Secret paid content');
|
||||
attrs.html.should.eql('<p>Can read this</p>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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: {}
|
||||
|
|
|
@ -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: '<p>I am here to stay</p>'
|
||||
};
|
||||
|
||||
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: '<p>I am here to stay</p>'
|
||||
};
|
||||
|
||||
it('should NOT hide content attributes when visibility is public', function () {
|
||||
const attrs = {
|
||||
visibility: 'public',
|
||||
plaintext: 'no touching',
|
||||
html: '<p>I am here to stay</p>'
|
||||
};
|
||||
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: '<p>What\'s the matter?</p>'
|
||||
};
|
||||
|
||||
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('<p>What\'s the matter?</p>');
|
||||
});
|
||||
|
||||
it('should hide content attributes when visibility is "members"', function () {
|
||||
const attrs = {
|
||||
visibility: 'members',
|
||||
plaintext: 'no touching. secret stuff',
|
||||
html: '<p>I am here to stay</p>'
|
||||
};
|
||||
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: '<p>What\'s the matter?</p>'
|
||||
};
|
||||
|
||||
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: '<p>What\'s the matter?</p>'
|
||||
};
|
||||
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: '<p>What\'s the matter?</p>'
|
||||
};
|
||||
|
||||
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('<p>What\'s the matter?</p>');
|
||||
});
|
||||
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: '<p>What\'s the matter?</p>'
|
||||
};
|
||||
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: '<p>Can read this</p>'
|
||||
};
|
||||
|
||||
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: '<p>Can read this</p>'
|
||||
};
|
||||
|
||||
const frame = {
|
||||
options: {},
|
||||
original: {
|
||||
context: {
|
||||
member: {
|
||||
status: 'paid'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
gating.forPost(attrs, frame);
|
||||
|
||||
attrs.plaintext.should.eql('Secret paid content');
|
||||
attrs.html.should.eql('<p>Can read this</p>');
|
||||
});
|
||||
attrs.plaintext.should.eql('Secret paid content');
|
||||
attrs.html.should.eql('<p>Can read this</p>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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: {}
|
||||
|
|
Loading…
Add table
Reference in a new issue