Ghost/core/server/api/posts.js
Hannah Wolfe ce06ad412a Adding and renaming permissions
refs #3283, refs #2739, refs #3096

- Renames permissions which didn't follow bread
- Adds permissions for notifications, mail and tags

Still todo:

- wire up the new permissions where they are needed
- add permissions for roles
2014-07-17 12:32:25 +01:00

197 lines
6.1 KiB
JavaScript

// # Posts API
// RESTful API for the Post resource
var when = require('when'),
_ = require('lodash'),
dataProvider = require('../models'),
canThis = require('../permissions').canThis,
errors = require('../errors'),
utils = require('./utils'),
docName = 'posts',
allowedIncludes = ['created_by', 'updated_by', 'published_by', 'author', 'tags', 'fields'],
posts;
// ## Helpers
function prepareInclude(include) {
var index;
include = _.intersection(include.split(','), allowedIncludes);
index = include.indexOf('author');
if (index !== -1) {
include[index] = 'author_id';
}
return include;
}
/**
* ## Posts API Methods
*
* **See:** [API Methods](index.js.html#api%20methods)
*/
posts = {
/**
* ### Browse
* Find a paginated set of posts
*
* Will only return published posts unless we have an authenticated user and an alternative status
* parameter.
*
* Will return without static pages unless told otherwise
*
* Can return posts for a particular tag by passing a tag slug in
*
* @public
* @param {{context, page, limit, status, staticPages, tag}} options (optional)
* @returns {Promise(Posts)} Posts Collection with Meta
*/
browse: function browse(options) {
options = options || {};
if (!(options.context && options.context.user)) {
options.status = 'published';
}
if (options.include) {
options.include = prepareInclude(options.include);
}
return dataProvider.Post.findPage(options);
},
/**
* ### Read
* Find a post, by ID or Slug
*
* @public
* @param {{id_or_slug (required), context, status, include, ...}} options
* @return {Promise(Post)} Post
*/
read: function read(options) {
var attrs = ['id', 'slug', 'status'],
data = _.pick(options, attrs);
options = _.omit(options, attrs);
// only published posts if no user is present
if (!(options.context && options.context.user)) {
data.status = 'published';
}
if (options.include) {
options.include = prepareInclude(options.include);
}
return dataProvider.Post.findOne(data, options).then(function (result) {
if (result) {
return { posts: [ result.toJSON() ]};
}
return when.reject(new errors.NotFoundError('Post not found.'));
});
},
/**
* ### Edit
* Update properties of a post
*
* @public
* @param {Post} object Post or specific properties to update
* @param {{id (required), context, include,...}} options
* @return {Promise(Post)} Edited Post
*/
edit: function edit(object, options) {
return canThis(options.context).edit.post(options.id).then(function () {
return utils.checkObject(object, docName).then(function (checkedPostData) {
if (options.include) {
options.include = prepareInclude(options.include);
}
return dataProvider.Post.edit(checkedPostData.posts[0], options);
}).then(function (result) {
if (result) {
var post = result.toJSON();
// If previously was not published and now is (or vice versa), signal the change
post.statusChanged = false;
if (result.updated('status') !== result.get('status')) {
post.statusChanged = true;
}
return { posts: [ post ]};
}
return when.reject(new errors.NotFoundError('Post not found.'));
});
}, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to edit this post.'));
});
},
/**
* ### Add
* Create a new post along with any tags
*
* @public
* @param {Post} object
* @param {{context, include,...}} options
* @return {Promise(Post)} Created Post
*/
add: function add(object, options) {
options = options || {};
return canThis(options.context).add.post().then(function () {
return utils.checkObject(object, docName).then(function (checkedPostData) {
if (options.include) {
options.include = prepareInclude(options.include);
}
return dataProvider.Post.add(checkedPostData.posts[0], options);
}).then(function (result) {
var post = result.toJSON();
if (post.status === 'published') {
// When creating a new post that is published right now, signal the change
post.statusChanged = true;
}
return { posts: [ post ]};
});
}, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to add posts.'));
});
},
/**
* ### Destroy
* Delete a post, cleans up tag relations, but not unused tags
*
* @public
* @param {{id (required), context,...}} options
* @return {Promise(Post)} Deleted Post
*/
destroy: function destroy(options) {
return canThis(options.context).destroy.post(options.id).then(function () {
var readOptions = _.extend({}, options, {status: 'all'});
return posts.read(readOptions).then(function (result) {
return dataProvider.Post.destroy(options).then(function () {
var deletedObj = result;
if (deletedObj.posts) {
_.each(deletedObj.posts, function (post) {
post.statusChanged = true;
});
}
return deletedObj;
});
});
}, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to remove posts.'));
});
}
};
module.exports = posts;