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

Added calculated excerpt field to Content API v2 (#10326)

closes #10062

- return `post.excerpt` for Content API v2
- do not use `downsize`, because we might want to get rid of it if we drop v0.1 (downsize does not create good excerpts)
- simple substring of the plaintext field
This commit is contained in:
Katharina Irrgang 2019-01-04 19:00:45 +01:00 committed by GitHub
parent 6448c7bdc8
commit 30a0b1794a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 75 additions and 2 deletions

View file

@ -0,0 +1,13 @@
module.exports.forPost = (frame, model, attrs) => {
const _ = require('lodash');
if (!frame.options.hasOwnProperty('columns') ||
(frame.options.columns.includes('excerpt') && frame.options.formats && frame.options.formats.includes('plaintext'))) {
if (_.isEmpty(attrs.custom_excerpt)) {
const plaintext = model.get('plaintext');
attrs.excerpt = plaintext.substring(0, 500);
} else {
attrs.excerpt = attrs.custom_excerpt;
}
}
};

View file

@ -3,6 +3,7 @@ const url = require('./url');
const date = require('./date');
const members = require('./members');
const clean = require('./clean');
const extraAttrs = require('./extra-attrs');
const mapUser = (model, frame) => {
const jsonModel = model.toJSON ? model.toJSON(frame.options) : model;
@ -36,6 +37,7 @@ const mapPost = (model, frame) => {
if (utils.isContentAPI(frame)) {
date.forPost(jsonModel);
members.forPost(jsonModel, frame);
extraAttrs.forPost(frame, model, jsonModel);
clean.post(jsonModel);
}

View file

@ -83,7 +83,9 @@ function getMetaData(data, root) {
// 1. CASE: custom_excerpt is populated via the UI
// 2. CASE: no custom_excerpt, but meta_description is poplated via the UI
// 3. CASE: fall back to automated excerpt of 50 words if neither custom_excerpt nor meta_description is provided
customExcerpt = data.post.custom_excerpt;
// @NOTE: v2 returns a calculated `post.excerpt`. v0.1 does not
// @TODO: simplify or remove if we drop v0.1
customExcerpt = data.post.excerpt || data.post.custom_excerpt;
metaDescription = data.post.meta_description;
fallbackExcerpt = data.post.html ? getExcerpt(data.post.html, {words: 50}) : '';

View file

@ -10,6 +10,15 @@ var proxy = require('./proxy'),
SafeString = proxy.SafeString,
getMetaDataExcerpt = proxy.metaData.getMetaDataExcerpt;
/**
* @NOTE:
*
* Content API v2 returns a calculated `post.excerpt` field.
* See https://github.com/TryGhost/Ghost/issues/10062.
* We have not touched this helper yet, we will revisit later.
*
* @TODO: remove or change if we drop v0.1
*/
module.exports = function excerpt(options) {
var truncateOptions = (options || {}).hash || {},
excerptText = this.custom_excerpt ? String(this.custom_excerpt) : String(this.html);

View file

@ -23,6 +23,8 @@ const expectedProperties = {
.without('locale')
// These fields aren't useful as they always have known values
.without('page', 'status')
// v2 returns a calculated excerpt field
.concat('excerpt')
,
author: _(schema.users)
.keys()

View file

@ -0,0 +1,38 @@
const should = require('should');
const sinon = require('sinon');
const extraAttrsUtil = require('../../../../../../../../server/api/v2/utils/serializers/output/utils/extra-attrs');
const sandbox = sinon.sandbox.create();
describe('Unit: v2/utils/serializers/output/utils/extra-attrs', () => {
const frame = {
options: {}
};
let model;
beforeEach(function () {
model = sandbox.stub();
model.get = sandbox.stub();
model.get.withArgs('plaintext').returns(new Array(5000).join('A'));
});
describe('for post', function () {
it('respects custom excerpt', () => {
const attrs = {custom_excerpt: 'custom excerpt'};
extraAttrsUtil.forPost(frame, model, attrs);
model.get.called.should.be.false();
attrs.excerpt.should.eql(attrs.custom_excerpt);
});
it('no custom excerpt', () => {
const attrs = {};
extraAttrsUtil.forPost(frame, model, attrs);
model.get.called.should.be.true();
attrs.excerpt.should.eql(new Array(501).join('A'));
});
});
});

View file

@ -4,6 +4,7 @@ const testUtils = require('../../../../../../../utils');
const dateUtil = require('../../../../../../../../server/api/v2/utils/serializers/output/utils/date');
const urlUtil = require('../../../../../../../../server/api/v2/utils/serializers/output/utils/url');
const cleanUtil = require('../../../../../../../../server/api/v2/utils/serializers/output/utils/clean');
const extraAttrsUtils = require('../../../../../../../../server/api/v2/utils/serializers/output/utils/extra-attrs');
const mapper = require('../../../../../../../../server/api/v2/utils/serializers/output/utils/mapper');
const sandbox = sinon.sandbox.create();
@ -16,6 +17,8 @@ describe('Unit: v2/utils/serializers/output/utils/mapper', () => {
sandbox.stub(urlUtil, 'forTag').returns({});
sandbox.stub(urlUtil, 'forUser').returns({});
sandbox.stub(extraAttrsUtils, 'forPost').returns({});
sandbox.stub(cleanUtil, 'post').returns({});
sandbox.stub(cleanUtil, 'tag').returns({});
sandbox.stub(cleanUtil, 'author').returns({});
@ -30,7 +33,9 @@ describe('Unit: v2/utils/serializers/output/utils/mapper', () => {
beforeEach(() => {
postModel = (data) => {
return Object.assign(data, {toJSON: sandbox.stub().returns(data)});
return Object.assign(data, {
toJSON: sandbox.stub().returns(data)
});
};
});
@ -62,6 +67,8 @@ describe('Unit: v2/utils/serializers/output/utils/mapper', () => {
dateUtil.forPost.callCount.should.equal(1);
extraAttrsUtils.forPost.callCount.should.equal(1);
cleanUtil.post.callCount.should.eql(1);
cleanUtil.tag.callCount.should.eql(1);
cleanUtil.author.callCount.should.eql(1);