mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-27 22:49:56 -05:00
Merge pull request #4686 from jaswilli/tag-api-post-count
Finish up post count support in tags API
This commit is contained in:
commit
7cdfd95098
4 changed files with 133 additions and 57 deletions
|
@ -8,8 +8,17 @@ var Promise = require('bluebird'),
|
|||
utils = require('./utils'),
|
||||
|
||||
docName = 'tags',
|
||||
allowedIncludes = ['post_count'],
|
||||
tags;
|
||||
|
||||
// ## Helpers
|
||||
function prepareInclude(include) {
|
||||
include = include || '';
|
||||
include = _.intersection(include.split(','), allowedIncludes);
|
||||
|
||||
return include;
|
||||
}
|
||||
|
||||
/**
|
||||
* ## Tags API Methods
|
||||
*
|
||||
|
@ -22,7 +31,13 @@ tags = {
|
|||
* @returns {Promise(Tags)} Tags Collection
|
||||
*/
|
||||
browse: function browse(options) {
|
||||
options = options || {};
|
||||
|
||||
return canThis(options.context).browse.tag().then(function () {
|
||||
if (options.include) {
|
||||
options.include = prepareInclude(options.include);
|
||||
}
|
||||
|
||||
return dataProvider.Tag.findPage(options);
|
||||
}, function () {
|
||||
return Promise.reject(new errors.NoPermissionError('You do not have permission to browse tags.'));
|
||||
|
@ -35,9 +50,16 @@ tags = {
|
|||
* @return {Promise(Tag)} Tag
|
||||
*/
|
||||
read: function read(options) {
|
||||
options = options || {};
|
||||
|
||||
var attrs = ['id', 'slug'],
|
||||
data = _.pick(options, attrs);
|
||||
data = _.pick(options, attrs);
|
||||
|
||||
return canThis(options.context).read.tag().then(function () {
|
||||
if (options.include) {
|
||||
options.include = prepareInclude(options.include);
|
||||
}
|
||||
|
||||
return dataProvider.Tag.findOne(data, options).then(function (result) {
|
||||
if (result) {
|
||||
return {tags: [result.toJSON()]};
|
||||
|
@ -59,6 +81,10 @@ tags = {
|
|||
options = options || {};
|
||||
|
||||
return canThis(options.context).add.tag(object).then(function () {
|
||||
if (options.include) {
|
||||
options.include = prepareInclude(options.include);
|
||||
}
|
||||
|
||||
return utils.checkObject(object, docName).then(function (checkedTagData) {
|
||||
return dataProvider.Tag.add(checkedTagData.tags[0], options);
|
||||
}).then(function (result) {
|
||||
|
@ -80,7 +106,13 @@ tags = {
|
|||
* @return {Promise(Tag)} Edited Tag
|
||||
*/
|
||||
edit: function edit(object, options) {
|
||||
options = options || {};
|
||||
|
||||
return canThis(options.context).edit.tag(options.id).then(function () {
|
||||
if (options.include) {
|
||||
options.include = prepareInclude(options.include);
|
||||
}
|
||||
|
||||
return utils.checkObject(object, docName).then(function (checkedTagData) {
|
||||
return dataProvider.Tag.edit(checkedTagData.tags[0], options);
|
||||
}).then(function (result) {
|
||||
|
@ -105,6 +137,8 @@ tags = {
|
|||
* @return {Promise(Tag)} Deleted Tag
|
||||
*/
|
||||
destroy: function destroy(options) {
|
||||
options = options || {};
|
||||
|
||||
return canThis(options.context).destroy.tag(options.id).then(function () {
|
||||
return tags.read(options).then(function (result) {
|
||||
return dataProvider.Tag.destroy(options).then(function () {
|
||||
|
|
|
@ -7,6 +7,17 @@ var _ = require('lodash'),
|
|||
Tag,
|
||||
Tags;
|
||||
|
||||
function addPostCount(options, obj) {
|
||||
if (options.include && options.include.indexOf('post_count') > -1) {
|
||||
obj.query('select', 'tags.*');
|
||||
obj.query('count', 'posts_tags.id as post_count');
|
||||
obj.query('leftJoin', 'posts_tags', 'tag_id', 'tags.id');
|
||||
obj.query('groupBy', 'tag_id', 'tags.id');
|
||||
|
||||
options.include = _.pull([].concat(options.include), 'post_count');
|
||||
}
|
||||
}
|
||||
|
||||
Tag = ghostBookshelf.Model.extend({
|
||||
|
||||
tableName: 'tags',
|
||||
|
@ -70,13 +81,32 @@ Tag = ghostBookshelf.Model.extend({
|
|||
|
||||
return options;
|
||||
},
|
||||
|
||||
/**
|
||||
* ### Find One
|
||||
* @overrides ghostBookshelf.Model.findOne
|
||||
*/
|
||||
findOne: function (data, options) {
|
||||
options = options || {};
|
||||
|
||||
options = this.filterOptions(options, 'findOne');
|
||||
data = this.filterData(data, 'findOne');
|
||||
|
||||
var tag = this.forge(data);
|
||||
|
||||
addPostCount(options, tag);
|
||||
|
||||
// Add related objects
|
||||
options.withRelated = _.union(options.withRelated, options.include);
|
||||
|
||||
return tag.fetch(options);
|
||||
},
|
||||
|
||||
findPage: function (options) {
|
||||
options = options || {};
|
||||
|
||||
var tagCollection = Tags.forge(),
|
||||
collectionPromise,
|
||||
totalPromise,
|
||||
countPromise,
|
||||
qb;
|
||||
|
||||
if (options.limit && options.limit !== 'all') {
|
||||
|
@ -102,6 +132,8 @@ Tag = ghostBookshelf.Model.extend({
|
|||
.query('offset', options.limit * (options.page - 1));
|
||||
}
|
||||
|
||||
addPostCount(options, tagCollection);
|
||||
|
||||
collectionPromise = tagCollection.fetch(_.omit(options, 'page', 'limit'));
|
||||
|
||||
// Find total number of tags
|
||||
|
@ -112,22 +144,10 @@ Tag = ghostBookshelf.Model.extend({
|
|||
qb.where(options.where);
|
||||
}
|
||||
|
||||
totalPromise = qb.count('tags.id as aggregate');
|
||||
|
||||
// Fetch post count information
|
||||
|
||||
if (options.include) {
|
||||
if (options.include.indexOf('post_count') > -1) {
|
||||
qb = ghostBookshelf.knex('posts_tags');
|
||||
countPromise = qb.select('tag_id').count('* as postCount').groupBy('tag_id');
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.join(collectionPromise, totalPromise, countPromise).then(function (results) {
|
||||
return Promise.join(collectionPromise, qb.count('tags.id as aggregate')).then(function (results) {
|
||||
var totalTags = results[1][0].aggregate,
|
||||
calcPages = Math.ceil(totalTags / options.limit) || 0,
|
||||
tagCollection = results[0],
|
||||
postsPerTagCollection = results[2],
|
||||
pagination = {},
|
||||
meta = {},
|
||||
data = {};
|
||||
|
@ -140,19 +160,6 @@ Tag = ghostBookshelf.Model.extend({
|
|||
pagination.prev = null;
|
||||
|
||||
data.tags = tagCollection.toJSON();
|
||||
|
||||
if (postsPerTagCollection) {
|
||||
// Merge two result sets
|
||||
_.each(data.tags, function (tag) {
|
||||
var postsPerTag = _.find(postsPerTagCollection, function (obj) { return obj.tag_id === tag.id; });
|
||||
if (postsPerTag) {
|
||||
tag.post_count = postsPerTag.postCount;
|
||||
} else {
|
||||
tag.post_count = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
data.meta = meta;
|
||||
meta.pagination = pagination;
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ describe('Tags API', function () {
|
|||
// Keep the DB clean
|
||||
before(testUtils.teardown);
|
||||
afterEach(testUtils.teardown);
|
||||
beforeEach(testUtils.setup('users:roles', 'tag', 'perms:tag', 'perms:init'));
|
||||
beforeEach(testUtils.setup('users:roles', 'perms:tag', 'perms:init', 'posts'));
|
||||
|
||||
should.exist(TagAPI);
|
||||
|
||||
|
@ -161,5 +161,34 @@ describe('Tags API', function () {
|
|||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('with include post_count', function (done) {
|
||||
TagAPI.browse({context: {user: 1}, include: 'post_count'}).then(function (results) {
|
||||
should.exist(results);
|
||||
should.exist(results.tags);
|
||||
results.tags.length.should.be.above(0);
|
||||
|
||||
testUtils.API.checkResponse(results.tags[0], 'tag', 'post_count');
|
||||
should.exist(results.tags[0].post_count);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Read', function () {
|
||||
it('returns post_count with include post_count', function (done) {
|
||||
TagAPI.read({context: {user: 1}, include: 'post_count', slug: 'kitchen-sink'}).then(function (results) {
|
||||
should.exist(results);
|
||||
should.exist(results.tags);
|
||||
results.tags.length.should.be.above(0);
|
||||
|
||||
testUtils.API.checkResponse(results.tags[0], 'tag', 'post_count');
|
||||
should.exist(results.tags[0].post_count);
|
||||
results.tags[0].post_count.should.equal(2);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -37,40 +37,46 @@ describe('Tag Model', function () {
|
|||
}).catch(done);
|
||||
});
|
||||
|
||||
it('can findPage with limit all', function (done) {
|
||||
it('returns post_count if include post_count', function (done) {
|
||||
testUtils.fixtures.insertPosts().then(function () {
|
||||
return TagModel.findPage({limit: 'all'});
|
||||
}).then(function (results) {
|
||||
results.meta.pagination.page.should.equal(1);
|
||||
results.meta.pagination.limit.should.equal('all');
|
||||
results.meta.pagination.pages.should.equal(1);
|
||||
results.tags.length.should.equal(5);
|
||||
TagModel.findOne({slug: 'kitchen-sink'}, {include: 'post_count'}).then(function (tag) {
|
||||
should.exist(tag);
|
||||
tag.get('post_count').should.equal(2);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('can findPage with post_count include', function (done) {
|
||||
testUtils.fixtures.insertPosts().then(function () {
|
||||
return TagModel.findPage({include: 'post_count'});
|
||||
}).then(function (results) {
|
||||
_.each(results.tags, function (tag) { tag.should.have.property('post_count'); });
|
||||
_.findWhere(results.tags, {slug: 'kitchen-sink'}).post_count.should.equal(2);
|
||||
_.findWhere(results.tags, {slug: 'pollo'}).post_count.should.equal(1);
|
||||
_.findWhere(results.tags, {slug: 'injection'}).post_count.should.equal(0);
|
||||
describe('findPage', function () {
|
||||
beforeEach(function (done) {
|
||||
testUtils.fixtures.insertPosts().then(function () {
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
it('with limit all', function (done) {
|
||||
TagModel.findPage({limit: 'all'}).then(function (results) {
|
||||
results.meta.pagination.page.should.equal(1);
|
||||
results.meta.pagination.limit.should.equal('all');
|
||||
results.meta.pagination.pages.should.equal(1);
|
||||
results.tags.length.should.equal(5);
|
||||
|
||||
it('can findPage with post_count include and limit less then total_tags', function (done) {
|
||||
testUtils.fixtures.insertPosts().then(function () {
|
||||
return TagModel.findPage({include: 'post_count', limit: 2});
|
||||
}).then(function (results) {
|
||||
_.each(results.tags, function (tag) { tag.should.have.property('post_count'); });
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
it('with include post_count', function (done) {
|
||||
TagModel.findPage({limit: 'all', include: 'post_count'}).then(function (results) {
|
||||
results.meta.pagination.page.should.equal(1);
|
||||
results.meta.pagination.limit.should.equal('all');
|
||||
results.meta.pagination.pages.should.equal(1);
|
||||
results.tags.length.should.equal(5);
|
||||
should.exist(results.tags[0].post_count);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('a Post', function () {
|
||||
|
|
Loading…
Add table
Reference in a new issue