0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-11 02:12:21 -05:00

ES6 migration: server/api (#9761)

refs #9589

- not all of the api files were updated
This commit is contained in:
Mandeep Singh Gulati 2018-09-10 18:00:48 +05:30 committed by Katharina Irrgang
parent 5e963935f9
commit 03af23cddf
7 changed files with 161 additions and 153 deletions

View file

@ -4,7 +4,7 @@
// Ghost's JSON API is integral to the workings of Ghost, regardless of whether you want to access data internally, // Ghost's JSON API is integral to the workings of Ghost, regardless of whether you want to access data internally,
// from a theme, an app, or from an external app, you'll use the Ghost JSON API to do so. // from a theme, an app, or from an external app, you'll use the Ghost JSON API to do so.
var _ = require('lodash'), const {isEmpty} = require('lodash'),
Promise = require('bluebird'), Promise = require('bluebird'),
models = require('../models'), models = require('../models'),
urlService = require('../services/url'), urlService = require('../services/url'),
@ -29,9 +29,9 @@ var _ = require('lodash'),
exporter = require('../data/exporter'), exporter = require('../data/exporter'),
slack = require('./slack'), slack = require('./slack'),
webhooks = require('./webhooks'), webhooks = require('./webhooks'),
oembed = require('./oembed'), oembed = require('./oembed');
http, let http,
addHeaders, addHeaders,
cacheInvalidationHeader, cacheInvalidationHeader,
locationHeader, locationHeader,
@ -68,13 +68,14 @@ function isActiveThemeUpdate(method, endpoint, result) {
* @return {String} Resolves to header string * @return {String} Resolves to header string
*/ */
cacheInvalidationHeader = function cacheInvalidationHeader(req, result) { cacheInvalidationHeader = function cacheInvalidationHeader(req, result) {
var parsedUrl = req._parsedUrl.pathname.replace(/^\/|\/$/g, '').split('/'), const parsedUrl = req._parsedUrl.pathname.replace(/^\/|\/$/g, '').split('/'),
method = req.method, method = req.method,
endpoint = parsedUrl[0], endpoint = parsedUrl[0],
subdir = parsedUrl[1], subdir = parsedUrl[1],
jsonResult = result.toJSON ? result.toJSON() : result, jsonResult = result.toJSON ? result.toJSON() : result,
INVALIDATE_ALL = '/*', INVALIDATE_ALL = '/*';
post,
let post,
hasStatusChanged, hasStatusChanged,
wasPublishedUpdated; wasPublishedUpdated;
@ -123,15 +124,15 @@ cacheInvalidationHeader = function cacheInvalidationHeader(req, result) {
* @return {String} Resolves to header string * @return {String} Resolves to header string
*/ */
locationHeader = function locationHeader(req, result) { locationHeader = function locationHeader(req, result) {
var apiRoot = urlService.utils.urlFor('api'), const apiRoot = urlService.utils.urlFor('api');
location, let location,
newObject, newObject,
statusQuery; statusQuery;
if (req.method === 'POST') { if (req.method === 'POST') {
if (result.hasOwnProperty('posts')) { if (result.hasOwnProperty('posts')) {
newObject = result.posts[0]; newObject = result.posts[0];
statusQuery = '/?status=' + newObject.status; statusQuery = `/?status=${newObject.status}`;
location = urlService.utils.urlJoin(apiRoot, 'posts', newObject.id, statusQuery); location = urlService.utils.urlJoin(apiRoot, 'posts', newObject.id, statusQuery);
} else if (result.hasOwnProperty('notifications')) { } else if (result.hasOwnProperty('notifications')) {
newObject = result.notifications[0]; newObject = result.notifications[0];
@ -168,13 +169,13 @@ locationHeader = function locationHeader(req, result) {
contentDispositionHeaderExport = function contentDispositionHeaderExport() { contentDispositionHeaderExport = function contentDispositionHeaderExport() {
return exporter.fileName().then(function then(filename) { return exporter.fileName().then(function then(filename) {
return 'Attachment; filename="' + filename + '"'; return `Attachment; filename="${filename}"`;
}); });
}; };
contentDispositionHeaderSubscribers = function contentDispositionHeaderSubscribers() { contentDispositionHeaderSubscribers = function contentDispositionHeaderSubscribers() {
var datetime = (new Date()).toJSON().substring(0, 10); const datetime = (new Date()).toJSON().substring(0, 10);
return Promise.resolve('Attachment; filename="subscribers.' + datetime + '.csv"'); return Promise.resolve(`Attachment; filename="subscribers.${datetime}.csv"`);
}; };
contentDispositionHeaderRedirects = function contentDispositionHeaderRedirects() { contentDispositionHeaderRedirects = function contentDispositionHeaderRedirects() {
@ -186,7 +187,7 @@ contentDispositionHeaderRoutes = () => {
}; };
addHeaders = function addHeaders(apiMethod, req, res, result) { addHeaders = function addHeaders(apiMethod, req, res, result) {
var cacheInvalidation, let cacheInvalidation,
location, location,
contentDisposition; contentDisposition;
@ -267,7 +268,7 @@ http = function http(apiMethod) {
return function apiHandler(req, res, next) { return function apiHandler(req, res, next) {
// We define 2 properties for using as arguments in API calls: // We define 2 properties for using as arguments in API calls:
let object = req.body, let object = req.body,
options = _.extend({}, req.file, {ip: req.ip}, req.query, req.params, { options = Object.assign({}, req.file, {ip: req.ip}, req.query, req.params, {
context: { context: {
// @TODO: forward the client and user obj (options.context.user.id) // @TODO: forward the client and user obj (options.context.user.id)
user: ((req.user && req.user.id) || (req.user && models.User.isExternalUser(req.user.id))) ? req.user.id : null, user: ((req.user && req.user.id) || (req.user && models.User.isExternalUser(req.user.id))) ? req.user.id : null,
@ -282,7 +283,7 @@ http = function http(apiMethod) {
// If this is a GET, or a DELETE, req.body should be null, so we only have options (route and query params) // If this is a GET, or a DELETE, req.body should be null, so we only have options (route and query params)
// If this is a PUT, POST, or PATCH, req.body is an object // If this is a PUT, POST, or PATCH, req.body is an object
if (_.isEmpty(object)) { if (isEmpty(object)) {
object = options; object = options;
options = {}; options = {};
} }
@ -303,7 +304,7 @@ http = function http(apiMethod) {
// CASE: api method response wants to handle the express response // CASE: api method response wants to handle the express response
// example: serve files (stream) // example: serve files (stream)
if (_.isFunction(response)) { if (typeof response === 'function') {
return response(req, res, next); return response(req, res, next);
} }

View file

@ -1,5 +1,5 @@
var Promise = require('bluebird'), const Promise = require('bluebird'),
_ = require('lodash'), {omit, merge} = require('lodash'),
pipeline = require('../lib/promise/pipeline'), pipeline = require('../lib/promise/pipeline'),
mail = require('../services/mail'), mail = require('../services/mail'),
urlService = require('../services/url'), urlService = require('../services/url'),
@ -10,12 +10,11 @@ var Promise = require('bluebird'),
mailAPI = require('./mail'), mailAPI = require('./mail'),
settingsAPI = require('./settings'), settingsAPI = require('./settings'),
docName = 'invites', docName = 'invites',
allowedIncludes = ['created_by', 'updated_by'], allowedIncludes = ['created_by', 'updated_by'];
invites;
invites = { const invites = {
browse: function browse(options) { browse: (options) => {
var tasks; let tasks;
function modelQuery(options) { function modelQuery(options) {
return models.Invite.findPage(options); return models.Invite.findPage(options);
@ -31,12 +30,12 @@ invites = {
return pipeline(tasks, options); return pipeline(tasks, options);
}, },
read: function read(options) { read: (options) => {
var attrs = ['id', 'email'], const attrs = ['id', 'email'];
tasks; let tasks;
function modelQuery(options) { function modelQuery(options) {
return models.Invite.findOne(options.data, _.omit(options, ['data'])) return models.Invite.findOne(options.data, omit(options, ['data']))
.then(function onModelResponse(model) { .then(function onModelResponse(model) {
if (!model) { if (!model) {
return Promise.reject(new common.errors.NotFoundError({ return Promise.reject(new common.errors.NotFoundError({
@ -60,12 +59,12 @@ invites = {
return pipeline(tasks, options); return pipeline(tasks, options);
}, },
destroy: function destroy(options) { destroy: (options) => {
var tasks; let tasks;
function modelQuery(options) { function modelQuery(options) {
return models.Invite.findOne({id: options.id}, _.omit(options, ['data'])) return models.Invite.findOne({id: options.id}, omit(options, ['data']))
.then(function (invite) { .then((invite) => {
if (!invite) { if (!invite) {
throw new common.errors.NotFoundError({message: common.i18n.t('errors.api.invites.inviteNotFound')}); throw new common.errors.NotFoundError({message: common.i18n.t('errors.api.invites.inviteNotFound')});
} }
@ -84,23 +83,23 @@ invites = {
return pipeline(tasks, options); return pipeline(tasks, options);
}, },
add: function add(object, options) { add: (object, options) => {
var tasks, let loggedInUser = options.context.user,
loggedInUser = options.context.user, tasks,
emailData, emailData,
invite; invite;
function addInvite(options) { function addInvite(options) {
var data = options.data; const data = options.data;
return models.Invite.add(data.invites[0], _.omit(options, 'data')) return models.Invite.add(data.invites[0], omit(options, 'data'))
.then(function (_invite) { .then((_invite) => {
invite = _invite; invite = _invite;
return settingsAPI.read({key: 'title'}); return settingsAPI.read({key: 'title'});
}) })
.then(function (response) { .then((response) => {
var adminUrl = urlService.utils.urlFor('admin', true); const adminUrl = urlService.utils.urlFor('admin', true);
emailData = { emailData = {
blogName: response.settings[0].value, blogName: response.settings[0].value,
@ -111,8 +110,8 @@ invites = {
}; };
return mail.utils.generateContent({data: emailData, template: 'invite-user'}); return mail.utils.generateContent({data: emailData, template: 'invite-user'});
}).then(function (emailContent) { }).then((emailContent) => {
var payload = { const payload = {
mail: [{ mail: [{
message: { message: {
to: invite.get('email'), to: invite.get('email'),
@ -128,20 +127,23 @@ invites = {
}; };
return mailAPI.send(payload, {context: {internal: true}}); return mailAPI.send(payload, {context: {internal: true}});
}).then(function () { }).then(() => {
options.id = invite.id; options.id = invite.id;
return models.Invite.edit({status: 'sent'}, options); return models.Invite.edit({status: 'sent'}, options);
}).then(function () { }).then(() => {
invite.set('status', 'sent'); invite.set('status', 'sent');
var inviteAsJSON = invite.toJSON(); const inviteAsJSON = invite.toJSON();
return { return {
invites: [inviteAsJSON] invites: [inviteAsJSON]
}; };
}).catch(function (error) { }).catch((error) => {
if (error && error.errorType === 'EmailError') { if (error && error.errorType === 'EmailError') {
error.message = common.i18n.t('errors.api.invites.errorSendingEmail.error', {message: error.message}) + ' ' + const errorMessage = common.i18n.t('errors.api.invites.errorSendingEmail.error', {
common.i18n.t('errors.api.invites.errorSendingEmail.help'); message: error.message
});
const helpText = common.i18n.t('errors.api.invites.errorSendingEmail.help');
error.message = `${errorMessage} ${helpText}`;
common.logging.warn(error.message); common.logging.warn(error.message);
} }
@ -150,19 +152,17 @@ invites = {
} }
function destroyOldInvite(options) { function destroyOldInvite(options) {
var data = options.data; const data = options.data;
return models.Invite.findOne({email: data.invites[0].email}, _.omit(options, 'data')) return models.Invite.findOne({email: data.invites[0].email}, omit(options, 'data'))
.then(function (invite) { .then((invite) => {
if (!invite) { if (!invite) {
return Promise.resolve(options); return Promise.resolve(options);
} }
return invite.destroy(options); return invite.destroy(options);
}) })
.then(function () { .then(() => { return options; });
return options;
});
} }
function validation(options) { function validation(options) {
@ -179,7 +179,7 @@ invites = {
// We cannot use permissible because we don't have access to the role_id!!! // We cannot use permissible because we don't have access to the role_id!!!
// Adding a permissible function to the invite model, doesn't give us much context of the invite we would like to add // Adding a permissible function to the invite model, doesn't give us much context of the invite we would like to add
// As we are looking forward to replace the permission system completely, we do not add a hack here // As we are looking forward to replace the permission system completely, we do not add a hack here
return models.Role.findOne({id: options.data.invites[0].role_id}).then(function (roleToInvite) { return models.Role.findOne({id: options.data.invites[0].role_id}).then((roleToInvite) => {
if (!roleToInvite) { if (!roleToInvite) {
return Promise.reject(new common.errors.NotFoundError({message: common.i18n.t('errors.api.invites.roleNotFound')})); return Promise.reject(new common.errors.NotFoundError({message: common.i18n.t('errors.api.invites.roleNotFound')}));
} }
@ -188,8 +188,8 @@ invites = {
return Promise.reject(new common.errors.NoPermissionError({message: common.i18n.t('errors.api.invites.notAllowedToInviteOwner')})); return Promise.reject(new common.errors.NoPermissionError({message: common.i18n.t('errors.api.invites.notAllowedToInviteOwner')}));
} }
var loggedInUserRole = loggedInUser.related('roles').models[0].get('name'), const loggedInUserRole = loggedInUser.related('roles').models[0].get('name');
allowed = []; let allowed = [];
if (loggedInUserRole === 'Owner' || loggedInUserRole === 'Administrator') { if (loggedInUserRole === 'Owner' || loggedInUserRole === 'Administrator') {
allowed = ['Administrator', 'Editor', 'Author', 'Contributor']; allowed = ['Administrator', 'Editor', 'Author', 'Contributor'];
@ -202,14 +202,12 @@ invites = {
message: common.i18n.t('errors.api.invites.notAllowedToInvite') message: common.i18n.t('errors.api.invites.notAllowedToInvite')
})); }));
} }
}).then(function () { }).then(() => { return options; });
return options;
});
} }
function checkIfUserExists(options) { function checkIfUserExists(options) {
return models.User.findOne({email: options.data.invites[0].email}, options) return models.User.findOne({email: options.data.invites[0].email}, options)
.then(function (user) { .then((user) => {
if (user) { if (user) {
return Promise.reject(new common.errors.ValidationError({ return Promise.reject(new common.errors.ValidationError({
message: common.i18n.t('errors.api.users.userAlreadyRegistered') message: common.i18n.t('errors.api.users.userAlreadyRegistered')
@ -221,8 +219,8 @@ invites = {
} }
function fetchLoggedInUser(options) { function fetchLoggedInUser(options) {
return models.User.findOne({id: loggedInUser}, _.merge({}, _.omit(options, 'data'), {withRelated: ['roles']})) return models.User.findOne({id: loggedInUser}, merge({}, omit(options, 'data'), {withRelated: ['roles']}))
.then(function (user) { .then((user) => {
if (!user) { if (!user) {
return Promise.reject(new common.errors.NotFoundError({message: common.i18n.t('errors.api.users.userNotFound')})); return Promise.reject(new common.errors.NotFoundError({message: common.i18n.t('errors.api.users.userNotFound')}));
} }

View file

@ -1,16 +1,16 @@
// # Mail API // # Mail API
// API for sending Mail // API for sending Mail
var Promise = require('bluebird'), const Promise = require('bluebird'),
pipeline = require('../lib/promise/pipeline'), pipeline = require('../lib/promise/pipeline'),
localUtils = require('./utils'), localUtils = require('./utils'),
models = require('../models'), models = require('../models'),
common = require('../lib/common'), common = require('../lib/common'),
mail = require('../services/mail'), mail = require('../services/mail'),
notificationsAPI = require('./notifications'), notificationsAPI = require('./notifications'),
docName = 'mail', docName = 'mail';
mailer,
apiMail; let mailer;
/** /**
* Send mail helper * Send mail helper
@ -20,7 +20,7 @@ function sendMail(object) {
mailer = new mail.GhostMailer(); mailer = new mail.GhostMailer();
} }
return mailer.send(object.mail[0].message).catch(function (err) { return mailer.send(object.mail[0].message).catch((err) => {
if (mailer.state.usingDirect) { if (mailer.state.usingDirect) {
notificationsAPI.add( notificationsAPI.add(
{ {
@ -47,7 +47,7 @@ function sendMail(object) {
* @typedef Mail * @typedef Mail
* @param mail * @param mail
*/ */
apiMail = { const apiMail = {
/** /**
* ### Send * ### Send
* Send an email * Send an email
@ -56,8 +56,8 @@ apiMail = {
* @param {Mail} object details of the email to send * @param {Mail} object details of the email to send
* @returns {Promise} * @returns {Promise}
*/ */
send: function (object, options) { send: (object, options) => {
var tasks; let tasks;
/** /**
* ### Format Response * ### Format Response
@ -100,8 +100,8 @@ apiMail = {
* @param {Object} options required property 'to' which contains the recipient address * @param {Object} options required property 'to' which contains the recipient address
* @returns {Promise} * @returns {Promise}
*/ */
sendTest: function (options) { sendTest: (options) => {
var tasks; let tasks;
/** /**
* ### Model Query * ### Model Query
@ -116,8 +116,8 @@ apiMail = {
*/ */
function generateContent(result) { function generateContent(result) {
return mail.utils.generateContent({template: 'test'}).then(function (content) { return mail.utils.generateContent({template: 'test'}).then((content) => {
var payload = { const payload = {
mail: [{ mail: [{
message: { message: {
to: result.get('email'), to: result.get('email'),

View file

@ -2,7 +2,7 @@
// RESTful API for creating notifications // RESTful API for creating notifications
const Promise = require('bluebird'), const Promise = require('bluebird'),
_ = require('lodash'), {merge, orderBy, remove} = require('lodash'),
semver = require('semver'), semver = require('semver'),
moment = require('moment'), moment = require('moment'),
ObjectId = require('bson-objectid'), ObjectId = require('bson-objectid'),
@ -21,11 +21,11 @@ let notifications,
_private.fetchAllNotifications = function fetchAllNotifications() { _private.fetchAllNotifications = function fetchAllNotifications() {
let allNotifications; let allNotifications;
return SettingsAPI.read(_.merge({key: 'notifications'}, internalContext)) return SettingsAPI.read(merge({key: 'notifications'}, internalContext))
.then(function (response) { .then((response) => {
allNotifications = JSON.parse(response.settings[0].value || []); allNotifications = JSON.parse(response.settings[0].value || []);
_.each(allNotifications, function (notification) { allNotifications.forEach((notification) => {
notification.addedAt = moment(notification.addedAt).toDate(); notification.addedAt = moment(notification.addedAt).toDate();
}); });
@ -34,7 +34,7 @@ _private.fetchAllNotifications = function fetchAllNotifications() {
}; };
_private.publicResponse = function publicResponse(notificationsToReturn) { _private.publicResponse = function publicResponse(notificationsToReturn) {
_.each(notificationsToReturn, function (notification) { notificationsToReturn.forEach((notification) => {
delete notification.seen; delete notification.seen;
delete notification.addedAt; delete notification.addedAt;
}); });
@ -56,17 +56,17 @@ notifications = {
* Fetch all notifications * Fetch all notifications
* @returns {Promise(Notifications)} * @returns {Promise(Notifications)}
*/ */
browse: function browse(options) { browse: (options) => {
return canThis(options.context).browse.notification().then(function () { return canThis(options.context).browse.notification().then(() => {
return _private.fetchAllNotifications() return _private.fetchAllNotifications()
.then(function (allNotifications) { .then((allNotifications) => {
allNotifications = _.orderBy(allNotifications, 'addedAt', 'desc'); allNotifications = orderBy(allNotifications, 'addedAt', 'desc');
allNotifications = allNotifications.filter(function (notification) { allNotifications = allNotifications.filter((notification) => {
// CASE: do not return old release notification // CASE: do not return old release notification
if (!notification.custom && notification.message) { if (!notification.custom && notification.message) {
let notificationVersion = notification.message.match(/(\d+\.)(\d+\.)(\d+)/); const notificationVersion = notification.message.match(/(\d+\.)(\d+\.)(\d+)/),
let blogVersion = ghostVersion.full.match(/^(\d+\.)(\d+\.)(\d+)/); blogVersion = ghostVersion.full.match(/^(\d+\.)(\d+\.)(\d+)/);
if (notificationVersion && blogVersion && semver.gt(notificationVersion[0], blogVersion[0])) { if (notificationVersion && blogVersion && semver.gt(notificationVersion[0], blogVersion[0])) {
return true; return true;
@ -80,7 +80,7 @@ notifications = {
return _private.publicResponse(allNotifications); return _private.publicResponse(allNotifications);
}); });
}, function () { }, () => {
return Promise.reject(new common.errors.NoPermissionError({ return Promise.reject(new common.errors.NoPermissionError({
message: common.i18n.t('errors.api.notifications.noPermissionToBrowseNotif') message: common.i18n.t('errors.api.notifications.noPermissionToBrowseNotif')
})); }));
@ -106,8 +106,8 @@ notifications = {
* }] }; * }] };
* ``` * ```
*/ */
add: function add(object, options) { add: (object, options) => {
var tasks; let tasks;
/** /**
* ### Handle Permissions * ### Handle Permissions
@ -120,9 +120,9 @@ notifications = {
return Promise.resolve(options); return Promise.resolve(options);
} }
return canThis(options.context).add.notification().then(function () { return canThis(options.context).add.notification().then(() => {
return options; return options;
}, function () { }, () => {
return Promise.reject(new common.errors.NoPermissionError({ return Promise.reject(new common.errors.NoPermissionError({
message: common.i18n.t('errors.api.notifications.noPermissionToAddNotif') message: common.i18n.t('errors.api.notifications.noPermissionToAddNotif')
})); }));
@ -136,7 +136,7 @@ notifications = {
* @returns {Object} options * @returns {Object} options
*/ */
function saveNotifications(options) { function saveNotifications(options) {
let defaults = { const defaults = {
dismissible: true, dismissible: true,
location: 'bottom', location: 'bottom',
status: 'alert', status: 'alert',
@ -146,26 +146,28 @@ notifications = {
seen: false, seen: false,
addedAt: moment().toDate() addedAt: moment().toDate()
}, },
notificationsToCheck = options.data.notifications, notificationsToCheck = options.data.notifications;
addedNotifications = []; let addedNotifications = [];
return _private.fetchAllNotifications() return _private.fetchAllNotifications()
.then(function (allNotifications) { .then((allNotifications) => {
_.each(notificationsToCheck, function (notification) { notificationsToCheck.forEach((notification) => {
let isDuplicate = _.find(allNotifications, {id: notification.id}); const isDuplicate = allNotifications.find((n) => {
return n.id === notification.id;
});
if (!isDuplicate) { if (!isDuplicate) {
addedNotifications.push(_.merge({}, defaults, notification, overrides)); addedNotifications.push(merge({}, defaults, notification, overrides));
} }
}); });
let hasReleaseNotification = _.find(notificationsToCheck, {custom: false}); const hasReleaseNotification = notificationsToCheck.find((notification) => {
return !notification.custom;
});
// CASE: remove any existing release notifications if a new release notification comes in // CASE: remove any existing release notifications if a new release notification comes in
if (hasReleaseNotification) { if (hasReleaseNotification) {
_.remove(allNotifications, function (el) { remove(allNotifications, (el) => { return !el.custom; });
return !el.custom;
});
} }
// CASE: nothing to add, skip // CASE: nothing to add, skip
@ -173,12 +175,16 @@ notifications = {
return Promise.resolve(); return Promise.resolve();
} }
let addedReleaseNotifications = _.filter(addedNotifications, {custom: false}); const addedReleaseNotifications = addedNotifications.filter((notification) => {
return !notification.custom;
});
// CASE: only latest release notification // CASE: only latest release notification
if (addedReleaseNotifications.length > 1) { if (addedReleaseNotifications.length > 1) {
addedNotifications = _.filter(addedNotifications, {custom: true}); addedNotifications = addedNotifications.filter((notification) => {
addedNotifications.push(_.orderBy(addedReleaseNotifications, 'created_at', 'desc')[0]); return notification.custom;
});
addedNotifications.push(orderBy(addedReleaseNotifications, 'created_at', 'desc')[0]);
} }
return SettingsAPI.edit({ return SettingsAPI.edit({
@ -188,9 +194,7 @@ notifications = {
}] }]
}, internalContext); }, internalContext);
}) })
.then(function () { .then(() => { return _private.publicResponse(addedNotifications); });
return _private.publicResponse(addedNotifications);
});
} }
tasks = [ tasks = [
@ -209,7 +213,7 @@ notifications = {
* @param {{id (required), context}} options * @param {{id (required), context}} options
* @returns {Promise} * @returns {Promise}
*/ */
destroy: function destroy(options) { destroy: (options) => {
let tasks; let tasks;
/** /**
@ -219,9 +223,9 @@ notifications = {
* @returns {Object} options * @returns {Object} options
*/ */
function handlePermissions(options) { function handlePermissions(options) {
return canThis(options.context).destroy.notification().then(function () { return canThis(options.context).destroy.notification().then(() => {
return options; return options;
}, function () { }, () => {
return Promise.reject(new common.errors.NoPermissionError({ return Promise.reject(new common.errors.NoPermissionError({
message: common.i18n.t('errors.api.notifications.noPermissionToDestroyNotif') message: common.i18n.t('errors.api.notifications.noPermissionToDestroyNotif')
})); }));
@ -230,9 +234,13 @@ notifications = {
function destroyNotification(options) { function destroyNotification(options) {
return _private.fetchAllNotifications() return _private.fetchAllNotifications()
.then(function (allNotifications) { .then((allNotifications) => {
let notificationToMarkAsSeen = _.find(allNotifications, {id: options.id}), const notificationToMarkAsSeen = allNotifications.find((notification) => {
notificationToMarkAsSeenIndex = _.findIndex(allNotifications, {id: options.id}); return notification.id === options.id;
}),
notificationToMarkAsSeenIndex = allNotifications.findIndex((notification) => {
return notification.id === options.id;
});
if (notificationToMarkAsSeenIndex > -1 && !notificationToMarkAsSeen.dismissible) { if (notificationToMarkAsSeenIndex > -1 && !notificationToMarkAsSeen.dismissible) {
return Promise.reject(new common.errors.NoPermissionError({ return Promise.reject(new common.errors.NoPermissionError({
@ -277,12 +285,12 @@ notifications = {
* @private Not exposed over HTTP * @private Not exposed over HTTP
* @returns {Promise} * @returns {Promise}
*/ */
destroyAll: function destroyAll(options) { destroyAll: (options) => {
return canThis(options.context).destroy.notification() return canThis(options.context).destroy.notification()
.then(function () { .then(() => {
return _private.fetchAllNotifications() return _private.fetchAllNotifications()
.then(function (allNotifications) { .then((allNotifications) => {
_.each(allNotifications, function (notification) { allNotifications.forEach((notification) => {
notification.seen = true; notification.seen = true;
}); });
@ -294,7 +302,7 @@ notifications = {
}, internalContext); }, internalContext);
}) })
.return(); .return();
}, function (err) { }, (err) => {
return Promise.reject(new common.errors.NoPermissionError({ return Promise.reject(new common.errors.NoPermissionError({
err: err, err: err,
context: common.i18n.t('errors.api.notifications.noPermissionToDestroyNotif') context: common.i18n.t('errors.api.notifications.noPermissionToDestroyNotif')

View file

@ -32,7 +32,7 @@ const getOembedUrlFromHTML = function getOembedUrlFromHTML(html) {
return cheerio('link[type="application/json+oembed"]', html).attr('href'); return cheerio('link[type="application/json+oembed"]', html).attr('href');
}; };
let oembed = { const oembed = {
read(options) { read(options) {
let {url} = options; let {url} = options;

View file

@ -1,7 +1,7 @@
// # Posts API // # Posts API
// RESTful API for the Post resource // RESTful API for the Post resource
const Promise = require('bluebird'), const Promise = require('bluebird'),
_ = require('lodash'), {omit, defaults} = require('lodash'),
pipeline = require('../lib/promise/pipeline'), pipeline = require('../lib/promise/pipeline'),
localUtils = require('./utils'), localUtils = require('./utils'),
models = require('../models'), models = require('../models'),
@ -38,9 +38,9 @@ posts = {
* @param {{context, page, limit, status, staticPages, tag, featured}} options (optional) * @param {{context, page, limit, status, staticPages, tag, featured}} options (optional)
* @returns {Promise<Posts>} Posts Collection with Meta * @returns {Promise<Posts>} Posts Collection with Meta
*/ */
browse: function browse(options) { browse: (options) => {
var extraOptions = ['status', 'formats', 'absolute_urls'], const extraOptions = ['status', 'formats', 'absolute_urls'];
permittedOptions, let permittedOptions,
tasks; tasks;
// Workaround to remove static pages from results // Workaround to remove static pages from results
@ -80,11 +80,12 @@ posts = {
* @param {Object} options * @param {Object} options
* @return {Promise<Post>} Post * @return {Promise<Post>} Post
*/ */
read: function read(options) { read: (options) => {
var attrs = ['id', 'slug', 'status', 'uuid'], const attrs = ['id', 'slug', 'status', 'uuid'],
// NOTE: the scheduler API uses the post API and forwards custom options // NOTE: the scheduler API uses the post API and forwards custom options
extraAllowedOptions = options.opts || ['formats', 'absolute_urls'], extraAllowedOptions = options.opts || ['formats', 'absolute_urls'];
tasks;
let tasks;
/** /**
* ### Model Query * ### Model Query
@ -93,7 +94,7 @@ posts = {
* @returns {Object} options * @returns {Object} options
*/ */
function modelQuery(options) { function modelQuery(options) {
return models.Post.findOne(options.data, _.omit(options, ['data'])) return models.Post.findOne(options.data, omit(options, ['data']))
.then(function onModelResponse(model) { .then(function onModelResponse(model) {
if (!model) { if (!model) {
return Promise.reject(new common.errors.NotFoundError({ return Promise.reject(new common.errors.NotFoundError({
@ -128,10 +129,10 @@ posts = {
* @param {{id (required), context, include,...}} options * @param {{id (required), context, include,...}} options
* @return {Promise(Post)} Edited Post * @return {Promise(Post)} Edited Post
*/ */
edit: function edit(object, options) { edit: (object, options) => {
var tasks, let tasks;
// NOTE: the scheduler API uses the post API and forwards custom options // NOTE: the scheduler API uses the post API and forwards custom options
extraAllowedOptions = options.opts || []; const extraAllowedOptions = options.opts || [];
/** /**
* ### Model Query * ### Model Query
@ -140,7 +141,7 @@ posts = {
* @returns {Object} options * @returns {Object} options
*/ */
function modelQuery(options) { function modelQuery(options) {
return models.Post.edit(options.data.posts[0], _.omit(options, ['data'])) return models.Post.edit(options.data.posts[0], omit(options, ['data']))
.then(function onModelResponse(model) { .then(function onModelResponse(model) {
if (!model) { if (!model) {
return Promise.reject(new common.errors.NotFoundError({ return Promise.reject(new common.errors.NotFoundError({
@ -148,7 +149,7 @@ posts = {
})); }));
} }
var post = model.toJSON(options); const post = model.toJSON(options);
// If previously was not published and now is (or vice versa), signal the change // If previously was not published and now is (or vice versa), signal the change
// @TODO: `statusChanged` get's added for the API headers only. Reconsider this. // @TODO: `statusChanged` get's added for the API headers only. Reconsider this.
@ -184,8 +185,8 @@ posts = {
* @param {{context, include,...}} options * @param {{context, include,...}} options
* @return {Promise(Post)} Created Post * @return {Promise(Post)} Created Post
*/ */
add: function add(object, options) { add: (object, options) => {
var tasks; let tasks;
/** /**
* ### Model Query * ### Model Query
@ -194,9 +195,9 @@ posts = {
* @returns {Object} options * @returns {Object} options
*/ */
function modelQuery(options) { function modelQuery(options) {
return models.Post.add(options.data.posts[0], _.omit(options, ['data'])) return models.Post.add(options.data.posts[0], omit(options, ['data']))
.then(function onModelResponse(model) { .then(function onModelResponse(model) {
var post = model.toJSON(options); const post = model.toJSON(options);
if (post.status === 'published') { if (post.status === 'published') {
// When creating a new post that is published right now, signal the change // When creating a new post that is published right now, signal the change
@ -228,18 +229,18 @@ posts = {
* @param {{id (required), context,...}} options * @param {{id (required), context,...}} options
* @return {Promise} * @return {Promise}
*/ */
destroy: function destroy(options) { destroy: (options) => {
var tasks; let tasks;
/** /**
* @function deletePost * @function deletePost
* @param {Object} options * @param {Object} options
*/ */
function deletePost(options) { function deletePost(options) {
const opts = _.defaults({require: true}, options); const opts = defaults({require: true}, options);
return models.Post.destroy(opts).return(null) return models.Post.destroy(opts).return(null)
.catch(models.Post.NotFoundError, function () { .catch(models.Post.NotFoundError, () => {
throw new common.errors.NotFoundError({ throw new common.errors.NotFoundError({
message: common.i18n.t('errors.api.posts.postNotFound') message: common.i18n.t('errors.api.posts.postNotFound')
}); });

View file

@ -12,7 +12,7 @@ let redirectsAPI,
_private = {}; _private = {};
_private.readRedirectsFile = function readRedirectsFile(customRedirectsPath) { _private.readRedirectsFile = function readRedirectsFile(customRedirectsPath) {
let redirectsPath = customRedirectsPath || path.join(config.getContentPath('data'), 'redirects.json'); const redirectsPath = customRedirectsPath || path.join(config.getContentPath('data'), 'redirects.json');
return fs.readFile(redirectsPath, 'utf-8') return fs.readFile(redirectsPath, 'utf-8')
.then(function serveContent(content) { .then(function serveContent(content) {
@ -42,43 +42,43 @@ _private.readRedirectsFile = function readRedirectsFile(customRedirectsPath) {
}; };
redirectsAPI = { redirectsAPI = {
download: function download(options) { download: (options) => {
return localUtils.handlePermissions('redirects', 'download')(options) return localUtils.handlePermissions('redirects', 'download')(options)
.then(function () { .then(() => {
return _private.readRedirectsFile(); return _private.readRedirectsFile();
}); });
}, },
upload: function upload(options) { upload: (options) => {
let redirectsPath = path.join(config.getContentPath('data'), 'redirects.json'), const redirectsPath = path.join(config.getContentPath('data'), 'redirects.json'),
backupRedirectsPath = path.join(config.getContentPath('data'), `redirects-${moment().format('YYYY-MM-DD-HH-mm-ss')}.json`); backupRedirectsPath = path.join(config.getContentPath('data'), `redirects-${moment().format('YYYY-MM-DD-HH-mm-ss')}.json`);
return localUtils.handlePermissions('redirects', 'upload')(options) return localUtils.handlePermissions('redirects', 'upload')(options)
.then(function backupOldRedirectsFile() { .then(function backupOldRedirectsFile() {
return fs.pathExists(redirectsPath) return fs.pathExists(redirectsPath)
.then(function (exists) { .then((exists) => {
if (!exists) { if (!exists) {
return null; return null;
} }
return fs.pathExists(backupRedirectsPath) return fs.pathExists(backupRedirectsPath)
.then(function (exists) { .then((exists) => {
if (!exists) { if (!exists) {
return null; return null;
} }
return fs.unlink(backupRedirectsPath); return fs.unlink(backupRedirectsPath);
}) })
.then(function () { .then(() => {
return fs.move(redirectsPath, backupRedirectsPath); return fs.move(redirectsPath, backupRedirectsPath);
}); });
}) })
.then(function overrideFile() { .then(function overrideFile() {
return _private.readRedirectsFile(options.path) return _private.readRedirectsFile(options.path)
.then(function (content) { .then((content) => {
validation.validateRedirects(content); validation.validateRedirects(content);
return fs.writeFile(redirectsPath, JSON.stringify(content), 'utf-8'); return fs.writeFile(redirectsPath, JSON.stringify(content), 'utf-8');
}) })
.then(function () { .then(() => {
// CASE: trigger that redirects are getting re-registered // CASE: trigger that redirects are getting re-registered
customRedirectsMiddleware.reload(); customRedirectsMiddleware.reload();
}); });