mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-11 02:12:21 -05:00
Added newsletters endpoint to Content API (#14778)
refs https://github.com/TryGhost/Team/issues/1599 - allows active newsletters data to be fetched via content API
This commit is contained in:
parent
837e11b4d8
commit
9f85f7a4fe
9 changed files with 265 additions and 0 deletions
|
@ -215,5 +215,9 @@ module.exports = {
|
|||
|
||||
get tiersPublic() {
|
||||
return shared.pipeline(require('./tiers-public'), localUtils, 'content');
|
||||
},
|
||||
|
||||
get newslettersPublic() {
|
||||
return shared.pipeline(require('./newsletters-public'), localUtils, 'content');
|
||||
}
|
||||
};
|
||||
|
|
19
core/server/api/canary/newsletters-public.js
Normal file
19
core/server/api/canary/newsletters-public.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
const models = require('../../models');
|
||||
|
||||
module.exports = {
|
||||
docName: 'newsletters',
|
||||
|
||||
browse: {
|
||||
options: [
|
||||
'filter',
|
||||
'fields',
|
||||
'limit',
|
||||
'order',
|
||||
'page'
|
||||
],
|
||||
permissions: true,
|
||||
query(frame) {
|
||||
return models.Newsletter.findPage(frame.options);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -9,5 +9,6 @@ module.exports = {
|
|||
settings: require('./settings'),
|
||||
snippets: require('./snippets'),
|
||||
tags: require('./tags'),
|
||||
newsletters: require('./newsletters'),
|
||||
users: require('./users')
|
||||
};
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
const utils = require('../../../index');
|
||||
|
||||
module.exports = (model, frame) => {
|
||||
const jsonModel = model.toJSON(frame.options);
|
||||
|
||||
if (utils.isContentAPI(frame)) {
|
||||
const serialized = {
|
||||
id: jsonModel.id,
|
||||
uuid: jsonModel.uuid,
|
||||
name: jsonModel.name,
|
||||
description: jsonModel.description,
|
||||
slug: jsonModel.slug,
|
||||
visibility: jsonModel.visibility,
|
||||
sort_order: jsonModel.sort_order,
|
||||
created_at: jsonModel.created_at,
|
||||
updated_at: jsonModel.updated_at
|
||||
};
|
||||
|
||||
return serialized;
|
||||
}
|
||||
|
||||
return jsonModel;
|
||||
};
|
|
@ -38,6 +38,11 @@ const Newsletter = ghostBookshelf.Model.extend({
|
|||
return this.hasMany('Post');
|
||||
},
|
||||
|
||||
// Force active newsletters for content API
|
||||
enforcedFilters: function enforcedFilters(options) {
|
||||
return options.context && options.context.public ? 'status:active' : null;
|
||||
},
|
||||
|
||||
async onSaving(model, _attr, options) {
|
||||
ghostBookshelf.Model.prototype.onSaving.apply(this, arguments);
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ module.exports = function apiRoutes() {
|
|||
|
||||
router.get('/products', mw.authenticatePublic, http(api.productsPublic.browse));
|
||||
router.get('/tiers', mw.authenticatePublic, http(api.tiersPublic.browse));
|
||||
router.get('/newsletters', mw.authenticatePublic, http(api.newslettersPublic.browse));
|
||||
|
||||
return router;
|
||||
};
|
||||
|
|
125
test/e2e-api/content/__snapshots__/newsletters.test.js.snap
Normal file
125
test/e2e-api/content/__snapshots__/newsletters.test.js.snap
Normal file
|
@ -0,0 +1,125 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Newsletters Content API Can request only active newsletters 1: [body] 1`] = `
|
||||
Object {
|
||||
"meta": Object {
|
||||
"pagination": Object {
|
||||
"limit": 15,
|
||||
"next": null,
|
||||
"page": 1,
|
||||
"pages": 1,
|
||||
"prev": null,
|
||||
"total": 3,
|
||||
},
|
||||
},
|
||||
"newsletters": Array [
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"name": "Default Newsletter",
|
||||
"slug": "default-newsletter",
|
||||
"sort_order": 0,
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "members",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"name": "Daily newsletter",
|
||||
"slug": "daily-newsletter",
|
||||
"sort_order": 1,
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "members",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"name": "Weekly newsletter",
|
||||
"slug": "weekly-newsletter",
|
||||
"sort_order": 2,
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "members",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Newsletters Content API Can request only active newsletters 2: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "*",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "918",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Newsletters Content API Cannot override filters to fetch archived newsletters 1: [body] 1`] = `
|
||||
Object {
|
||||
"meta": Object {
|
||||
"pagination": Object {
|
||||
"limit": 15,
|
||||
"next": null,
|
||||
"page": 1,
|
||||
"pages": 1,
|
||||
"prev": null,
|
||||
"total": 3,
|
||||
},
|
||||
},
|
||||
"newsletters": Array [
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"name": "Default Newsletter",
|
||||
"slug": "default-newsletter",
|
||||
"sort_order": 0,
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "members",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"name": "Daily newsletter",
|
||||
"slug": "daily-newsletter",
|
||||
"sort_order": 1,
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "members",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"name": "Weekly newsletter",
|
||||
"slug": "weekly-newsletter",
|
||||
"sort_order": 2,
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "members",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Newsletters Content API Cannot override filters to fetch archived newsletters 2: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "*",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "918",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
40
test/e2e-api/content/newsletters.test.js
Normal file
40
test/e2e-api/content/newsletters.test.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
const {agentProvider, fixtureManager, matchers} = require('../../utils/e2e-framework');
|
||||
|
||||
const newsletterSnapshot = {
|
||||
id: matchers.anyObjectId,
|
||||
uuid: matchers.anyUuid,
|
||||
created_at: matchers.anyISODateTime,
|
||||
updated_at: matchers.anyISODateTime
|
||||
};
|
||||
|
||||
describe('Newsletters Content API', function () {
|
||||
let agent;
|
||||
|
||||
before(async function () {
|
||||
agent = await agentProvider.getContentAPIAgent();
|
||||
await fixtureManager.init('api_keys', 'newsletters');
|
||||
agent.authenticate();
|
||||
});
|
||||
|
||||
it('Can request only active newsletters', async function () {
|
||||
await agent.get('/newsletters/')
|
||||
.expectStatus(200)
|
||||
.matchHeaderSnapshot({
|
||||
etag: matchers.anyEtag
|
||||
})
|
||||
.matchBodySnapshot({
|
||||
newsletters: Array(3).fill(newsletterSnapshot)
|
||||
});
|
||||
});
|
||||
|
||||
it('Cannot override filters to fetch archived newsletters', async function () {
|
||||
await agent.get('/newsletters/?filter=status:archived')
|
||||
.expectStatus(200)
|
||||
.matchHeaderSnapshot({
|
||||
etag: matchers.anyEtag
|
||||
})
|
||||
.matchBodySnapshot({
|
||||
newsletters: Array(3).fill(newsletterSnapshot)
|
||||
});
|
||||
});
|
||||
});
|
|
@ -211,4 +211,51 @@ describe('Unit: utils/serializers/output/mappers', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Newsletter Mapper', function () {
|
||||
let newsletterModel;
|
||||
|
||||
beforeEach(function () {
|
||||
newsletterModel = (data) => {
|
||||
return Object.assign(data, {toJSON: sinon.stub().returns(data)});
|
||||
};
|
||||
});
|
||||
|
||||
it('returns only allowed keys for content API', function () {
|
||||
const frame = {
|
||||
apiType: 'content'
|
||||
};
|
||||
|
||||
const newsletter = newsletterModel(testUtils.DataGenerator.forKnex.createNewsletter({
|
||||
name: 'Basic newsletter',
|
||||
slug: 'basic-newsletter'
|
||||
}));
|
||||
|
||||
const mapped = mappers.newsletters(newsletter, frame);
|
||||
|
||||
mapped.should.eql({
|
||||
id: newsletter.id,
|
||||
uuid: newsletter.uuid,
|
||||
name: newsletter.name,
|
||||
description: newsletter.description,
|
||||
slug: newsletter.slug,
|
||||
visibility: newsletter.visibility,
|
||||
sort_order: newsletter.sort_order,
|
||||
created_at: newsletter.created_at,
|
||||
updated_at: newsletter.updated_at
|
||||
});
|
||||
});
|
||||
|
||||
it('returns all keys for admin API', function () {
|
||||
const frame = {};
|
||||
|
||||
const newsletter = newsletterModel(testUtils.DataGenerator.forKnex.createNewsletter({
|
||||
name: 'Full newsletter',
|
||||
slug: 'full-newsletter'
|
||||
}));
|
||||
|
||||
const mapped = mappers.newsletters(newsletter, frame);
|
||||
mapped.should.eql(newsletter.toJSON());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue