diff --git a/core/server/api/endpoints/comments-comments.js b/core/server/api/endpoints/comments-comments.js new file mode 100644 index 0000000000..56d7f8fd85 --- /dev/null +++ b/core/server/api/endpoints/comments-comments.js @@ -0,0 +1,146 @@ +const Promise = require('bluebird'); +const tpl = require('@tryghost/tpl'); +const errors = require('@tryghost/errors'); +const models = require('../../models'); +const ALLOWED_INCLUDES = ['post', 'member']; +const UNSAFE_ATTRS = ['status']; + +const messages = { + commentNotFound: 'Comment could not be found' +}; + +module.exports = { + docName: 'comments', + + browse: { + options: [ + 'include', + 'page', + 'limit', + 'fields', + 'filter', + 'order', + 'debug' + ], + validation: { + options: { + include: ALLOWED_INCLUDES + } + }, + permissions: true, + query(frame) { + return models.Comment.findPage(frame.options); + } + }, + + read: { + options: [ + 'include' + ], + data: [ + 'id', + 'email' + ], + validation: { + options: { + include: ALLOWED_INCLUDES + } + }, + permissions: true, + query(frame) { + return models.Comment.findOne(frame.data, frame.options) + .then((model) => { + if (!model) { + return Promise.reject(new errors.NotFoundError({ + message: tpl(messages.commentNotFound) + })); + } + + return model; + }); + } + }, + + edit: { + headers: {}, + options: [ + 'id', + 'include' + ], + validation: { + options: { + include: { + values: ALLOWED_INCLUDES + }, + id: { + required: true + } + } + }, + permissions: true, + query(frame) { + return models.Comment.edit(frame.data.comments[0], frame.options) + .then((model) => { + if (!model) { + return Promise.reject(new errors.NotFoundError({ + message: tpl(messages.commentNotFound) + })); + } + + return model; + }); + } + }, + + add: { + statusCode: 201, + options: [ + 'include' + + ], + validation: { + options: { + include: ALLOWED_INCLUDES + }, + data: { + member_id: { + required: true + }, + post_id: { + required: true + } + } + }, + permissions: { + unsafeAttrs: UNSAFE_ATTRS + }, + query(frame) { + return models.Comment.add(frame.data.comments[0], frame.options); + } + }, + + destroy: { + statusCode: 204, + options: [ + 'include', + 'id' + ], + validation: { + options: { + include: ALLOWED_INCLUDES + } + }, + permissions: true, + query(frame) { + frame.options.require = true; + + return models.Comment.destroy(frame.options) + .then(() => null) + .catch(models.Comment.NotFoundError, () => { + return Promise.reject(new errors.NotFoundError({ + message: tpl(messages.commentNotFound) + })); + }); + } + } +}; diff --git a/core/server/api/endpoints/index.js b/core/server/api/endpoints/index.js index 681db12fb6..9e2099cb2c 100644 --- a/core/server/api/endpoints/index.js +++ b/core/server/api/endpoints/index.js @@ -219,5 +219,13 @@ module.exports = { get offersPublic() { return shared.pipeline(require('./offers-public'), localUtils, 'content'); + }, + + /** + * Comment API + */ + + get commentsComments() { + return shared.pipeline(require('./comments-comments'), localUtils, 'comments'); } }; diff --git a/core/server/models/comment.js b/core/server/models/comment.js index 6e79bc6b66..22156844c4 100644 --- a/core/server/models/comment.js +++ b/core/server/models/comment.js @@ -31,13 +31,13 @@ const Comment = ghostBookshelf.Model.extend({ model.emitChange('added', options); } -}); - -const Comments = ghostBookshelf.Collection.extend({ - model: Comment +}, { + async permissible(model, action, context, unsafeAttrs, loadedPermissions, hasUserPermission, hasApiKeyPermission, hasMemberPermission) { + console.log('checking permissions', hasMemberPermission); + return true; + } }); module.exports = { - Comment: ghostBookshelf.model('Comment', Comment), - Comments: ghostBookshelf.collection('Comments', Comments) + Comment: ghostBookshelf.model('Comment', Comment) }; diff --git a/core/server/web/comments/app.js b/core/server/web/comments/app.js index 1f750fc0d7..71eeaf6fb9 100644 --- a/core/server/web/comments/app.js +++ b/core/server/web/comments/app.js @@ -1,9 +1,11 @@ const debug = require('@tryghost/debug')('comments'); const errorHandler = require('@tryghost/mw-error-handler'); const cors = require('cors'); +const bodyParser = require('body-parser'); const express = require('../../../shared/express'); const urlUtils = require('../../../shared/url-utils'); const sentry = require('../../../shared/sentry'); +const routes = require('./routes'); module.exports = function setupCommentsApp() { debug('Comments App setup start'); @@ -13,8 +15,10 @@ module.exports = function setupCommentsApp() { const siteUrl = new URL(urlUtils.getSiteUrl()); commentsApp.use(cors(siteUrl.origin)); + commentsApp.use(bodyParser.json({limit: '50mb'})); + // Routing - commentsApp.get('/api/comments'); + commentsApp.use('/api/', routes()); // API error handling commentsApp.use('/api', errorHandler.resourceNotFound); diff --git a/core/server/web/comments/routes.js b/core/server/web/comments/routes.js new file mode 100644 index 0000000000..749f086791 --- /dev/null +++ b/core/server/web/comments/routes.js @@ -0,0 +1,15 @@ +const express = require('../../../shared/express'); +const api = require('../../api').endpoints; +const http = require('../../api').shared.http; + +module.exports = function apiRoutes() { + const router = express.Router('content api'); + + router.get('/comments', http(api.commentsComments.browse)); + router.get('/comments/:id', http(api.commentsComments.read)); + router.post('/comments', http(api.commentsComments.add)); + router.put('/comments/:id', http(api.commentsComments.edit)); + router.delete('/comments/:id', http(api.commentsComments.destroy)); + + return router; +};