Ghost/core/server/api/v2/notifications.js
2018-10-12 21:13:20 +02:00

197 lines
6.4 KiB
JavaScript

const moment = require('moment-timezone');
const semver = require('semver');
const Promise = require('bluebird');
const _ = require('lodash');
const settingsCache = require('../../services/settings/cache');
const ghostVersion = require('../../lib/ghost-version');
const common = require('../../lib/common');
const ObjectId = require('bson-objectid');
const api = require('./index');
const internalContext = {context: {internal: true}};
const _private = {};
_private.fetchAllNotifications = () => {
let allNotifications = settingsCache.get('notifications');
allNotifications.forEach((notification) => {
notification.addedAt = moment(notification.addedAt).toDate();
});
return allNotifications;
};
module.exports = {
docName: 'notifications',
browse: {
permissions: true,
query() {
let allNotifications = _private.fetchAllNotifications();
allNotifications = _.orderBy(allNotifications, 'addedAt', 'desc');
allNotifications = allNotifications.filter((notification) => {
// CASE: do not return old release notification
if (!notification.custom && notification.message) {
const notificationVersion = notification.message.match(/(\d+\.)(\d+\.)(\d+)/),
blogVersion = ghostVersion.full.match(/^(\d+\.)(\d+\.)(\d+)/);
if (notificationVersion && blogVersion && semver.gt(notificationVersion[0], blogVersion[0])) {
return true;
} else {
return false;
}
}
return notification.seen !== true;
});
return allNotifications;
}
},
add: {
statusCode(result) {
if (result.notifications.length) {
return 201;
} else {
return 200;
}
},
permissions: true,
query(frame) {
const defaults = {
dismissible: true,
location: 'bottom',
status: 'alert',
id: ObjectId.generate()
};
const overrides = {
seen: false,
addedAt: moment().toDate()
};
let notificationsToCheck = frame.data.notifications;
let addedNotifications = [];
const allNotifications = _private.fetchAllNotifications();
notificationsToCheck.forEach((notification) => {
const isDuplicate = allNotifications.find((n) => {
return n.id === notification.id;
});
if (!isDuplicate) {
addedNotifications.push(Object.assign({}, defaults, notification, overrides));
}
});
const hasReleaseNotification = notificationsToCheck.find((notification) => {
return !notification.custom;
});
// CASE: remove any existing release notifications if a new release notification comes in
if (hasReleaseNotification) {
_.remove(allNotifications, (el) => {
return !el.custom;
});
}
// CASE: nothing to add, skip
if (!addedNotifications.length) {
return Promise.resolve();
}
const addedReleaseNotifications = addedNotifications.filter((notification) => {
return !notification.custom;
});
// CASE: only latest release notification
if (addedReleaseNotifications.length > 1) {
addedNotifications = addedNotifications.filter((notification) => {
return notification.custom;
});
addedNotifications.push(_.orderBy(addedReleaseNotifications, 'created_at', 'desc')[0]);
}
return api.settings.edit({
settings: [{
key: 'notifications',
value: allNotifications.concat(addedNotifications)
}]
}, internalContext).then(() => {
return addedNotifications;
});
}
},
destroy: {
statusCode: 204,
options: ['notification_id'],
validation: {
options: {
notification_id: {
required: true
}
}
},
permissions: true,
query(frame) {
const allNotifications = _private.fetchAllNotifications();
const notificationToMarkAsSeen = allNotifications.find((notification) => {
return notification.id === frame.options.notification_id;
}),
notificationToMarkAsSeenIndex = allNotifications.findIndex((notification) => {
return notification.id === frame.options.notification_id;
});
if (notificationToMarkAsSeenIndex > -1 && !notificationToMarkAsSeen.dismissible) {
return Promise.reject(new common.errors.NoPermissionError({
message: common.i18n.t('errors.api.notifications.noPermissionToDismissNotif')
}));
}
if (notificationToMarkAsSeenIndex < 0) {
return Promise.reject(new common.errors.NotFoundError({
message: common.i18n.t('errors.api.notifications.notificationDoesNotExist')
}));
}
if (notificationToMarkAsSeen.seen) {
return Promise.resolve();
}
allNotifications[notificationToMarkAsSeenIndex].seen = true;
return api.settings.edit({
settings: [{
key: 'notifications',
value: allNotifications
}]
}, internalContext).return();
}
},
destroyAll: {
statusCode: 204,
permissions: {
method: 'destroy'
},
query() {
const allNotifications = _private.fetchAllNotifications();
allNotifications.forEach((notification) => {
notification.seen = true;
});
return api.settings.edit({
settings: [{
key: 'notifications',
value: allNotifications
}]
}, internalContext).return();
}
}
};