0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-13 22:41:32 -05:00

Merge pull request #2596 from sebgie/issue#2580-move-obj

Move post API to primary document format
This commit is contained in:
Hannah Wolfe 2014-04-16 11:36:56 +01:00
commit b89727a573
11 changed files with 191 additions and 164 deletions

View file

@ -1,4 +1,4 @@
/*global Ghost, _, Backbone */
/*global Ghost, _, Backbone, JSON */
(function () {
'use strict';
@ -11,6 +11,10 @@
blacklist: ['published', 'draft'],
parse: function (resp) {
if (resp.posts) {
resp = resp.posts[0];
}
if (resp.status) {
resp.published = resp.status === 'published';
resp.draft = resp.status === 'draft';
@ -39,6 +43,15 @@
return tag.id === tagToRemove.id || tag.name === tagToRemove.name;
});
this.set('tags', tags);
},
sync: function (method, model, options) {
//wrap post in {posts: [{...}]}
if (method === 'create' || method === 'update') {
options.data = JSON.stringify({posts: [this.attributes]});
options.contentType = 'application/json';
}
return Backbone.Model.prototype.sync.apply(this, arguments);
}
});

View file

@ -29,8 +29,8 @@ function cacheInvalidationHeader(req, result) {
cacheInvalidate = '/*';
} else if (endpoint === 'posts') {
cacheInvalidate = '/, /page/*, /rss/, /rss/*, /tag/*';
if (id && jsonResult.slug) {
return config.urlForPost(settings, jsonResult).then(function (postUrl) {
if (id && jsonResult.posts[0].slug) {
return config.urlForPost(settings, jsonResult.posts[0]).then(function (postUrl) {
return cacheInvalidate + ', ' + postUrl;
});
}

View file

@ -5,10 +5,17 @@ var when = require('when'),
filteredUserAttributes = require('./users').filteredAttributes,
posts;
function checkPostData(postData) {
if (_.isEmpty(postData) || _.isEmpty(postData.posts) || _.isEmpty(postData.posts[0])) {
return when.reject({code: 400, message: 'No root key (\'posts\') provided.'});
}
return when.resolve(postData);
}
// ## Posts
posts = {
// #### Browse
// #### Browse
// **takes:** filter / pagination parameters
browse: function browse(options) {
options = options || {};
@ -21,14 +28,12 @@ posts = {
for (i = 0; i < omitted.posts.length; i = i + 1) {
omitted.posts[i].author = _.omit(omitted.posts[i].author, filteredUserAttributes);
omitted.posts[i].user = _.omit(omitted.posts[i].user, filteredUserAttributes);
}
return omitted;
});
},
// #### Read
// **takes:** an identifier (id or slug?)
read: function read(args) {
// **returns:** a promise for a single post in a json object
@ -39,8 +44,7 @@ posts = {
if (result) {
omitted = result.toJSON();
omitted.author = _.omit(omitted.author, filteredUserAttributes);
omitted.user = _.omit(omitted.user, filteredUserAttributes);
return omitted;
return { posts: [ omitted ]};
}
return when.reject({code: 404, message: 'Post not found'});
@ -57,7 +61,6 @@ posts = {
},
// #### Edit
// **takes:** a json object with all the properties which should be updated
edit: function edit(postData) {
// **returns:** a promise for the resulting post in a json object
@ -66,21 +69,15 @@ posts = {
}
var self = this;
return canThis(self.user).edit.post(postData.id).then(function () {
return dataProvider.Post.edit(postData).then(function (result) {
return checkPostData(postData).then(function (checkedPostData) {
return dataProvider.Post.edit(checkedPostData.posts[0]);
}).then(function (result) {
if (result) {
var omitted = result.toJSON();
omitted.author = _.omit(omitted.author, filteredUserAttributes);
omitted.user = _.omit(omitted.user, filteredUserAttributes);
return omitted;
return { posts: [ omitted ]};
}
return when.reject({code: 404, message: 'Post not found'});
}).otherwise(function (error) {
return dataProvider.Post.findOne({id: postData.id, status: 'all'}).then(function (result) {
if (!result) {
return when.reject({code: 404, message: 'Post not found'});
}
return when.reject({message: error.message});
});
});
}, function () {
return when.reject({code: 403, message: 'You do not have permission to edit this post.'});
@ -88,7 +85,6 @@ posts = {
},
// #### Add
// **takes:** a json object representing a post,
add: function add(postData) {
// **returns:** a promise for the resulting post in a json object
@ -97,14 +93,19 @@ posts = {
}
return canThis(this.user).create.post().then(function () {
return dataProvider.Post.add(postData);
return checkPostData(postData).then(function (checkedPostData) {
return dataProvider.Post.add(checkedPostData.posts[0]);
}).then(function (result) {
var omitted = result.toJSON();
omitted.author = _.omit(omitted.author, filteredUserAttributes);
return { posts: [ omitted ]};
});
}, function () {
return when.reject({code: 403, message: 'You do not have permission to add posts.'});
});
},
// #### Destroy
// **takes:** an identifier (id or slug?)
destroy: function destroy(args) {
// **returns:** a promise for a json response with the id of the deleted post
@ -113,7 +114,7 @@ posts = {
}
return canThis(this.user).remove.post(args.id).then(function () {
return when(posts.read({id : args.id, status: 'all'})).then(function (result) {
return posts.read({id : args.id, status: 'all'}).then(function (result) {
return dataProvider.Post.destroy(args.id).then(function () {
var deletedObj = result;
return deletedObj;

View file

@ -172,7 +172,10 @@ frontendControllers = {
// Query database to find post
return api.posts.read(postLookup);
}).then(function (post) {
}).then(function (result) {
var post = result.posts[0],
slugDate = [],
slugFormat = [];
if (!post) {
return next();
@ -208,9 +211,6 @@ frontendControllers = {
// we will check it against the post published date
// to verify it's correct.
if (params.year || params.month || params.day) {
var slugDate = [],
slugFormat = [];
if (params.year) {
slugDate.push(params.year);
slugFormat.push('YYYY');

View file

@ -149,7 +149,9 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
edit: function (editedObj, options) {
options = options || {};
return this.forge({id: editedObj.id}).fetch(options).then(function (foundObj) {
return foundObj.save(editedObj, options);
if (foundObj) {
return foundObj.save(editedObj, options);
}
});
},

View file

@ -192,10 +192,6 @@ Post = ghostBookshelf.Model.extend({
},
// Relations
user: function () {
return this.belongsTo(User, 'created_by');
},
author: function () {
return this.belongsTo(User, 'author_id');
},
@ -210,7 +206,7 @@ Post = ghostBookshelf.Model.extend({
// Extends base model findAll to eager-fetch author and user relationships.
findAll: function (options) {
options = options || {};
options.withRelated = [ 'author', 'user', 'tags' ];
options.withRelated = [ 'author', 'tags' ];
return ghostBookshelf.Model.findAll.call(this, options);
},
@ -227,7 +223,7 @@ Post = ghostBookshelf.Model.extend({
delete args.status;
}
options.withRelated = [ 'author', 'user', 'tags' ];
options.withRelated = [ 'author', 'tags' ];
return ghostBookshelf.Model.findOne.call(this, args, options);
},
@ -293,7 +289,7 @@ Post = ghostBookshelf.Model.extend({
}
// Fetch related models
opts.withRelated = [ 'author', 'user', 'tags' ];
opts.withRelated = [ 'author', 'tags' ];
// If a query param for a tag is attached
// we need to fetch the tag model to find its id
@ -439,7 +435,9 @@ Post = ghostBookshelf.Model.extend({
var self = this;
return ghostBookshelf.Model.edit.call(this, editedPost, options).then(function (post) {
return self.findOne({status: 'all', id: post.id}, options);
if (post) {
return self.findOne({status: 'all', id: post.id}, options);
}
});
},
destroy: function (_identifier, options) {

View file

@ -198,8 +198,9 @@ describe('Post API', function () {
res.should.be.json;
var jsonResponse = res.body;
jsonResponse.should.exist;
testUtils.API.checkResponse(jsonResponse, 'post');
jsonResponse.page.should.eql(0);
jsonResponse.posts.should.exist;
testUtils.API.checkResponse(jsonResponse.posts[0], 'post');
jsonResponse.posts[0].page.should.eql(0);
done();
});
});
@ -216,8 +217,9 @@ describe('Post API', function () {
res.should.be.json;
var jsonResponse = res.body;
jsonResponse.should.exist;
testUtils.API.checkResponse(jsonResponse, 'post');
jsonResponse.page.should.eql(1);
jsonResponse.posts.should.exist;
testUtils.API.checkResponse(jsonResponse.posts[0], 'post');
jsonResponse.posts[0].page.should.eql(1);
done();
});
});
@ -281,7 +283,7 @@ describe('Post API', function () {
var newTitle = 'My Post',
changedTitle = 'My Post changed',
publishedState = 'published',
newPost = {status: 'draft', title: newTitle, markdown: 'my post'};
newPost = {posts: [{status: 'draft', title: newTitle, markdown: 'my post'}]};
request.post(testUtils.API.getApiQuery('posts/'))
.set('X-CSRF-Token', csrfToken)
@ -294,12 +296,12 @@ describe('Post API', function () {
res.should.be.json;
var draftPost = res.body;
draftPost.should.exist;
draftPost.title.should.eql(newTitle);
draftPost.status = publishedState;
testUtils.API.checkResponse(draftPost, 'post');
draftPost.posts.should.exist;
draftPost.posts[0].title.should.eql(newTitle);
draftPost.posts[0].status = publishedState;
testUtils.API.checkResponse(draftPost.posts[0], 'post');
request.put(testUtils.API.getApiQuery('posts/' + draftPost.id + '/'))
request.put(testUtils.API.getApiQuery('posts/' + draftPost.posts[0].id + '/'))
.set('X-CSRF-Token', csrfToken)
.send(draftPost)
.expect(200)
@ -309,15 +311,15 @@ describe('Post API', function () {
}
var publishedPost = res.body;
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + publishedPost.slug + '/');
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + publishedPost.posts[0].slug + '/');
res.should.be.json;
publishedPost.should.exist;
publishedPost.title.should.eql(newTitle);
publishedPost.status.should.eql(publishedState);
testUtils.API.checkResponse(publishedPost, 'post');
publishedPost.posts.should.exist;
publishedPost.posts[0].title.should.eql(newTitle);
publishedPost.posts[0].status.should.eql(publishedState);
testUtils.API.checkResponse(publishedPost.posts[0], 'post');
request.put(testUtils.API.getApiQuery('posts/' + publishedPost.id + '/'))
request.put(testUtils.API.getApiQuery('posts/' + publishedPost.posts[0].id + '/'))
.set('X-CSRF-Token', csrfToken)
.send(publishedPost)
.expect(200)
@ -327,11 +329,12 @@ describe('Post API', function () {
}
var updatedPost = res.body;
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + updatedPost.slug + '/');
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + updatedPost.posts[0].slug + '/');
res.should.be.json;
updatedPost.should.exist;
updatedPost.title.should.eql(newTitle);
testUtils.API.checkResponse(updatedPost, 'post');
updatedPost.posts.should.exist;
updatedPost.posts[0].title.should.eql(newTitle);
testUtils.API.checkResponse(updatedPost.posts[0], 'post');
done();
});
});
@ -352,8 +355,8 @@ describe('Post API', function () {
var jsonResponse = res.body,
changedValue = 'My new Title';
jsonResponse.should.exist;
jsonResponse.title = changedValue;
jsonResponse.posts[0].should.exist;
jsonResponse.posts[0].title = changedValue;
request.put(testUtils.API.getApiQuery('posts/1/'))
.set('X-CSRF-Token', csrfToken)
@ -365,12 +368,12 @@ describe('Post API', function () {
}
var putBody = res.body;
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.slug + '/');
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.posts[0].slug + '/');
res.should.be.json;
putBody.should.exist;
putBody.title.should.eql(changedValue);
putBody.posts[0].title.should.eql(changedValue);
testUtils.API.checkResponse(putBody, 'post');
testUtils.API.checkResponse(putBody.posts[0], 'post');
done();
});
});
@ -386,8 +389,8 @@ describe('Post API', function () {
var jsonResponse = res.body,
changedValue = true;
jsonResponse.should.exist;
jsonResponse.page.should.eql(0);
jsonResponse.page = changedValue;
jsonResponse.posts[0].page.should.eql(0);
jsonResponse.posts[0].page = changedValue;
request.put(testUtils.API.getApiQuery('posts/1/'))
.set('X-CSRF-Token', csrfToken)
@ -399,12 +402,12 @@ describe('Post API', function () {
}
var putBody = res.body;
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.slug + '/');
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.posts[0].slug + '/');
res.should.be.json;
putBody.should.exist;
putBody.page.should.eql(changedValue);
putBody.posts[0].page.should.eql(changedValue);
testUtils.API.checkResponse(putBody, 'post');
testUtils.API.checkResponse(putBody.posts[0], 'post');
done();
});
});
@ -421,8 +424,8 @@ describe('Post API', function () {
var jsonResponse = res.body,
changedValue = false;
jsonResponse.should.exist;
jsonResponse.page.should.eql(1);
jsonResponse.page = changedValue;
jsonResponse.posts[0].page.should.eql(1);
jsonResponse.posts[0].page = changedValue;
request.put(testUtils.API.getApiQuery('posts/1/'))
.set('X-CSRF-Token', csrfToken)
@ -434,12 +437,12 @@ describe('Post API', function () {
}
var putBody = res.body;
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.slug + '/');
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.posts[0].slug + '/');
res.should.be.json;
putBody.should.exist;
putBody.page.should.eql(changedValue);
putBody.posts[0].page.should.eql(changedValue);
testUtils.API.checkResponse(putBody, 'post');
testUtils.API.checkResponse(putBody.posts[0], 'post');
done();
});
});
@ -490,15 +493,16 @@ describe('Post API', function () {
}
var putBody = res.body;
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.slug + '/');
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.posts[0].slug + '/');
res.should.be.json;
putBody.should.exist;
putBody.title.should.eql(changedValue);
if (_.isEmpty(putBody.published_at)) {
putBody.posts.should.exist;
putBody.posts[0].title.should.eql(changedValue);
if (_.isEmpty(putBody.posts[0].published_at)) {
should.fail('null', 'valid date', 'publish_at should not be empty');
done();
}
testUtils.API.checkResponse(putBody, 'post');
testUtils.API.checkResponse(putBody.posts[0], 'post');
done();
});
});
@ -517,9 +521,9 @@ describe('Post API', function () {
var jsonResponse = res.body,
changedValue = 'My new Title';
jsonResponse.title.exist;
jsonResponse.testvalue = changedValue;
jsonResponse.id = 99;
jsonResponse.posts[0].title.exist;
jsonResponse.posts[0].testvalue = changedValue;
jsonResponse.posts[0].id = 99;
request.put(testUtils.API.getApiQuery('posts/99/'))
.set('X-CSRF-Token', csrfToken)
.send(jsonResponse)
@ -551,9 +555,10 @@ describe('Post API', function () {
res.should.be.json;
var jsonResponse = res.body;
jsonResponse.should.exist;
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + jsonResponse.slug + '/');
testUtils.API.checkResponse(jsonResponse, 'post');
jsonResponse.id.should.eql(deletePostId);
jsonResponse.posts.should.exist;
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + jsonResponse.posts[0].slug + '/');
testUtils.API.checkResponse(jsonResponse.posts[0], 'post');
jsonResponse.posts[0].id.should.eql(deletePostId);
done();
});
});
@ -579,13 +584,15 @@ describe('Post API', function () {
it('can delete a new draft', function (done) {
var newTitle = 'My Post',
publishedState = 'draft',
newPost = {status: publishedState, title: newTitle, markdown: 'my post'};
newPost = {posts: [{status: publishedState, title: newTitle, markdown: 'my post'}]};
request.post(testUtils.API.getApiQuery('posts/'))
.set('X-CSRF-Token', csrfToken)
.send(newPost)
.expect(200)
.end(function (err ,res) {
console.log("end");
console.log(err);
if (err) {
return done(err);
}
@ -594,11 +601,11 @@ describe('Post API', function () {
res.should.be.json;
draftPost.should.exist;
draftPost.title.should.eql(newTitle);
draftPost.status = publishedState;
testUtils.API.checkResponse(draftPost, 'post');
draftPost.posts[0].title.should.eql(newTitle);
draftPost.posts[0].status = publishedState;
testUtils.API.checkResponse(draftPost.posts[0], 'post');
request.del(testUtils.API.getApiQuery('posts/' + draftPost.id + '/'))
request.del(testUtils.API.getApiQuery('posts/' + draftPost.posts[0].id + '/'))
.set('X-CSRF-Token', csrfToken)
.expect(200)
.end(function (err, res) {
@ -609,7 +616,8 @@ describe('Post API', function () {
res.should.be.json;
var jsonResponse = res.body
jsonResponse.should.exist;
testUtils.API.checkResponse(jsonResponse, 'post');
jsonResponse.posts.should.exist;
testUtils.API.checkResponse(jsonResponse.posts[0], 'post');
done();
});
});
@ -677,9 +685,10 @@ describe('Post API', function () {
var jsonResponse = res.body;
jsonResponse.should.exist;
testUtils.API.checkResponse(jsonResponse, 'post');
jsonResponse.slug.should.not.match(/^\/[0-9]{4}\/[0-9]{2}\/[0-9]{2}/);
jsonResponse.page.should.eql(0);
jsonResponse.posts.should.exist;
testUtils.API.checkResponse(jsonResponse.posts[0], 'post');
jsonResponse.posts[0].slug.should.not.match(/^\/[0-9]{4}\/[0-9]{2}\/[0-9]{2}/);
jsonResponse.posts[0].page.should.eql(0);
done();
});
});
@ -694,7 +703,8 @@ describe('Post API', function () {
var jsonResponse = res.body,
changedValue = 'My new Title';
jsonResponse.should.exist;
jsonResponse.title = changedValue;
jsonResponse.posts.should.exist;
jsonResponse.posts[0].title = changedValue;
request.put(testUtils.API.getApiQuery('posts/2/'))
.set('X-CSRF-Token', csrfToken)
@ -709,14 +719,14 @@ describe('Post API', function () {
dd = ("0" + today.getDate()).slice(-2),
mm = ("0" + (today.getMonth() + 1)).slice(-2),
yyyy = today.getFullYear(),
postLink = '/' + yyyy + '/' + mm + '/' + dd + '/' + putBody.slug + '/';
postLink = '/' + yyyy + '/' + mm + '/' + dd + '/' + putBody.posts[0].slug + '/';
res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, ' + postLink);
res.should.be.json;
putBody.should.exist;
putBody.title.should.eql(changedValue);
putBody.posts[0].title.should.eql(changedValue);
testUtils.API.checkResponse(putBody, 'post');
testUtils.API.checkResponse(putBody.posts[0], 'post');
done();
});
});

View file

@ -52,7 +52,7 @@ describe('Post API', function () {
return PostAPI.read({slug: firstPost.slug});
}).then(function (found) {
should.exist(found);
testUtils.API.checkResponse(found, 'post');
testUtils.API.checkResponse(found.posts[0], 'post');
done();
}).then(null, done);
});

View file

@ -75,9 +75,7 @@ describe('Post Model', function () {
firstPost = results.models[0].toJSON();
firstPost.author.should.be.an.Object;
firstPost.user.should.be.an.Object;
firstPost.author.name.should.equal(DataGenerator.Content.users[0].name);
firstPost.user.name.should.equal(DataGenerator.Content.users[0].name);
done();
}, done);
@ -91,9 +89,7 @@ describe('Post Model', function () {
firstPost = result.toJSON();
firstPost.author.should.be.an.Object;
firstPost.user.should.be.an.Object;
firstPost.author.name.should.equal(testUtils.DataGenerator.Content.users[0].name);
firstPost.user.name.should.equal(testUtils.DataGenerator.Content.users[0].name);
done();
}, done);

View file

@ -360,29 +360,35 @@ describe('Frontend Controller', function () {
describe('single', function () {
var mockPosts = [{
'status': 'published',
'id': 1,
'title': 'Test static page',
'slug': 'test-static-page',
'markdown': 'Test static page content',
'page': 1,
'published_at': new Date('2013/12/30').getTime()
'posts': [{
'status': 'published',
'id': 1,
'title': 'Test static page',
'slug': 'test-static-page',
'markdown': 'Test static page content',
'page': 1,
'published_at': new Date('2013/12/30').getTime()
}]
}, {
'status': 'published',
'id': 2,
'title': 'Test normal post',
'slug': 'test-normal-post',
'markdown': 'The test normal post content',
'page': 0,
'published_at': new Date('2014/1/2').getTime()
'posts': [{
'status': 'published',
'id': 2,
'title': 'Test normal post',
'slug': 'test-normal-post',
'markdown': 'The test normal post content',
'page': 0,
'published_at': new Date('2014/1/2').getTime()
}]
}, {
'status': 'published',
'id': 3,
'title': 'About',
'slug': 'about',
'markdown': 'This is the about page content',
'page': 1,
'published_at': new Date('2014/1/30').getTime()
'posts': [{
'status': 'published',
'id': 3,
'title': 'About',
'slug': 'about',
'markdown': 'This is the about page content',
'page': 1,
'published_at': new Date('2014/1/30').getTime()
}]
}],
// Helper function to prevent unit tests
// from failing via timeout when they
@ -395,7 +401,9 @@ describe('Frontend Controller', function () {
beforeEach(function () {
sandbox.stub(api.posts, 'read', function (args) {
return when(_.find(mockPosts, args));
return when(_.find(mockPosts, function(mock) {
return mock.posts[0].slug === args.slug;
}));
});
apiSettingsStub = sandbox.stub(api.settings, 'read');
@ -433,16 +441,15 @@ describe('Frontend Controller', function () {
it('it will render custom page template if it exists', function (done) {
var req = {
path: '/' + mockPosts[2].slug
path: '/' + mockPosts[2].posts[0].slug
},
res = {
render: function (view, context) {
assert.equal(view, 'page-' + mockPosts[2].slug);
assert.equal(context.post, mockPosts[2]);
assert.equal(view, 'page-' + mockPosts[2].posts[0].slug);
assert.equal(context.post, mockPosts[2].posts[0]);
done();
}
};
frontend.single(req, res, failTest(done));
});
});
@ -456,12 +463,12 @@ describe('Frontend Controller', function () {
it('will render static page via /:slug', function (done) {
var req = {
path: '/' + mockPosts[0].slug
path: '/' + mockPosts[0].posts[0].slug
},
res = {
render: function (view, context) {
assert.equal(view, 'page');
assert.equal(context.post, mockPosts[0]);
assert.equal(context.post, mockPosts[0].posts[0]);
done();
}
};
@ -471,7 +478,7 @@ describe('Frontend Controller', function () {
it('will NOT render static page via /YYY/MM/DD/:slug', function (done) {
var req = {
path: '/' + ['2012/12/30', mockPosts[0].slug].join('/')
path: '/' + ['2012/12/30', mockPosts[0].posts[0].slug].join('/')
},
res = {
render: sinon.spy()
@ -485,13 +492,13 @@ describe('Frontend Controller', function () {
it('will redirect static page to admin edit page via /:slug/edit', function (done) {
var req = {
path: '/' + [mockPosts[0].slug, 'edit'].join('/')
path: '/' + [mockPosts[0].posts[0].slug, 'edit'].join('/')
},
res = {
render: sinon.spy(),
redirect: function(arg) {
res.render.called.should.be.false;
arg.should.eql(adminEditPagePath + mockPosts[0].id + '/');
arg.should.eql(adminEditPagePath + mockPosts[0].posts[0].id + '/');
done();
}
};
@ -501,7 +508,7 @@ describe('Frontend Controller', function () {
it('will NOT redirect static page to admin edit page via /YYYY/MM/DD/:slug/edit', function (done) {
var req = {
path: '/' + ['2012/12/30', mockPosts[0].slug, 'edit'].join('/')
path: '/' + ['2012/12/30', mockPosts[0].posts[0].slug, 'edit'].join('/')
},
res = {
render: sinon.spy(),
@ -525,12 +532,12 @@ describe('Frontend Controller', function () {
it('will render static page via /:slug', function (done) {
var req = {
path: '/' + mockPosts[0].slug
path: '/' + mockPosts[0].posts[0].slug
},
res = {
render: function (view, context) {
assert.equal(view, 'page');
assert.equal(context.post, mockPosts[0]);
assert.equal(context.post, mockPosts[0].posts[0]);
done();
}
};
@ -540,7 +547,7 @@ describe('Frontend Controller', function () {
it('will NOT render static page via /YYYY/MM/DD/:slug', function (done) {
var req = {
path: '/' + ['2012/12/30', mockPosts[0].slug].join('/')
path: '/' + ['2012/12/30', mockPosts[0].posts[0].slug].join('/')
},
res = {
render: sinon.spy()
@ -554,13 +561,13 @@ describe('Frontend Controller', function () {
it('will redirect static page to admin edit page via /:slug/edit', function (done) {
var req = {
path: '/' + [mockPosts[0].slug, 'edit'].join('/')
path: '/' + [mockPosts[0].posts[0].slug, 'edit'].join('/')
},
res = {
render: sinon.spy(),
redirect: function (arg) {
res.render.called.should.be.false;
arg.should.eql(adminEditPagePath + mockPosts[0].id + '/');
arg.should.eql(adminEditPagePath + mockPosts[0].posts[0].id + '/');
done();
}
};
@ -570,7 +577,7 @@ describe('Frontend Controller', function () {
it('will NOT redirect static page to admin edit page via /YYYY/MM/DD/:slug/edit', function (done) {
var req = {
path: '/' + ['2012/12/30', mockPosts[0].slug, 'edit'].join('/')
path: '/' + ['2012/12/30', mockPosts[0].posts[0].slug, 'edit'].join('/')
},
res = {
render: sinon.spy(),
@ -596,13 +603,13 @@ describe('Frontend Controller', function () {
it('will render post via /:slug', function (done) {
var req = {
path: '/' + mockPosts[1].slug
path: '/' + mockPosts[1].posts[0].slug
},
res = {
render: function (view, context) {
assert.equal(view, 'post');
assert(context.post, 'Context object has post attribute');
assert.equal(context.post, mockPosts[1]);
assert.equal(context.post, mockPosts[1].posts[0]);
done();
}
};
@ -612,7 +619,7 @@ describe('Frontend Controller', function () {
it('will NOT render post via /YYYY/MM/DD/:slug', function (done) {
var req = {
path: '/' + ['2012/12/30', mockPosts[1].slug].join('/')
path: '/' + ['2012/12/30', mockPosts[1].posts[0].slug].join('/')
},
res = {
render: sinon.spy()
@ -627,13 +634,13 @@ describe('Frontend Controller', function () {
// Handle Edit append
it('will redirect post to admin edit page via /:slug/edit', function (done) {
var req = {
path: '/' + [mockPosts[1].slug, 'edit'].join('/')
path: '/' + [mockPosts[1].posts[0].slug, 'edit'].join('/')
},
res = {
render: sinon.spy(),
redirect: function(arg) {
res.render.called.should.be.false;
arg.should.eql(adminEditPagePath + mockPosts[1].id + '/');
arg.should.eql(adminEditPagePath + mockPosts[1].posts[0].id + '/');
done();
}
};
@ -643,7 +650,7 @@ describe('Frontend Controller', function () {
it('will NOT redirect post to admin edit page via /YYYY/MM/DD/:slug/edit', function (done) {
var req = {
path: '/' + ['2012/12/30', mockPosts[1].slug, 'edit'].join('/')
path: '/' + ['2012/12/30', mockPosts[1].posts[0].slug, 'edit'].join('/')
},
res = {
render: sinon.spy(),
@ -666,15 +673,15 @@ describe('Frontend Controller', function () {
});
it('will render post via /YYYY/MM/DD/:slug', function (done) {
var date = moment(mockPosts[1].published_at).format('YYYY/MM/DD'),
var date = moment(mockPosts[1].posts[0].published_at).format('YYYY/MM/DD'),
req = {
path: '/' + [date, mockPosts[1].slug].join('/')
path: '/' + [date, mockPosts[1].posts[0].slug].join('/')
},
res = {
render: function (view, context) {
assert.equal(view, 'post');
assert(context.post, 'Context object has post attribute');
assert.equal(context.post, mockPosts[1]);
assert.equal(context.post, mockPosts[1].posts[0]);
done();
}
};
@ -685,7 +692,7 @@ describe('Frontend Controller', function () {
it('will NOT render post via /YYYY/MM/DD/:slug with non-matching date in url', function (done) {
var date = moment(mockPosts[1].published_at).subtract('days', 1).format('YYYY/MM/DD'),
req = {
path: '/' + [date, mockPosts[1].slug].join('/')
path: '/' + [date, mockPosts[1].posts[0].slug].join('/')
},
res = {
render: sinon.spy()
@ -699,7 +706,7 @@ describe('Frontend Controller', function () {
it('will NOT render post via /:slug', function (done) {
var req = {
path: '/' + mockPosts[1].slug
path: '/' + mockPosts[1].posts[0].slug
},
res = {
render: sinon.spy()
@ -713,15 +720,15 @@ describe('Frontend Controller', function () {
// Handle Edit append
it('will redirect post to admin edit page via /YYYY/MM/DD/:slug/edit', function (done) {
var dateFormat = moment(mockPosts[1].published_at).format('YYYY/MM/DD'),
var dateFormat = moment(mockPosts[1].posts[0].published_at).format('YYYY/MM/DD'),
req = {
path: '/' + [dateFormat, mockPosts[1].slug, 'edit'].join('/')
path: '/' + [dateFormat, mockPosts[1].posts[0].slug, 'edit'].join('/')
},
res = {
render: sinon.spy(),
redirect: function (arg) {
res.render.called.should.be.false;
arg.should.eql(adminEditPagePath + mockPosts[1].id + '/');
arg.should.eql(adminEditPagePath + mockPosts[1].posts[0].id + '/');
done();
}
};
@ -731,7 +738,7 @@ describe('Frontend Controller', function () {
it('will NOT redirect post to admin edit page via /:slug/edit', function (done) {
var req = {
path: '/' + [mockPosts[1].slug, 'edit'].join('/')
path: '/' + [mockPosts[1].posts[0].slug, 'edit'].join('/')
},
res = {
render: sinon.spy(),
@ -754,15 +761,15 @@ describe('Frontend Controller', function () {
});
it('will render post via /:year/:slug', function (done) {
var date = moment(mockPosts[1].published_at).format('YYYY'),
var date = moment(mockPosts[1].posts[0].published_at).format('YYYY'),
req = {
path: '/' + [date, mockPosts[1].slug].join('/')
path: '/' + [date, mockPosts[1].posts[0].slug].join('/')
},
res = {
render: function (view, context) {
assert.equal(view, 'post');
assert(context.post, 'Context object has post attribute');
assert.equal(context.post, mockPosts[1]);
assert.equal(context.post, mockPosts[1].posts[0]);
done();
}
};
@ -771,9 +778,9 @@ describe('Frontend Controller', function () {
});
it('will NOT render post via /YYYY/MM/DD/:slug', function (done) {
var date = moment(mockPosts[1].published_at).format('YYYY/MM/DD'),
var date = moment(mockPosts[1].posts[0].published_at).format('YYYY/MM/DD'),
req = {
path: '/' + [date, mockPosts[1].slug].join('/')
path: '/' + [date, mockPosts[1].posts[0].slug].join('/')
},
res = {
render: sinon.spy()
@ -786,9 +793,9 @@ describe('Frontend Controller', function () {
});
it('will NOT render post via /:year/slug when year does not match post year', function (done) {
var date = moment(mockPosts[1].published_at).subtract('years', 1).format('YYYY'),
var date = moment(mockPosts[1].posts[0].published_at).subtract('years', 1).format('YYYY'),
req = {
path: '/' + [date, mockPosts[1].slug].join('/')
path: '/' + [date, mockPosts[1].posts[0].slug].join('/')
},
res = {
render: sinon.spy()
@ -802,7 +809,7 @@ describe('Frontend Controller', function () {
it('will NOT render post via /:slug', function (done) {
var req = {
path: '/' + mockPosts[1].slug
path: '/' + mockPosts[1].posts[0].slug
},
res = {
render: sinon.spy()
@ -816,15 +823,15 @@ describe('Frontend Controller', function () {
// Handle Edit append
it('will redirect post to admin edit page via /:year/:slug/edit', function (done) {
var date = moment(mockPosts[1].published_at).format('YYYY'),
var date = moment(mockPosts[1].posts[0].published_at).format('YYYY'),
req = {
path: '/' + [date, mockPosts[1].slug, 'edit'].join('/')
path: '/' + [date, mockPosts[1].posts[0].slug, 'edit'].join('/')
},
res = {
render: sinon.spy(),
redirect: function (arg) {
res.render.called.should.be.false;
arg.should.eql(adminEditPagePath + mockPosts[1].id + '/');
arg.should.eql(adminEditPagePath + mockPosts[1].posts[0].id + '/');
done();
}
};
@ -834,7 +841,7 @@ describe('Frontend Controller', function () {
it('will NOT redirect post to admin edit page /:slug/edit', function (done) {
var req = {
path: '/' + [mockPosts[1].slug, 'edit'].join('/')
path: '/' + [mockPosts[1].posts[0].slug, 'edit'].join('/')
},
res = {
render: sinon.spy(),

View file

@ -8,7 +8,7 @@ var _ = require('lodash'),
posts: ['posts', 'page', 'limit', 'pages', 'total'],
post: ['id', 'uuid', 'title', 'slug', 'markdown', 'html', 'meta_title', 'meta_description',
'featured', 'image', 'status', 'language', 'author_id', 'created_at', 'created_by', 'updated_at',
'updated_by', 'published_at', 'published_by', 'page', 'author', 'user', 'tags'],
'updated_by', 'published_at', 'published_by', 'page', 'author', 'tags'],
// TODO: remove databaseVersion, dbHash
settings: ['databaseVersion', 'dbHash', 'title', 'description', 'email', 'logo', 'cover', 'defaultLang',
"permalinks", 'postsPerPage', 'forceI18n', 'activeTheme', 'activeApps', 'installedApps',