mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-23 22:11:09 +03:00
Merge pull request #1627 from sebgie/issue#755
remove ghost.settings and ghost.notifications
This commit is contained in:
commit
7a46c36045
112
core/ghost.js
112
core/ghost.js
@ -11,6 +11,7 @@ var config = require('./server/config'),
|
||||
models = require('./server/models'),
|
||||
permissions = require('./server/permissions'),
|
||||
uuid = require('node-uuid'),
|
||||
api = require('./server/api'),
|
||||
|
||||
// Variables
|
||||
Ghost,
|
||||
@ -27,39 +28,36 @@ Ghost = function () {
|
||||
if (!instance) {
|
||||
instance = this;
|
||||
|
||||
// Holds the persistent notifications
|
||||
instance.notifications = [];
|
||||
instance.globals = {};
|
||||
|
||||
// Holds the dbhash (mainly used for cookie secret)
|
||||
instance.dbHash = undefined;
|
||||
|
||||
_.extend(instance, {
|
||||
// there's no management here to be sure this has loaded
|
||||
settings: function (key) {
|
||||
if (key) {
|
||||
return instance.settingsCache[key].value;
|
||||
}
|
||||
return instance.settingsCache;
|
||||
},
|
||||
dataProvider: models,
|
||||
blogGlobals: function () {
|
||||
var localPath = url.parse(config().url).path;
|
||||
|
||||
// Remove trailing slash
|
||||
if (localPath !== '/') {
|
||||
localPath = localPath.replace(/\/$/, '');
|
||||
}
|
||||
|
||||
/* this is a bit of a hack until we have a better way to combine settings and config
|
||||
* this data is what becomes globally available to themes */
|
||||
return {
|
||||
url: config().url.replace(/\/$/, ''),
|
||||
path: localPath,
|
||||
title: instance.settings('title'),
|
||||
description: instance.settings('description'),
|
||||
logo: instance.settings('logo'),
|
||||
cover: instance.settings('cover')
|
||||
};
|
||||
return instance.globals;
|
||||
},
|
||||
getGlobals: function () {
|
||||
return when.all([
|
||||
api.settings.read('title'),
|
||||
api.settings.read('description'),
|
||||
api.settings.read('logo'),
|
||||
api.settings.read('cover')
|
||||
]).then(function (globals) {
|
||||
|
||||
instance.globals.path = config.paths().path;
|
||||
|
||||
instance.globals.url = config().url;
|
||||
instance.globals.title = globals[0].value;
|
||||
instance.globals.description = globals[1].value;
|
||||
instance.globals.logo = globals[2] ? globals[2].value : '';
|
||||
instance.globals.cover = globals[3] ? globals[3].value : '';
|
||||
return;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -82,13 +80,12 @@ Ghost.prototype.init = function () {
|
||||
'See <a href="http://docs.ghost.org/">http://docs.ghost.org</a> for instructions.'
|
||||
];
|
||||
|
||||
self.notifications.push({
|
||||
return api.notifications.add({
|
||||
type: 'info',
|
||||
message: firstRunMessage.join(' '),
|
||||
status: 'persistent',
|
||||
id: 'ghost-first-run'
|
||||
});
|
||||
return when.resolve();
|
||||
}
|
||||
|
||||
function initDbHashAndFirstRun() {
|
||||
@ -112,16 +109,17 @@ Ghost.prototype.init = function () {
|
||||
// Initialise the models
|
||||
self.dataProvider.init(),
|
||||
// Calculate paths
|
||||
config.paths.updatePaths()
|
||||
config.paths.updatePaths(config().url)
|
||||
).then(function () {
|
||||
// Populate any missing default settings
|
||||
return models.Settings.populateDefaults();
|
||||
}).then(function () {
|
||||
// Initialize the settings cache
|
||||
return self.updateSettingsCache();
|
||||
return api.init();
|
||||
}).then(function () {
|
||||
|
||||
return self.getGlobals();
|
||||
}).then(function () {
|
||||
// Update path to activeTheme
|
||||
config.paths.setActiveTheme(self);
|
||||
return when.join(
|
||||
// Check for or initialise a dbHash.
|
||||
initDbHashAndFirstRun(),
|
||||
@ -131,60 +129,4 @@ Ghost.prototype.init = function () {
|
||||
}).otherwise(errors.logAndThrowError);
|
||||
};
|
||||
|
||||
// Maintain the internal cache of the settings object
|
||||
Ghost.prototype.updateSettingsCache = function (settings) {
|
||||
var self = this;
|
||||
|
||||
settings = settings || {};
|
||||
|
||||
if (!_.isEmpty(settings)) {
|
||||
_.map(settings, function (setting, key) {
|
||||
self.settingsCache[key].value = setting.value;
|
||||
});
|
||||
} else {
|
||||
// TODO: this should use api.browse
|
||||
return when(models.Settings.findAll()).then(function (result) {
|
||||
return when(self.readSettingsResult(result)).then(function (s) {
|
||||
self.settingsCache = s;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Ghost.prototype.readSettingsResult = function (result) {
|
||||
var settings = {};
|
||||
return when(_.map(result.models, function (member) {
|
||||
if (!settings.hasOwnProperty(member.attributes.key)) {
|
||||
var val = {};
|
||||
val.value = member.attributes.value;
|
||||
val.type = member.attributes.type;
|
||||
settings[member.attributes.key] = val;
|
||||
}
|
||||
})).then(function () {
|
||||
return when(config.paths().availableThemes).then(function (themes) {
|
||||
var themeKeys = Object.keys(themes),
|
||||
res = [],
|
||||
i,
|
||||
item;
|
||||
for (i = 0; i < themeKeys.length; i += 1) {
|
||||
//do not include hidden files
|
||||
if (themeKeys[i].indexOf('.') !== 0) {
|
||||
item = {};
|
||||
item.name = themeKeys[i];
|
||||
//data about files currently not used
|
||||
//item.details = themes[themeKeys[i]];
|
||||
if (themeKeys[i] === settings.activeTheme.value) {
|
||||
item.active = true;
|
||||
}
|
||||
res.push(item);
|
||||
}
|
||||
}
|
||||
settings.availableThemes = {};
|
||||
settings.availableThemes.value = res;
|
||||
settings.availableThemes.type = 'theme';
|
||||
return settings;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Ghost;
|
||||
|
@ -1,5 +1,4 @@
|
||||
var Ghost = require('../../ghost'),
|
||||
dataExport = require('../data/export'),
|
||||
var dataExport = require('../data/export'),
|
||||
dataImport = require('../data/import'),
|
||||
api = require('../api'),
|
||||
fs = require('fs-extra'),
|
||||
@ -8,8 +7,8 @@ var Ghost = require('../../ghost'),
|
||||
nodefn = require('when/node/function'),
|
||||
_ = require('underscore'),
|
||||
schema = require('../data/schema'),
|
||||
config = require('../config'),
|
||||
|
||||
ghost = new Ghost(),
|
||||
db;
|
||||
|
||||
db = {
|
||||
@ -27,15 +26,16 @@ db = {
|
||||
res.download(exportedFilePath, 'GhostData.json');
|
||||
}).otherwise(function (error) {
|
||||
// Notify of an error if it occurs
|
||||
var notification = {
|
||||
type: 'error',
|
||||
message: error.message || error,
|
||||
status: 'persistent',
|
||||
id: 'per-' + (ghost.notifications.length + 1)
|
||||
};
|
||||
|
||||
return api.notifications.add(notification).then(function () {
|
||||
res.redirect('/ghost/debug/');
|
||||
return api.notification.browse().then(function (notifications) {
|
||||
var notification = {
|
||||
type: 'error',
|
||||
message: error.message || error,
|
||||
status: 'persistent',
|
||||
id: 'per-' + (notifications.length + 1)
|
||||
};
|
||||
return api.notifications.add(notification).then(function () {
|
||||
res.redirect(config.paths().webroot + '/ghost/debug/');
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
@ -51,15 +51,16 @@ db = {
|
||||
* - If the size is 0
|
||||
* - If the name doesn't have json in it
|
||||
*/
|
||||
notification = {
|
||||
type: 'error',
|
||||
message: "Must select a .json file to import",
|
||||
status: 'persistent',
|
||||
id: 'per-' + (ghost.notifications.length + 1)
|
||||
};
|
||||
|
||||
return api.notifications.add(notification).then(function () {
|
||||
res.redirect('/ghost/debug/');
|
||||
return api.notification.browse().then(function (notifications) {
|
||||
notification = {
|
||||
type: 'error',
|
||||
message: "Must select a .json file to import",
|
||||
status: 'persistent',
|
||||
id: 'per-' + (notifications.length + 1)
|
||||
};
|
||||
return api.notifications.add(notification).then(function () {
|
||||
res.redirect(config.paths().webroot + '/ghost/debug/');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -125,32 +126,35 @@ db = {
|
||||
});
|
||||
})
|
||||
.then(function importSuccess() {
|
||||
notification = {
|
||||
type: 'success',
|
||||
message: "Data imported. Log in with the user details you imported",
|
||||
status: 'persistent',
|
||||
id: 'per-' + (ghost.notifications.length + 1)
|
||||
};
|
||||
return api.notification.browse().then(function (notifications) {
|
||||
notification = {
|
||||
type: 'success',
|
||||
message: "Data imported. Log in with the user details you imported",
|
||||
status: 'persistent',
|
||||
id: 'per-' + (notifications.length + 1)
|
||||
};
|
||||
|
||||
return api.notifications.add(notification).then(function () {
|
||||
req.session.destroy();
|
||||
res.set({
|
||||
"X-Cache-Invalidate": "/*"
|
||||
return api.notifications.add(notification).then(function () {
|
||||
req.session.destroy();
|
||||
res.set({
|
||||
"X-Cache-Invalidate": "/*"
|
||||
});
|
||||
res.redirect(config.paths().webroot + '/ghost/signin/');
|
||||
});
|
||||
res.redirect('/ghost/signin/');
|
||||
});
|
||||
|
||||
}, function importFailure(error) {
|
||||
// Notify of an error if it occurs
|
||||
notification = {
|
||||
type: 'error',
|
||||
message: error.message || error,
|
||||
status: 'persistent',
|
||||
id: 'per-' + (ghost.notifications.length + 1)
|
||||
};
|
||||
return api.notification.browse().then(function (notifications) {
|
||||
// Notify of an error if it occurs
|
||||
notification = {
|
||||
type: 'error',
|
||||
message: error.message || error,
|
||||
status: 'persistent',
|
||||
id: 'per-' + (notifications.length + 1)
|
||||
};
|
||||
|
||||
return api.notifications.add(notification).then(function () {
|
||||
res.redirect('/ghost/debug/');
|
||||
return api.notifications.add(notification).then(function () {
|
||||
res.redirect(config.paths().webroot + '/ghost/debug/');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1,397 +1,19 @@
|
||||
// # Ghost Data API
|
||||
// Provides access to the data model
|
||||
|
||||
var Ghost = require('../../ghost'),
|
||||
_ = require('underscore'),
|
||||
when = require('when'),
|
||||
errors = require('../errorHandling'),
|
||||
permissions = require('../permissions'),
|
||||
db = require('./db'),
|
||||
canThis = permissions.canThis,
|
||||
|
||||
ghost = new Ghost(),
|
||||
dataProvider = ghost.dataProvider,
|
||||
posts,
|
||||
users,
|
||||
tags,
|
||||
notifications,
|
||||
settings,
|
||||
var _ = require('underscore'),
|
||||
when = require('when'),
|
||||
errors = require('../errorHandling'),
|
||||
db = require('./db'),
|
||||
settings = require('./settings'),
|
||||
notifications = require('./notifications'),
|
||||
dataProvider = require('../models'),
|
||||
config = require('../config'),
|
||||
posts = require('./posts'),
|
||||
users = require('./users'),
|
||||
tags = require('./tags'),
|
||||
requestHandler,
|
||||
settingsObject,
|
||||
settingsCollection,
|
||||
settingsFilter,
|
||||
filteredUserAttributes = ['password', 'created_by', 'updated_by', 'last_login'],
|
||||
ONE_DAY = 86400000;
|
||||
|
||||
// ## Posts
|
||||
posts = {
|
||||
// #### Browse
|
||||
|
||||
// **takes:** filter / pagination parameters
|
||||
browse: function browse(options) {
|
||||
|
||||
// **returns:** a promise for a page of posts in a json object
|
||||
//return dataProvider.Post.findPage(options);
|
||||
return dataProvider.Post.findPage(options).then(function (result) {
|
||||
var i = 0,
|
||||
omitted = result;
|
||||
|
||||
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
|
||||
|
||||
return dataProvider.Post.findOne(args).then(function (result) {
|
||||
var omitted;
|
||||
|
||||
if (result) {
|
||||
omitted = result.toJSON();
|
||||
omitted.author = _.omit(omitted.author, filteredUserAttributes);
|
||||
omitted.user = _.omit(omitted.user, filteredUserAttributes);
|
||||
return omitted;
|
||||
}
|
||||
return when.reject({errorCode: 404, message: 'Post not found'});
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
// #### 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
|
||||
if (!this.user) {
|
||||
return when.reject({errorCode: 403, message: 'You do not have permission to edit this post.'});
|
||||
}
|
||||
var self = this;
|
||||
return canThis(self.user).edit.post(postData.id).then(function () {
|
||||
return dataProvider.Post.edit(postData).then(function (result) {
|
||||
if (result) {
|
||||
var omitted = result.toJSON();
|
||||
omitted.author = _.omit(omitted.author, filteredUserAttributes);
|
||||
omitted.user = _.omit(omitted.user, filteredUserAttributes);
|
||||
return omitted;
|
||||
}
|
||||
return when.reject({errorCode: 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({errorCode: 404, message: 'Post not found'});
|
||||
}
|
||||
return when.reject({message: error.message});
|
||||
});
|
||||
});
|
||||
}, function () {
|
||||
return when.reject({errorCode: 403, message: 'You do not have permission to edit this post.'});
|
||||
});
|
||||
},
|
||||
|
||||
// #### Add
|
||||
|
||||
// **takes:** a json object representing a post,
|
||||
add: function add(postData) {
|
||||
// **returns:** a promise for the resulting post in a json object
|
||||
if (!this.user) {
|
||||
return when.reject({errorCode: 403, message: 'You do not have permission to add posts.'});
|
||||
}
|
||||
|
||||
return canThis(this.user).create.post().then(function () {
|
||||
return dataProvider.Post.add(postData);
|
||||
}, function () {
|
||||
return when.reject({errorCode: 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
|
||||
if (!this.user) {
|
||||
return when.reject({errorCode: 403, message: 'You do not have permission to remove posts.'});
|
||||
}
|
||||
|
||||
return canThis(this.user).remove.post(args.id).then(function () {
|
||||
return when(posts.read({id : args.id, status: 'all'})).then(function (result) {
|
||||
return dataProvider.Post.destroy(args.id).then(function () {
|
||||
var deletedObj = {};
|
||||
deletedObj.id = result.id;
|
||||
deletedObj.slug = result.slug;
|
||||
return deletedObj;
|
||||
});
|
||||
});
|
||||
}, function () {
|
||||
return when.reject({errorCode: 403, message: 'You do not have permission to remove posts.'});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// ## Users
|
||||
users = {
|
||||
// #### Browse
|
||||
|
||||
// **takes:** options object
|
||||
browse: function browse(options) {
|
||||
// **returns:** a promise for a collection of users in a json object
|
||||
|
||||
return dataProvider.User.browse(options).then(function (result) {
|
||||
var i = 0,
|
||||
omitted = {};
|
||||
|
||||
if (result) {
|
||||
omitted = result.toJSON();
|
||||
}
|
||||
|
||||
for (i = 0; i < omitted.length; i = i + 1) {
|
||||
omitted[i] = _.omit(omitted[i], filteredUserAttributes);
|
||||
}
|
||||
|
||||
return omitted;
|
||||
});
|
||||
},
|
||||
|
||||
// #### Read
|
||||
|
||||
// **takes:** an identifier (id or slug?)
|
||||
read: function read(args) {
|
||||
// **returns:** a promise for a single user in a json object
|
||||
if (args.id === 'me') {
|
||||
args = {id: this.user};
|
||||
}
|
||||
|
||||
return dataProvider.User.read(args).then(function (result) {
|
||||
if (result) {
|
||||
var omitted = _.omit(result.toJSON(), filteredUserAttributes);
|
||||
return omitted;
|
||||
}
|
||||
|
||||
return when.reject({errorCode: 404, message: 'User not found'});
|
||||
});
|
||||
},
|
||||
|
||||
// #### Edit
|
||||
|
||||
// **takes:** a json object representing a user
|
||||
edit: function edit(userData) {
|
||||
// **returns:** a promise for the resulting user in a json object
|
||||
userData.id = this.user;
|
||||
return dataProvider.User.edit(userData).then(function (result) {
|
||||
if (result) {
|
||||
var omitted = _.omit(result.toJSON(), filteredUserAttributes);
|
||||
return omitted;
|
||||
}
|
||||
return when.reject({errorCode: 404, message: 'User not found'});
|
||||
});
|
||||
},
|
||||
|
||||
// #### Add
|
||||
|
||||
// **takes:** a json object representing a user
|
||||
add: function add(userData) {
|
||||
|
||||
// **returns:** a promise for the resulting user in a json object
|
||||
return dataProvider.User.add(userData);
|
||||
},
|
||||
|
||||
// #### Check
|
||||
// Checks a password matches the given email address
|
||||
|
||||
// **takes:** a json object representing a user
|
||||
check: function check(userData) {
|
||||
// **returns:** on success, returns a promise for the resulting user in a json object
|
||||
return dataProvider.User.check(userData);
|
||||
},
|
||||
|
||||
// #### Change Password
|
||||
|
||||
// **takes:** a json object representing a user
|
||||
changePassword: function changePassword(userData) {
|
||||
// **returns:** on success, returns a promise for the resulting user in a json object
|
||||
return dataProvider.User.changePassword(userData);
|
||||
},
|
||||
|
||||
generateResetToken: function generateResetToken(email) {
|
||||
// TODO: Do we want to be able to pass this in?
|
||||
var expires = Date.now() + ONE_DAY;
|
||||
|
||||
return dataProvider.User.generateResetToken(email, expires, ghost.dbHash);
|
||||
},
|
||||
|
||||
validateToken: function validateToken(token) {
|
||||
return dataProvider.User.validateToken(token, ghost.dbHash);
|
||||
},
|
||||
|
||||
resetPassword: function resetPassword(token, newPassword, ne2Password) {
|
||||
return dataProvider.User.resetPassword(token, newPassword, ne2Password, ghost.dbHash);
|
||||
}
|
||||
};
|
||||
|
||||
tags = {
|
||||
// #### All
|
||||
|
||||
// **takes:** Nothing yet
|
||||
all: function browse() {
|
||||
// **returns:** a promise for all tags which have previously been used in a json object
|
||||
return dataProvider.Tag.findAll();
|
||||
}
|
||||
};
|
||||
|
||||
// ## Notifications
|
||||
notifications = {
|
||||
// #### Destroy
|
||||
|
||||
// **takes:** an identifier (id)
|
||||
destroy: function destroy(i) {
|
||||
ghost.notifications = _.reject(ghost.notifications, function (element) {
|
||||
return element.id === i.id;
|
||||
});
|
||||
// **returns:** a promise for remaining notifications as a json object
|
||||
return when(ghost.notifications);
|
||||
},
|
||||
|
||||
// #### Add
|
||||
|
||||
// **takes:** a notification object of the form
|
||||
// ```
|
||||
// msg = {
|
||||
// type: 'error', // this can be 'error', 'success', 'warn' and 'info'
|
||||
// message: 'This is an error', // A string. Should fit in one line.
|
||||
// status: 'persistent', // or 'passive'
|
||||
// id: 'auniqueid' // A unique ID
|
||||
// };
|
||||
// ```
|
||||
add: function add(notification) {
|
||||
// **returns:** a promise for all notifications as a json object
|
||||
return when(ghost.notifications.push(notification));
|
||||
}
|
||||
};
|
||||
|
||||
// ## Settings
|
||||
|
||||
// ### Helpers
|
||||
// Turn a settings collection into a single object/hashmap
|
||||
settingsObject = function (settings) {
|
||||
if (_.isObject(settings)) {
|
||||
return _.reduce(settings, function (res, item, key) {
|
||||
if (_.isArray(item)) {
|
||||
res[key] = item;
|
||||
} else {
|
||||
res[key] = item.value;
|
||||
}
|
||||
return res;
|
||||
}, {});
|
||||
}
|
||||
return (settings.toJSON ? settings.toJSON() : settings).reduce(function (res, item) {
|
||||
if (item.toJSON) { item = item.toJSON(); }
|
||||
if (item.key) { res[item.key] = item.value; }
|
||||
return res;
|
||||
}, {});
|
||||
};
|
||||
// Turn an object into a collection
|
||||
settingsCollection = function (settings) {
|
||||
return _.map(settings, function (value, key) {
|
||||
return { key: key, value: value };
|
||||
});
|
||||
};
|
||||
|
||||
// Filters an object based on a given filter object
|
||||
settingsFilter = function (settings, filter) {
|
||||
return _.object(_.filter(_.pairs(settings), function (setting) {
|
||||
if (filter) {
|
||||
return _.some(filter.split(','), function (f) {
|
||||
return setting[1].type === f;
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
};
|
||||
|
||||
settings = {
|
||||
// #### Browse
|
||||
|
||||
// **takes:** options object
|
||||
browse: function browse(options) {
|
||||
// **returns:** a promise for a settings json object
|
||||
if (ghost.settings()) {
|
||||
return when(ghost.settings()).then(function (settings) {
|
||||
//TODO: omit where type==core
|
||||
return settingsObject(settingsFilter(settings, options.type));
|
||||
}, errors.logAndThrowError);
|
||||
}
|
||||
},
|
||||
|
||||
// #### Read
|
||||
|
||||
// **takes:** either a json object containing a key, or a single key string
|
||||
read: function read(options) {
|
||||
if (_.isString(options)) {
|
||||
options = { key: options };
|
||||
}
|
||||
|
||||
if (ghost.settings()) {
|
||||
return when(ghost.settings()[options.key]).then(function (setting) {
|
||||
if (!setting) {
|
||||
return when.reject({errorCode: 404, message: 'Unable to find setting: ' + options.key});
|
||||
}
|
||||
var res = {};
|
||||
res.key = options.key;
|
||||
res.value = setting.value;
|
||||
return res;
|
||||
}, errors.logAndThrowError);
|
||||
}
|
||||
},
|
||||
|
||||
// #### Edit
|
||||
|
||||
// **takes:** either a json object representing a collection of settings, or a key and value pair
|
||||
edit: function edit(key, value) {
|
||||
// Check for passing a collection of settings first
|
||||
if (_.isObject(key)) {
|
||||
//clean data
|
||||
var type = key.type;
|
||||
delete key.type;
|
||||
delete key.availableThemes;
|
||||
|
||||
key = settingsCollection(key);
|
||||
return dataProvider.Settings.edit(key).then(function (result) {
|
||||
result.models = result;
|
||||
return when(ghost.readSettingsResult(result)).then(function (settings) {
|
||||
ghost.updateSettingsCache(settings);
|
||||
return settingsObject(settingsFilter(ghost.settings(), type));
|
||||
});
|
||||
}).otherwise(function (error) {
|
||||
return dataProvider.Settings.read(key.key).then(function (result) {
|
||||
if (!result) {
|
||||
return when.reject({errorCode: 404, message: 'Unable to find setting: ' + key});
|
||||
}
|
||||
return when.reject({message: error.message});
|
||||
});
|
||||
});
|
||||
}
|
||||
return dataProvider.Settings.read(key).then(function (setting) {
|
||||
if (!setting) {
|
||||
return when.reject({errorCode: 404, message: 'Unable to find setting: ' + key});
|
||||
}
|
||||
if (!_.isString(value)) {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
setting.set('value', value);
|
||||
return dataProvider.Settings.edit(setting).then(function (result) {
|
||||
ghost.settings()[_.first(result).attributes.key].value = _.first(result).attributes.value;
|
||||
return settingsObject(ghost.settings());
|
||||
}, errors.logAndThrowError);
|
||||
});
|
||||
}
|
||||
};
|
||||
init;
|
||||
|
||||
// ## Request Handlers
|
||||
|
||||
@ -429,41 +51,49 @@ requestHandler = function (apiMethod) {
|
||||
apiContext = {
|
||||
user: req.session && req.session.user
|
||||
},
|
||||
root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
|
||||
postRouteIndex,
|
||||
i;
|
||||
|
||||
// If permalinks have changed, find old post route
|
||||
if (req.body.permalinks && req.body.permalinks !== ghost.settings('permalinks')) {
|
||||
for (i = 0; i < req.app.routes.get.length; i += 1) {
|
||||
if (req.app.routes.get[i].path === root + ghost.settings('permalinks')) {
|
||||
postRouteIndex = i;
|
||||
break;
|
||||
settings.read('permalinks').then(function (permalinks) {
|
||||
// If permalinks have changed, find old post route
|
||||
if (req.body.permalinks && req.body.permalinks !== permalinks) {
|
||||
for (i = 0; i < req.app.routes.get.length; i += 1) {
|
||||
if (req.app.routes.get[i].path === config.paths().webroot + permalinks) {
|
||||
postRouteIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return apiMethod.call(apiContext, options).then(function (result) {
|
||||
// Reload post route
|
||||
if (postRouteIndex) {
|
||||
req.app.get(ghost.settings('permalinks'), req.app.routes.get.splice(postRouteIndex, 1)[0].callbacks);
|
||||
}
|
||||
return apiMethod.call(apiContext, options).then(function (result) {
|
||||
// Reload post route
|
||||
if (postRouteIndex) {
|
||||
req.app.get(permalinks, req.app.routes.get.splice(postRouteIndex, 1)[0].callbacks);
|
||||
}
|
||||
|
||||
invalidateCache(req, res, result);
|
||||
res.json(result || {});
|
||||
}, function (error) {
|
||||
var errorCode = error.errorCode || 500,
|
||||
errorMsg = {error: _.isString(error) ? error : (_.isObject(error) ? error.message : 'Unknown API Error')};
|
||||
res.json(errorCode, errorMsg);
|
||||
invalidateCache(req, res, result);
|
||||
res.json(result || {});
|
||||
}, function (error) {
|
||||
var errorCode = error.errorCode || 500,
|
||||
errorMsg = {error: _.isString(error) ? error : (_.isObject(error) ? error.message : 'Unknown API Error')};
|
||||
res.json(errorCode, errorMsg);
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
init = function () {
|
||||
return settings.updateSettingsCache();
|
||||
};
|
||||
|
||||
// Public API
|
||||
module.exports.posts = posts;
|
||||
module.exports.users = users;
|
||||
module.exports.tags = tags;
|
||||
module.exports.notifications = notifications;
|
||||
module.exports.settings = settings;
|
||||
module.exports.db = db;
|
||||
module.exports.requestHandler = requestHandler;
|
||||
module.exports = {
|
||||
posts: posts,
|
||||
users: users,
|
||||
tags: tags,
|
||||
notifications: notifications,
|
||||
settings: settings,
|
||||
db: db,
|
||||
requestHandler: requestHandler,
|
||||
init: init
|
||||
};
|
||||
|
47
core/server/api/notifications.js
Normal file
47
core/server/api/notifications.js
Normal file
@ -0,0 +1,47 @@
|
||||
var when = require('when'),
|
||||
_ = require('underscore'),
|
||||
// Holds the persistent notifications
|
||||
notificationsStore = [],
|
||||
notifications;
|
||||
|
||||
// ## Notifications
|
||||
notifications = {
|
||||
|
||||
browse: function browse() {
|
||||
return when(notificationsStore);
|
||||
},
|
||||
|
||||
// #### Destroy
|
||||
|
||||
// **takes:** an identifier object ({id: id})
|
||||
destroy: function destroy(i) {
|
||||
notificationsStore = _.reject(notificationsStore, function (element) {
|
||||
return element.id === i.id;
|
||||
});
|
||||
// **returns:** a promise for remaining notifications as a json object
|
||||
return when(notificationsStore);
|
||||
},
|
||||
|
||||
destroyAll: function destroyAll() {
|
||||
notificationsStore = [];
|
||||
return when(notificationsStore);
|
||||
},
|
||||
|
||||
// #### Add
|
||||
|
||||
// **takes:** a notification object of the form
|
||||
// ```
|
||||
// msg = {
|
||||
// type: 'error', // this can be 'error', 'success', 'warn' and 'info'
|
||||
// message: 'This is an error', // A string. Should fit in one line.
|
||||
// status: 'persistent', // or 'passive'
|
||||
// id: 'auniqueid' // A unique ID
|
||||
// };
|
||||
// ```
|
||||
add: function add(notification) {
|
||||
// **returns:** a promise for all notifications as a json object
|
||||
return when(notificationsStore.push(notification));
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = notifications;
|
121
core/server/api/posts.js
Normal file
121
core/server/api/posts.js
Normal file
@ -0,0 +1,121 @@
|
||||
var when = require('when'),
|
||||
_ = require('underscore'),
|
||||
dataProvider = require('../models'),
|
||||
permissions = require('../permissions'),
|
||||
canThis = permissions.canThis,
|
||||
filteredUserAttributes = require('./users').filteredAttributes,
|
||||
posts;
|
||||
|
||||
// ## Posts
|
||||
posts = {
|
||||
// #### Browse
|
||||
|
||||
// **takes:** filter / pagination parameters
|
||||
browse: function browse(options) {
|
||||
|
||||
// **returns:** a promise for a page of posts in a json object
|
||||
//return dataProvider.Post.findPage(options);
|
||||
return dataProvider.Post.findPage(options).then(function (result) {
|
||||
var i = 0,
|
||||
omitted = result;
|
||||
|
||||
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
|
||||
|
||||
return dataProvider.Post.findOne(args).then(function (result) {
|
||||
var omitted;
|
||||
|
||||
if (result) {
|
||||
omitted = result.toJSON();
|
||||
omitted.author = _.omit(omitted.author, filteredUserAttributes);
|
||||
omitted.user = _.omit(omitted.user, filteredUserAttributes);
|
||||
return omitted;
|
||||
}
|
||||
return when.reject({errorCode: 404, message: 'Post not found'});
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
// #### 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
|
||||
if (!this.user) {
|
||||
return when.reject({errorCode: 403, message: 'You do not have permission to edit this post.'});
|
||||
}
|
||||
var self = this;
|
||||
return canThis(self.user).edit.post(postData.id).then(function () {
|
||||
return dataProvider.Post.edit(postData).then(function (result) {
|
||||
if (result) {
|
||||
var omitted = result.toJSON();
|
||||
omitted.author = _.omit(omitted.author, filteredUserAttributes);
|
||||
omitted.user = _.omit(omitted.user, filteredUserAttributes);
|
||||
return omitted;
|
||||
}
|
||||
return when.reject({errorCode: 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({errorCode: 404, message: 'Post not found'});
|
||||
}
|
||||
return when.reject({message: error.message});
|
||||
});
|
||||
});
|
||||
}, function () {
|
||||
return when.reject({errorCode: 403, message: 'You do not have permission to edit this post.'});
|
||||
});
|
||||
},
|
||||
|
||||
// #### Add
|
||||
|
||||
// **takes:** a json object representing a post,
|
||||
add: function add(postData) {
|
||||
// **returns:** a promise for the resulting post in a json object
|
||||
if (!this.user) {
|
||||
return when.reject({errorCode: 403, message: 'You do not have permission to add posts.'});
|
||||
}
|
||||
|
||||
return canThis(this.user).create.post().then(function () {
|
||||
return dataProvider.Post.add(postData);
|
||||
}, function () {
|
||||
return when.reject({errorCode: 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
|
||||
if (!this.user) {
|
||||
return when.reject({errorCode: 403, message: 'You do not have permission to remove posts.'});
|
||||
}
|
||||
|
||||
return canThis(this.user).remove.post(args.id).then(function () {
|
||||
return when(posts.read({id : args.id, status: 'all'})).then(function (result) {
|
||||
return dataProvider.Post.destroy(args.id).then(function () {
|
||||
var deletedObj = {};
|
||||
deletedObj.id = result.id;
|
||||
deletedObj.slug = result.slug;
|
||||
return deletedObj;
|
||||
});
|
||||
});
|
||||
}, function () {
|
||||
return when.reject({errorCode: 403, message: 'You do not have permission to remove posts.'});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = posts;
|
185
core/server/api/settings.js
Normal file
185
core/server/api/settings.js
Normal file
@ -0,0 +1,185 @@
|
||||
var _ = require('underscore'),
|
||||
dataProvider = require('../models'),
|
||||
when = require('when'),
|
||||
errors = require('../errorHandling'),
|
||||
config = require('../config'),
|
||||
settings,
|
||||
settingsObject,
|
||||
settingsCollection,
|
||||
settingsFilter,
|
||||
updateSettingsCache,
|
||||
readSettingsResult,
|
||||
// Holds cached settings
|
||||
settingsCache = {};
|
||||
|
||||
// ### Helpers
|
||||
// Turn a settings collection into a single object/hashmap
|
||||
settingsObject = function (settings) {
|
||||
if (_.isObject(settings)) {
|
||||
return _.reduce(settings, function (res, item, key) {
|
||||
if (_.isArray(item)) {
|
||||
res[key] = item;
|
||||
} else {
|
||||
res[key] = item.value;
|
||||
}
|
||||
return res;
|
||||
}, {});
|
||||
}
|
||||
return (settings.toJSON ? settings.toJSON() : settings).reduce(function (res, item) {
|
||||
if (item.toJSON) { item = item.toJSON(); }
|
||||
if (item.key) { res[item.key] = item.value; }
|
||||
return res;
|
||||
}, {});
|
||||
};
|
||||
// Turn an object into a collection
|
||||
settingsCollection = function (settings) {
|
||||
return _.map(settings, function (value, key) {
|
||||
return { key: key, value: value };
|
||||
});
|
||||
};
|
||||
|
||||
// Filters an object based on a given filter object
|
||||
settingsFilter = function (settings, filter) {
|
||||
return _.object(_.filter(_.pairs(settings), function (setting) {
|
||||
if (filter) {
|
||||
return _.some(filter.split(','), function (f) {
|
||||
return setting[1].type === f;
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
};
|
||||
|
||||
// Maintain the internal cache of the settings object
|
||||
updateSettingsCache = function (settings) {
|
||||
settings = settings || {};
|
||||
|
||||
if (!_.isEmpty(settings)) {
|
||||
_.map(settings, function (setting, key) {
|
||||
settingsCache[key].value = setting.value;
|
||||
});
|
||||
} else {
|
||||
return when(dataProvider.Settings.findAll()).then(function (result) {
|
||||
return when(readSettingsResult(result)).then(function (s) {
|
||||
settingsCache = s;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
readSettingsResult = function (result) {
|
||||
var settings = {};
|
||||
return when(_.map(result.models, function (member) {
|
||||
if (!settings.hasOwnProperty(member.attributes.key)) {
|
||||
var val = {};
|
||||
val.value = member.attributes.value;
|
||||
val.type = member.attributes.type;
|
||||
settings[member.attributes.key] = val;
|
||||
}
|
||||
})).then(function () {
|
||||
return when(config.paths().availableThemes).then(function (themes) {
|
||||
var themeKeys = Object.keys(themes),
|
||||
res = [],
|
||||
i,
|
||||
item;
|
||||
for (i = 0; i < themeKeys.length; i += 1) {
|
||||
//do not include hidden files
|
||||
if (themeKeys[i].indexOf('.') !== 0) {
|
||||
item = {};
|
||||
item.name = themeKeys[i];
|
||||
//data about files currently not used
|
||||
//item.details = themes[themeKeys[i]];
|
||||
if (themeKeys[i] === settings.activeTheme.value) {
|
||||
item.active = true;
|
||||
}
|
||||
res.push(item);
|
||||
}
|
||||
}
|
||||
settings.availableThemes = {};
|
||||
settings.availableThemes.value = res;
|
||||
settings.availableThemes.type = 'theme';
|
||||
return settings;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
settings = {
|
||||
// #### Browse
|
||||
|
||||
// **takes:** options object
|
||||
browse: function browse(options) {
|
||||
// **returns:** a promise for a settings json object
|
||||
if (settingsCache) {
|
||||
return when(settingsCache).then(function (settings) {
|
||||
//TODO: omit where type==core
|
||||
return settingsObject(settingsFilter(settings, options.type));
|
||||
}, errors.logAndThrowError);
|
||||
}
|
||||
},
|
||||
|
||||
// #### Read
|
||||
|
||||
// **takes:** either a json object containing a key, or a single key string
|
||||
read: function read(options) {
|
||||
if (_.isString(options)) {
|
||||
options = { key: options };
|
||||
}
|
||||
|
||||
if (settingsCache) {
|
||||
return when(settingsCache[options.key]).then(function (setting) {
|
||||
if (!setting) {
|
||||
return when.reject({errorCode: 404, message: 'Unable to find setting: ' + options.key});
|
||||
}
|
||||
var res = {};
|
||||
res.key = options.key;
|
||||
res.value = setting.value;
|
||||
return res;
|
||||
}, errors.logAndThrowError);
|
||||
}
|
||||
},
|
||||
|
||||
// #### Edit
|
||||
|
||||
// **takes:** either a json object representing a collection of settings, or a key and value pair
|
||||
edit: function edit(key, value) {
|
||||
// Check for passing a collection of settings first
|
||||
if (_.isObject(key)) {
|
||||
//clean data
|
||||
var type = key.type;
|
||||
delete key.type;
|
||||
delete key.availableThemes;
|
||||
|
||||
key = settingsCollection(key);
|
||||
return dataProvider.Settings.edit(key).then(function (result) {
|
||||
result.models = result;
|
||||
return when(readSettingsResult(result)).then(function (settings) {
|
||||
updateSettingsCache(settings);
|
||||
return settingsObject(settingsFilter(settingsCache, type));
|
||||
});
|
||||
}).otherwise(function (error) {
|
||||
return dataProvider.Settings.read(key.key).then(function (result) {
|
||||
if (!result) {
|
||||
return when.reject({errorCode: 404, message: 'Unable to find setting: ' + key});
|
||||
}
|
||||
return when.reject({message: error.message});
|
||||
});
|
||||
});
|
||||
}
|
||||
return dataProvider.Settings.read(key).then(function (setting) {
|
||||
if (!setting) {
|
||||
return when.reject({errorCode: 404, message: 'Unable to find setting: ' + key});
|
||||
}
|
||||
if (!_.isString(value)) {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
setting.set('value', value);
|
||||
return dataProvider.Settings.edit(setting).then(function (result) {
|
||||
settingsCache[_.first(result).attributes.key].value = _.first(result).attributes.value;
|
||||
return settingsObject(settingsCache);
|
||||
}, errors.logAndThrowError);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = settings;
|
||||
module.exports.updateSettingsCache = updateSettingsCache;
|
15
core/server/api/tags.js
Normal file
15
core/server/api/tags.js
Normal file
@ -0,0 +1,15 @@
|
||||
var dataProvider = require('../models'),
|
||||
tags;
|
||||
|
||||
|
||||
tags = {
|
||||
// #### All
|
||||
|
||||
// **takes:** Nothing yet
|
||||
all: function browse() {
|
||||
// **returns:** a promise for all tags which have previously been used in a json object
|
||||
return dataProvider.Tag.findAll();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = tags;
|
115
core/server/api/users.js
Normal file
115
core/server/api/users.js
Normal file
@ -0,0 +1,115 @@
|
||||
var when = require('when'),
|
||||
_ = require('underscore'),
|
||||
dataProvider = require('../models'),
|
||||
settings = require('./settings'),
|
||||
ONE_DAY = 86400000,
|
||||
filteredAttributes = ['password', 'created_by', 'updated_by', 'last_login'],
|
||||
users;
|
||||
|
||||
// ## Users
|
||||
users = {
|
||||
// #### Browse
|
||||
|
||||
// **takes:** options object
|
||||
browse: function browse(options) {
|
||||
// **returns:** a promise for a collection of users in a json object
|
||||
|
||||
return dataProvider.User.browse(options).then(function (result) {
|
||||
var i = 0,
|
||||
omitted = {};
|
||||
|
||||
if (result) {
|
||||
omitted = result.toJSON();
|
||||
}
|
||||
|
||||
for (i = 0; i < omitted.length; i = i + 1) {
|
||||
omitted[i] = _.omit(omitted[i], filteredAttributes);
|
||||
}
|
||||
|
||||
return omitted;
|
||||
});
|
||||
},
|
||||
|
||||
// #### Read
|
||||
|
||||
// **takes:** an identifier (id or slug?)
|
||||
read: function read(args) {
|
||||
// **returns:** a promise for a single user in a json object
|
||||
if (args.id === 'me') {
|
||||
args = {id: this.user};
|
||||
}
|
||||
|
||||
return dataProvider.User.read(args).then(function (result) {
|
||||
if (result) {
|
||||
var omitted = _.omit(result.toJSON(), filteredAttributes);
|
||||
return omitted;
|
||||
}
|
||||
|
||||
return when.reject({errorCode: 404, message: 'User not found'});
|
||||
});
|
||||
},
|
||||
|
||||
// #### Edit
|
||||
|
||||
// **takes:** a json object representing a user
|
||||
edit: function edit(userData) {
|
||||
// **returns:** a promise for the resulting user in a json object
|
||||
userData.id = this.user;
|
||||
return dataProvider.User.edit(userData).then(function (result) {
|
||||
if (result) {
|
||||
var omitted = _.omit(result.toJSON(), filteredAttributes);
|
||||
return omitted;
|
||||
}
|
||||
return when.reject({errorCode: 404, message: 'User not found'});
|
||||
});
|
||||
},
|
||||
|
||||
// #### Add
|
||||
|
||||
// **takes:** a json object representing a user
|
||||
add: function add(userData) {
|
||||
|
||||
// **returns:** a promise for the resulting user in a json object
|
||||
return dataProvider.User.add(userData);
|
||||
},
|
||||
|
||||
// #### Check
|
||||
// Checks a password matches the given email address
|
||||
|
||||
// **takes:** a json object representing a user
|
||||
check: function check(userData) {
|
||||
// **returns:** on success, returns a promise for the resulting user in a json object
|
||||
return dataProvider.User.check(userData);
|
||||
},
|
||||
|
||||
// #### Change Password
|
||||
|
||||
// **takes:** a json object representing a user
|
||||
changePassword: function changePassword(userData) {
|
||||
// **returns:** on success, returns a promise for the resulting user in a json object
|
||||
return dataProvider.User.changePassword(userData);
|
||||
},
|
||||
|
||||
generateResetToken: function generateResetToken(email) {
|
||||
// TODO: Do we want to be able to pass this in?
|
||||
var expires = Date.now() + ONE_DAY;
|
||||
return settings.read('dbHash').then(function (dbHash) {
|
||||
return dataProvider.User.generateResetToken(email, expires, dbHash);
|
||||
});
|
||||
},
|
||||
|
||||
validateToken: function validateToken(token) {
|
||||
return settings.read('dbHash').then(function (dbHash) {
|
||||
return dataProvider.User.validateToken(token, dbHash);
|
||||
});
|
||||
},
|
||||
|
||||
resetPassword: function resetPassword(token, newPassword, ne2Password) {
|
||||
return settings.read('dbHash').then(function (dbHash) {
|
||||
return dataProvider.User.resetPassword(token, newPassword, ne2Password, dbHash);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = users;
|
||||
module.exports.filteredAttributes = filteredAttributes;
|
@ -2,25 +2,28 @@
|
||||
|
||||
var path = require('path'),
|
||||
when = require('when'),
|
||||
url = require('url'),
|
||||
requireTree = require('../require-tree'),
|
||||
appRoot = path.resolve(__dirname, '../../../'),
|
||||
themePath = path.resolve(appRoot + '/content/themes'),
|
||||
pluginPath = path.resolve(appRoot + '/content/plugins'),
|
||||
themeDirectories = requireTree(themePath),
|
||||
pluginDirectories = requireTree(pluginPath),
|
||||
activeTheme = '',
|
||||
localPath = '',
|
||||
availableThemes,
|
||||
|
||||
availablePlugins;
|
||||
|
||||
|
||||
function getPaths() {
|
||||
return {
|
||||
'appRoot': appRoot,
|
||||
'path': localPath,
|
||||
'webroot': localPath === '/' ? '' : localPath,
|
||||
'config': path.join(appRoot, 'config.js'),
|
||||
'configExample': path.join(appRoot, 'config.example.js'),
|
||||
'themePath': themePath,
|
||||
'pluginPath': pluginPath,
|
||||
'activeTheme': path.join(themePath, activeTheme),
|
||||
'adminViews': path.join(appRoot, '/core/server/views/'),
|
||||
'helperTemplates': path.join(appRoot, '/core/server/helpers/tpl/'),
|
||||
'lang': path.join(appRoot, '/core/shared/lang/'),
|
||||
@ -29,8 +32,16 @@ function getPaths() {
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: remove configURL and give direct access to config object?
|
||||
// TODO: not called when executing tests
|
||||
function updatePaths(configURL) {
|
||||
localPath = url.parse(configURL).path;
|
||||
|
||||
// Remove trailing slash
|
||||
if (localPath !== '/') {
|
||||
localPath = localPath.replace(/\/$/, '');
|
||||
}
|
||||
|
||||
function updatePaths() {
|
||||
return when.all([themeDirectories, pluginDirectories]).then(function (paths) {
|
||||
availableThemes = paths[0];
|
||||
availablePlugins = paths[1];
|
||||
@ -38,14 +49,6 @@ function updatePaths() {
|
||||
});
|
||||
}
|
||||
|
||||
function setActiveTheme(ghost) {
|
||||
if (ghost && ghost.settingsCache) {
|
||||
activeTheme = ghost.settingsCache.activeTheme.value;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = getPaths;
|
||||
|
||||
module.exports.updatePaths = updatePaths;
|
||||
|
||||
module.exports.setActiveTheme = setActiveTheme;
|
@ -1,5 +1,4 @@
|
||||
var Ghost = require('../../ghost'),
|
||||
config = require('../config'),
|
||||
var config = require('../config'),
|
||||
_ = require('underscore'),
|
||||
path = require('path'),
|
||||
when = require('when'),
|
||||
@ -8,8 +7,6 @@ var Ghost = require('../../ghost'),
|
||||
errors = require('../errorHandling'),
|
||||
storage = require('../storage'),
|
||||
|
||||
ghost = new Ghost(),
|
||||
dataProvider = ghost.dataProvider,
|
||||
adminNavbar,
|
||||
adminControllers,
|
||||
loginSecurity = [];
|
||||
@ -74,8 +71,7 @@ adminControllers = {
|
||||
});
|
||||
},
|
||||
'auth': function (req, res) {
|
||||
var root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
|
||||
currentTime = process.hrtime()[0],
|
||||
var currentTime = process.hrtime()[0],
|
||||
denied = '';
|
||||
loginSecurity = _.filter(loginSecurity, function (ipTime) {
|
||||
return (ipTime.time + 2 > currentTime);
|
||||
@ -90,7 +86,7 @@ adminControllers = {
|
||||
req.session.regenerate(function (err) {
|
||||
if (!err) {
|
||||
req.session.user = user.id;
|
||||
var redirect = root + '/ghost/';
|
||||
var redirect = config.paths().webroot + '/ghost/';
|
||||
if (req.body.redirect) {
|
||||
redirect += decodeURIComponent(req.body.redirect);
|
||||
}
|
||||
@ -126,8 +122,7 @@ adminControllers = {
|
||||
});
|
||||
},
|
||||
'doRegister': function (req, res) {
|
||||
var root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
|
||||
name = req.body.name,
|
||||
var name = req.body.name,
|
||||
email = req.body.email,
|
||||
password = req.body.password;
|
||||
|
||||
@ -142,7 +137,7 @@ adminControllers = {
|
||||
if (req.session.user === undefined) {
|
||||
req.session.user = user.id;
|
||||
}
|
||||
res.json(200, {redirect: root + '/ghost/'});
|
||||
res.json(200, {redirect: config.paths().webroot + '/ghost/'});
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -159,8 +154,7 @@ adminControllers = {
|
||||
});
|
||||
},
|
||||
'generateResetToken': function (req, res) {
|
||||
var root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
|
||||
email = req.body.email;
|
||||
var email = req.body.email;
|
||||
|
||||
api.users.generateResetToken(email).then(function (token) {
|
||||
var siteLink = '<a href="' + config().url + '">' + config().url + '</a>',
|
||||
@ -185,7 +179,7 @@ adminControllers = {
|
||||
};
|
||||
|
||||
return api.notifications.add(notification).then(function () {
|
||||
res.json(200, {redirect: root + '/ghost/signin/'});
|
||||
res.json(200, {redirect: config.paths().webroot + '/ghost/signin/'});
|
||||
});
|
||||
|
||||
}, function failure(error) {
|
||||
@ -199,9 +193,8 @@ adminControllers = {
|
||||
});
|
||||
},
|
||||
'reset': function (req, res) {
|
||||
var root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
|
||||
// Validate the request token
|
||||
token = req.params.token;
|
||||
// Validate the request token
|
||||
var token = req.params.token;
|
||||
|
||||
api.users.validateToken(token).then(function () {
|
||||
// Render the reset form
|
||||
@ -222,13 +215,12 @@ adminControllers = {
|
||||
errors.logError(err, 'admin.js', "Please check the provided token for validity and expiration.");
|
||||
|
||||
return api.notifications.add(notification).then(function () {
|
||||
res.redirect(root + '/ghost/forgotten');
|
||||
res.redirect(config.paths().webroot + '/ghost/forgotten');
|
||||
});
|
||||
});
|
||||
},
|
||||
'resetPassword': function (req, res) {
|
||||
var root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
|
||||
token = req.params.token,
|
||||
var token = req.params.token,
|
||||
newPassword = req.param('newpassword'),
|
||||
ne2Password = req.param('ne2password');
|
||||
|
||||
@ -241,7 +233,7 @@ adminControllers = {
|
||||
};
|
||||
|
||||
return api.notifications.add(notification).then(function () {
|
||||
res.json(200, {redirect: root + '/ghost/signin/'});
|
||||
res.json(200, {redirect: config.paths().webroot + '/ghost/signin/'});
|
||||
});
|
||||
}).otherwise(function (err) {
|
||||
// TODO: Better error message if we can tell whether the passwords didn't match or something
|
||||
@ -251,8 +243,7 @@ adminControllers = {
|
||||
'logout': function (req, res) {
|
||||
req.session.destroy();
|
||||
|
||||
var root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
|
||||
notification = {
|
||||
var notification = {
|
||||
type: 'success',
|
||||
message: 'You were successfully signed out',
|
||||
status: 'passive',
|
||||
@ -260,7 +251,7 @@ adminControllers = {
|
||||
};
|
||||
|
||||
return api.notifications.add(notification).then(function () {
|
||||
res.redirect(root + '/ghost/signin/');
|
||||
res.redirect(config.paths().webroot + '/ghost/signin/');
|
||||
});
|
||||
},
|
||||
'index': function (req, res) {
|
||||
|
@ -4,8 +4,7 @@
|
||||
|
||||
/*global require, module */
|
||||
|
||||
var Ghost = require('../../ghost'),
|
||||
config = require('../config'),
|
||||
var config = require('../config'),
|
||||
api = require('../api'),
|
||||
RSS = require('rss'),
|
||||
_ = require('underscore'),
|
||||
@ -14,35 +13,37 @@ var Ghost = require('../../ghost'),
|
||||
url = require('url'),
|
||||
filters = require('../../server/filters'),
|
||||
|
||||
ghost = new Ghost(),
|
||||
frontendControllers;
|
||||
|
||||
frontendControllers = {
|
||||
'homepage': function (req, res, next) {
|
||||
var root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
|
||||
// Parse the page number
|
||||
pageParam = req.params.page !== undefined ? parseInt(req.params.page, 10) : 1,
|
||||
postsPerPage = parseInt(ghost.settings('postsPerPage'), 10),
|
||||
// Parse the page number
|
||||
var pageParam = req.params.page !== undefined ? parseInt(req.params.page, 10) : 1,
|
||||
postsPerPage,
|
||||
options = {};
|
||||
|
||||
// No negative pages
|
||||
if (isNaN(pageParam) || pageParam < 1) {
|
||||
//redirect to 404 page?
|
||||
return res.redirect(root + '/');
|
||||
}
|
||||
options.page = pageParam;
|
||||
api.settings.read('postsPerPage').then(function (postPP) {
|
||||
postsPerPage = parseInt(postPP.value, 10);
|
||||
// No negative pages
|
||||
if (isNaN(pageParam) || pageParam < 1) {
|
||||
//redirect to 404 page?
|
||||
return res.redirect('/');
|
||||
}
|
||||
options.page = pageParam;
|
||||
|
||||
// Redirect '/page/1/' to '/' for all teh good SEO
|
||||
if (pageParam === 1 && req.route.path === '/page/:page/') {
|
||||
return res.redirect(root + '/');
|
||||
}
|
||||
// Redirect '/page/1/' to '/' for all teh good SEO
|
||||
if (pageParam === 1 && req.route.path === '/page/:page/') {
|
||||
return res.redirect(config.paths().webroot + '/');
|
||||
}
|
||||
|
||||
// No negative posts per page, must be number
|
||||
if (!isNaN(postsPerPage) && postsPerPage > 0) {
|
||||
options.limit = postsPerPage;
|
||||
}
|
||||
|
||||
api.posts.browse(options).then(function (page) {
|
||||
// No negative posts per page, must be number
|
||||
if (!isNaN(postsPerPage) && postsPerPage > 0) {
|
||||
options.limit = postsPerPage;
|
||||
}
|
||||
return;
|
||||
}).then(function () {
|
||||
return api.posts.browse(options);
|
||||
}).then(function (page) {
|
||||
var maxPage = page.pages;
|
||||
|
||||
// A bit of a hack for situations with no content.
|
||||
@ -53,7 +54,7 @@ frontendControllers = {
|
||||
|
||||
// If page is greater than number of pages we have, redirect to last page
|
||||
if (pageParam > maxPage) {
|
||||
return res.redirect(maxPage === 1 ? root + '/' : (root + '/page/' + maxPage + '/'));
|
||||
return res.redirect(maxPage === 1 ? config.paths().webroot + '/' : (config.paths().webroot + '/page/' + maxPage + '/'));
|
||||
}
|
||||
|
||||
// Render the page of posts
|
||||
@ -70,12 +71,14 @@ frontendControllers = {
|
||||
api.posts.read(_.pick(req.params, ['id', 'slug'])).then(function (post) {
|
||||
if (post) {
|
||||
filters.doFilter('prePostsRender', post).then(function (post) {
|
||||
var paths = config.paths().availableThemes[ghost.settings('activeTheme')];
|
||||
if (post.page && paths.hasOwnProperty('page')) {
|
||||
res.render('page', {post: post});
|
||||
} else {
|
||||
res.render('post', {post: post});
|
||||
}
|
||||
api.settings.read('activeTheme').then(function (activeTheme) {
|
||||
var paths = config.paths().availableThemes[activeTheme];
|
||||
if (post.page && paths.hasOwnProperty('page')) {
|
||||
res.render('page', {post: post});
|
||||
} else {
|
||||
res.render('post', {post: post});
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
@ -90,14 +93,20 @@ frontendControllers = {
|
||||
'rss': function (req, res, next) {
|
||||
// Initialize RSS
|
||||
var siteUrl = config().url,
|
||||
root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
|
||||
pageParam = req.params.page !== undefined ? parseInt(req.params.page, 10) : 1,
|
||||
feed;
|
||||
//needs refact for multi user to not use first user as default
|
||||
api.users.read({id : 1}).then(function (user) {
|
||||
when.all([
|
||||
api.users.read({id : 1}),
|
||||
api.settings.read('title'),
|
||||
api.settings.read('description')
|
||||
]).then(function (values) {
|
||||
var user = values[0],
|
||||
title = values[1].value,
|
||||
description = values[2].value;
|
||||
feed = new RSS({
|
||||
title: ghost.settings('title'),
|
||||
description: ghost.settings('description'),
|
||||
title: title,
|
||||
description: description,
|
||||
generator: 'Ghost v' + res.locals.version,
|
||||
author: user ? user.name : null,
|
||||
feed_url: url.resolve(siteUrl, '/rss/'),
|
||||
@ -107,11 +116,11 @@ frontendControllers = {
|
||||
|
||||
// No negative pages
|
||||
if (isNaN(pageParam) || pageParam < 1) {
|
||||
return res.redirect(root + '/rss/');
|
||||
return res.redirect(config.paths().webroot + '/rss/');
|
||||
}
|
||||
|
||||
if (pageParam === 1 && req.route.path === root + '/rss/:page/') {
|
||||
return res.redirect(root + '/rss/');
|
||||
if (pageParam === 1 && req.route.path === config.paths().webroot + '/rss/:page/') {
|
||||
return res.redirect(config.paths().webroot + '/rss/');
|
||||
}
|
||||
|
||||
api.posts.browse({page: pageParam}).then(function (page) {
|
||||
@ -125,7 +134,7 @@ frontendControllers = {
|
||||
|
||||
// If page is greater than number of pages we have, redirect to last page
|
||||
if (pageParam > maxPage) {
|
||||
return res.redirect(root + '/rss/' + maxPage + '/');
|
||||
return res.redirect(config.paths().webroot + '/rss/' + maxPage + '/');
|
||||
}
|
||||
|
||||
filters.doFilter('prePostsRender', page.posts).then(function (posts) {
|
||||
|
@ -13,6 +13,7 @@ var _ = require('underscore'),
|
||||
version = packageInfo.version,
|
||||
scriptTemplate = _.template("<script src='<%= source %>?v=<%= version %>'></script>"),
|
||||
isProduction = process.env.NODE_ENV === 'production',
|
||||
api = require('../api'),
|
||||
coreHelpers = {},
|
||||
registerHelpers;
|
||||
|
||||
@ -95,25 +96,23 @@ coreHelpers.url = function (options) {
|
||||
},
|
||||
blog = coreHelpers.ghost.blogGlobals(),
|
||||
isAbsolute = options && options.hash.absolute;
|
||||
|
||||
if (isAbsolute) {
|
||||
output += blog.url;
|
||||
}
|
||||
|
||||
if (blog.path && blog.path !== '/') {
|
||||
output += blog.path;
|
||||
}
|
||||
|
||||
if (models.isPost(this)) {
|
||||
output += coreHelpers.ghost.settings('permalinks');
|
||||
output = output.replace(/(:[a-z]+)/g, function (match) {
|
||||
if (_.has(tags, match.substr(1))) {
|
||||
return tags[match.substr(1)]();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return output;
|
||||
return api.settings.read('permalinks').then(function (permalinks) {
|
||||
if (isAbsolute) {
|
||||
output += blog.url;
|
||||
}
|
||||
if (blog.path && blog.path !== '/') {
|
||||
output += blog.path;
|
||||
}
|
||||
if (models.isPost(self)) {
|
||||
output += permalinks.value;
|
||||
output = output.replace(/(:[a-z]+)/g, function (match) {
|
||||
if (_.has(tags, match.substr(1))) {
|
||||
return tags[match.substr(1)]();
|
||||
}
|
||||
});
|
||||
}
|
||||
return output;
|
||||
});
|
||||
};
|
||||
|
||||
// ### Asset helper
|
||||
@ -429,14 +428,19 @@ coreHelpers.meta_description = function (options) {
|
||||
*/
|
||||
coreHelpers.e = function (key, defaultString, options) {
|
||||
var output;
|
||||
|
||||
if (coreHelpers.ghost.settings('defaultLang') === 'en' && _.isEmpty(options.hash) && !coreHelpers.ghost.settings('forceI18n')) {
|
||||
output = defaultString;
|
||||
} else {
|
||||
output = polyglot().t(key, options.hash);
|
||||
}
|
||||
|
||||
return output;
|
||||
when.all([
|
||||
api.settings.read('defaultLang'),
|
||||
api.settings.read('forceI18n')
|
||||
]).then(function (values) {
|
||||
if (values[0].value === 'en'
|
||||
&& _.isEmpty(options.hash)
|
||||
&& _.isEmpty(values[1].value)) {
|
||||
output = defaultString;
|
||||
} else {
|
||||
output = polyglot().t(key, options.hash);
|
||||
}
|
||||
return output;
|
||||
});
|
||||
};
|
||||
|
||||
coreHelpers.json = function (object, options) {
|
||||
@ -605,8 +609,6 @@ registerHelpers = function (ghost, config) {
|
||||
|
||||
registerThemeHelper('date', coreHelpers.date);
|
||||
|
||||
registerThemeHelper('e', coreHelpers.e);
|
||||
|
||||
registerThemeHelper('encode', coreHelpers.encode);
|
||||
|
||||
registerThemeHelper('excerpt', coreHelpers.excerpt);
|
||||
@ -619,18 +621,16 @@ registerHelpers = function (ghost, config) {
|
||||
|
||||
registerThemeHelper('has_tag', coreHelpers.has_tag);
|
||||
|
||||
registerThemeHelper('helperMissing', coreHelpers.helperMissing);
|
||||
|
||||
registerThemeHelper('json', coreHelpers.json);
|
||||
|
||||
registerThemeHelper('pageUrl', coreHelpers.pageUrl);
|
||||
|
||||
registerThemeHelper('tags', coreHelpers.tags);
|
||||
|
||||
registerThemeHelper('url', coreHelpers.url);
|
||||
|
||||
registerAsyncThemeHelper('body_class', coreHelpers.body_class);
|
||||
|
||||
registerAsyncThemeHelper('e', coreHelpers.e);
|
||||
|
||||
registerAsyncThemeHelper('ghost_foot', coreHelpers.ghost_foot);
|
||||
|
||||
registerAsyncThemeHelper('ghost_head', coreHelpers.ghost_head);
|
||||
@ -641,6 +641,8 @@ registerHelpers = function (ghost, config) {
|
||||
|
||||
registerAsyncThemeHelper('post_class', coreHelpers.post_class);
|
||||
|
||||
registerAsyncThemeHelper('url', coreHelpers.url);
|
||||
|
||||
paginationHelper = template.loadTemplate('pagination').then(function (templateFn) {
|
||||
coreHelpers.paginationTemplate = templateFn;
|
||||
|
||||
|
@ -5,7 +5,8 @@ var templates = {},
|
||||
errors = require('../errorHandling'),
|
||||
path = require('path'),
|
||||
when = require('when'),
|
||||
config = require('../config');
|
||||
config = require('../config'),
|
||||
api = require('../api');
|
||||
|
||||
// ## Template utils
|
||||
|
||||
@ -19,22 +20,23 @@ templates.compileTemplate = function (templatePath) {
|
||||
// Load a template for a handlebars helper
|
||||
templates.loadTemplate = function (name) {
|
||||
var templateFileName = name + '.hbs',
|
||||
// Check for theme specific version first
|
||||
templatePath = path.join(config.paths().activeTheme, 'partials', templateFileName),
|
||||
deferred = when.defer();
|
||||
// Check for theme specific version first
|
||||
return api.settings.read('activeTheme').then(function (activeTheme) {
|
||||
var templatePath = path.join(config.paths().themePath, activeTheme.value, 'partials', templateFileName);
|
||||
|
||||
// Can't use nodefn here because exists just returns one parameter, true or false
|
||||
// Can't use nodefn here because exists just returns one parameter, true or false
|
||||
fs.exists(templatePath, function (exists) {
|
||||
if (!exists) {
|
||||
// Fall back to helpers templates location
|
||||
templatePath = path.join(config.paths().helperTemplates, templateFileName);
|
||||
}
|
||||
|
||||
fs.exists(templatePath, function (exists) {
|
||||
if (!exists) {
|
||||
// Fall back to helpers templates location
|
||||
templatePath = path.join(config.paths().helperTemplates, templateFileName);
|
||||
}
|
||||
templates.compileTemplate(templatePath).then(deferred.resolve, deferred.reject);
|
||||
});
|
||||
|
||||
templates.compileTemplate(templatePath).then(deferred.resolve, deferred.reject);
|
||||
return deferred.promise;
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
module.exports = templates;
|
@ -46,7 +46,7 @@ function setup(server) {
|
||||
// Initialise mail after first run,
|
||||
// passing in config module to prevent
|
||||
// circular dependencies.
|
||||
mailer.init(ghost, config),
|
||||
mailer.init(),
|
||||
helpers.loadCoreHelpers(ghost, config)
|
||||
);
|
||||
}).then(function () {
|
||||
|
@ -3,7 +3,9 @@ var cp = require('child_process'),
|
||||
_ = require('underscore'),
|
||||
when = require('when'),
|
||||
nodefn = require('when/node/function'),
|
||||
nodemailer = require('nodemailer');
|
||||
nodemailer = require('nodemailer'),
|
||||
api = require('./api'),
|
||||
config = require('./config');
|
||||
|
||||
function GhostMailer(opts) {
|
||||
opts = opts || {};
|
||||
@ -12,19 +14,10 @@ function GhostMailer(opts) {
|
||||
|
||||
// ## E-mail transport setup
|
||||
// *This promise should always resolve to avoid halting Ghost::init*.
|
||||
GhostMailer.prototype.init = function (ghost, configModule) {
|
||||
this.ghost = ghost;
|
||||
// TODO: fix circular reference ghost -> mail -> api -> ghost, remove this late require
|
||||
this.api = require('./api');
|
||||
// We currently pass in the config module to avoid
|
||||
// circular references, similar to above.
|
||||
this.config = configModule;
|
||||
|
||||
var self = this,
|
||||
config = this.config();
|
||||
|
||||
if (config.mail && config.mail.transport && config.mail.options) {
|
||||
this.createTransport(config);
|
||||
GhostMailer.prototype.init = function () {
|
||||
var self = this;
|
||||
if (config().mail && config().mail.transport && config().mail.options) {
|
||||
this.createTransport(config());
|
||||
return when.resolve();
|
||||
}
|
||||
|
||||
@ -64,7 +57,7 @@ GhostMailer.prototype.createTransport = function (config) {
|
||||
};
|
||||
|
||||
GhostMailer.prototype.usingSendmail = function () {
|
||||
this.api.notifications.add({
|
||||
api.notifications.add({
|
||||
type: 'info',
|
||||
message: [
|
||||
"Ghost is attempting to use your server's <b>sendmail</b> to send e-mail.",
|
||||
@ -77,7 +70,7 @@ GhostMailer.prototype.usingSendmail = function () {
|
||||
};
|
||||
|
||||
GhostMailer.prototype.emailDisabled = function () {
|
||||
this.api.notifications.add({
|
||||
api.notifications.add({
|
||||
type: 'warn',
|
||||
message: [
|
||||
"Ghost is currently unable to send e-mail.",
|
||||
@ -97,18 +90,19 @@ GhostMailer.prototype.send = function (message) {
|
||||
if (!(message && message.subject && message.html)) {
|
||||
return when.reject(new Error('Email Error: Incomplete message data.'));
|
||||
}
|
||||
api.settings.read('email').then(function (email) {
|
||||
var from = config().mail.fromaddress || email.value,
|
||||
to = message.to || email.value;
|
||||
|
||||
var from = this.config().mail.fromaddress || this.ghost.settings('email'),
|
||||
to = message.to || this.ghost.settings('email'),
|
||||
sendMail = nodefn.lift(this.transport.sendMail.bind(this.transport));
|
||||
|
||||
message = _.extend(message, {
|
||||
from: from,
|
||||
to: to,
|
||||
generateTextFromHTML: true
|
||||
});
|
||||
|
||||
return sendMail(message).otherwise(function (error) {
|
||||
message = _.extend(message, {
|
||||
from: from,
|
||||
to: to,
|
||||
generateTextFromHTML: true
|
||||
});
|
||||
}).then(function () {
|
||||
var sendMail = nodefn.lift(this.transport.sendMail.bind(this.transport));
|
||||
return sendMail(message);
|
||||
}).otherwise(function (error) {
|
||||
// Proxy the error message so we can add 'Email Error:' to the beginning to make it clearer.
|
||||
error = _.isString(error) ? 'Email Error:' + error : (_.isObject(error) ? 'Email Error: ' + error.message : 'Email Error: Unknown Email Error');
|
||||
return when.reject(new Error(error));
|
||||
|
@ -5,6 +5,7 @@
|
||||
var middleware = require('./middleware'),
|
||||
express = require('express'),
|
||||
_ = require('underscore'),
|
||||
when = require('when'),
|
||||
slashes = require('connect-slashes'),
|
||||
errors = require('../errorHandling'),
|
||||
api = require('../api'),
|
||||
@ -33,24 +34,32 @@ function ghostLocals(req, res, next) {
|
||||
|
||||
if (res.isAdmin) {
|
||||
res.locals.csrfToken = req.csrfToken();
|
||||
api.users.read({id: req.session.user}).then(function (currentUser) {
|
||||
when.all([
|
||||
api.users.read({id: req.session.user}),
|
||||
api.notifications.browse()
|
||||
]).then(function (values) {
|
||||
var currentUser = values[0],
|
||||
notifications = values[1];
|
||||
|
||||
_.extend(res.locals, {
|
||||
currentUser: {
|
||||
name: currentUser.name,
|
||||
email: currentUser.email,
|
||||
image: currentUser.image
|
||||
},
|
||||
messages: ghost.notifications
|
||||
messages: notifications
|
||||
});
|
||||
next();
|
||||
}).otherwise(function () {
|
||||
// Only show passive notifications
|
||||
_.extend(res.locals, {
|
||||
messages: _.reject(ghost.notifications, function (notification) {
|
||||
return notification.status !== 'passive';
|
||||
})
|
||||
api.notifications.browse().then(function (notifications) {
|
||||
_.extend(res.locals, {
|
||||
messages: _.reject(notifications, function (notification) {
|
||||
return notification.status !== 'passive';
|
||||
})
|
||||
});
|
||||
next();
|
||||
});
|
||||
next();
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
@ -66,14 +75,15 @@ function initViews(req, res, next) {
|
||||
if (!res.isAdmin) {
|
||||
// self.globals is a hack til we have a better way of getting combined settings & config
|
||||
hbsOptions = {templateOptions: {data: {blog: ghost.blogGlobals()}}};
|
||||
api.settings.read('activeTheme').then(function (activeTheme) {
|
||||
if (config.paths().availableThemes[activeTheme.value].hasOwnProperty('partials')) {
|
||||
// Check that the theme has a partials directory before trying to use it
|
||||
hbsOptions.partialsDir = path.join(config.paths().themePath, activeTheme.value, 'partials');
|
||||
}
|
||||
|
||||
if (config.paths().availableThemes[ghost.settings('activeTheme')].hasOwnProperty('partials')) {
|
||||
// Check that the theme has a partials directory before trying to use it
|
||||
hbsOptions.partialsDir = path.join(config.paths().activeTheme, 'partials');
|
||||
}
|
||||
|
||||
ghost.server.engine('hbs', hbs.express3(hbsOptions));
|
||||
ghost.server.set('views', config.paths().activeTheme);
|
||||
ghost.server.engine('hbs', hbs.express3(hbsOptions));
|
||||
ghost.server.set('views', path.join(config.paths().themePath, activeTheme.value));
|
||||
});
|
||||
} else {
|
||||
ghost.server.engine('hbs', hbs.express3({partialsDir: config.paths().adminViews + 'partials'}));
|
||||
ghost.server.set('views', config.paths().adminViews);
|
||||
@ -84,25 +94,22 @@ function initViews(req, res, next) {
|
||||
|
||||
// ### Activate Theme
|
||||
// Helper for manageAdminAndTheme
|
||||
function activateTheme() {
|
||||
function activateTheme(activeTheme) {
|
||||
var stackLocation = _.indexOf(ghost.server.stack, _.find(ghost.server.stack, function (stackItem) {
|
||||
return stackItem.route === '' && stackItem.handle.name === 'settingEnabled';
|
||||
}));
|
||||
|
||||
// Tell the paths to update
|
||||
config.paths.setActiveTheme(ghost);
|
||||
|
||||
// clear the view cache
|
||||
ghost.server.cache = {};
|
||||
ghost.server.disable(ghost.server.get('activeTheme'));
|
||||
ghost.server.set('activeTheme', ghost.settings('activeTheme'));
|
||||
ghost.server.set('activeTheme', activeTheme);
|
||||
ghost.server.enable(ghost.server.get('activeTheme'));
|
||||
if (stackLocation) {
|
||||
ghost.server.stack[stackLocation].handle = middleware.whenEnabled(ghost.server.get('activeTheme'), middleware.staticTheme());
|
||||
}
|
||||
|
||||
// Update user error template
|
||||
errors.updateActiveTheme(ghost.settings('activeTheme'));
|
||||
errors.updateActiveTheme(activeTheme);
|
||||
}
|
||||
|
||||
// ### ManageAdminAndTheme Middleware
|
||||
@ -123,26 +130,26 @@ function manageAdminAndTheme(req, res, next) {
|
||||
ghost.server.enable(ghost.server.get('activeTheme'));
|
||||
ghost.server.disable('admin');
|
||||
}
|
||||
|
||||
// Check if the theme changed
|
||||
if (ghost.settings('activeTheme') !== ghost.server.get('activeTheme')) {
|
||||
// Change theme
|
||||
if (!config.paths().availableThemes.hasOwnProperty(ghost.settings('activeTheme'))) {
|
||||
if (!res.isAdmin) {
|
||||
// Throw an error if the theme is not available, but not on the admin UI
|
||||
errors.logAndThrowError('The currently active theme ' + ghost.settings('activeTheme') + ' is missing.');
|
||||
api.settings.read('activeTheme').then(function (activeTheme) {
|
||||
// Check if the theme changed
|
||||
if (activeTheme.value !== ghost.server.get('activeTheme')) {
|
||||
// Change theme
|
||||
if (!config.paths().availableThemes.hasOwnProperty(activeTheme.value)) {
|
||||
if (!res.isAdmin) {
|
||||
// Throw an error if the theme is not available, but not on the admin UI
|
||||
errors.logAndThrowError('The currently active theme ' + activeTheme.value + ' is missing.');
|
||||
}
|
||||
} else {
|
||||
activateTheme(activeTheme.value);
|
||||
}
|
||||
} else {
|
||||
activateTheme();
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function (server) {
|
||||
var oneYear = 31536000000,
|
||||
root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
|
||||
root = config.paths().webroot,
|
||||
corePath = path.join(config.paths().appRoot, 'core');
|
||||
|
||||
// Logging configuration
|
||||
|
@ -7,6 +7,7 @@ var _ = require('underscore'),
|
||||
Ghost = require('../../ghost'),
|
||||
config = require('../config'),
|
||||
path = require('path'),
|
||||
api = require('../api'),
|
||||
ghost = new Ghost();
|
||||
|
||||
function isBlackListedFileType(file) {
|
||||
@ -23,26 +24,26 @@ var middleware = {
|
||||
auth: function (req, res, next) {
|
||||
if (!req.session.user) {
|
||||
var reqPath = req.path.replace(/^\/ghost\/?/gi, ''),
|
||||
root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
|
||||
redirect = '',
|
||||
msg;
|
||||
|
||||
if (reqPath !== '') {
|
||||
msg = {
|
||||
type: 'error',
|
||||
message: 'Please Sign In',
|
||||
status: 'passive',
|
||||
id: 'failedauth'
|
||||
};
|
||||
// let's only add the notification once
|
||||
if (!_.contains(_.pluck(ghost.notifications, 'id'), 'failedauth')) {
|
||||
ghost.notifications.push(msg);
|
||||
return api.notifications.browse().then(function (notifications) {
|
||||
if (reqPath !== '') {
|
||||
msg = {
|
||||
type: 'error',
|
||||
message: 'Please Sign In',
|
||||
status: 'passive',
|
||||
id: 'failedauth'
|
||||
};
|
||||
// let's only add the notification once
|
||||
if (!_.contains(_.pluck(notifications, 'id'), 'failedauth')) {
|
||||
api.notifications.add(msg);
|
||||
}
|
||||
redirect = '?r=' + encodeURIComponent(reqPath);
|
||||
}
|
||||
redirect = '?r=' + encodeURIComponent(reqPath);
|
||||
}
|
||||
return res.redirect(root + '/ghost/signin/' + redirect);
|
||||
return res.redirect(config.paths().webroot + '/ghost/signin/' + redirect);
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
},
|
||||
|
||||
@ -61,10 +62,8 @@ var middleware = {
|
||||
// Check if we're logged in, and if so, redirect people back to dashboard
|
||||
// Login and signup forms in particular
|
||||
redirectToDashboard: function (req, res, next) {
|
||||
var root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path;
|
||||
|
||||
if (req.session.user) {
|
||||
return res.redirect(root + '/ghost/');
|
||||
return res.redirect(config.paths().webroot + '/ghost/');
|
||||
}
|
||||
|
||||
next();
|
||||
@ -76,10 +75,14 @@ var middleware = {
|
||||
// otherwise they'd appear one too many times
|
||||
cleanNotifications: function (req, res, next) {
|
||||
/*jslint unparam:true*/
|
||||
ghost.notifications = _.reject(ghost.notifications, function (notification) {
|
||||
return notification.status === 'passive';
|
||||
api.notifications.browse().then(function (notifications) {
|
||||
_.each(notifications, function (notification) {
|
||||
if (notification.status === 'passive') {
|
||||
api.notifications.destroy(notification);
|
||||
}
|
||||
});
|
||||
next();
|
||||
});
|
||||
next();
|
||||
},
|
||||
|
||||
// ### DisableCachedResult Middleware
|
||||
@ -119,7 +122,9 @@ var middleware = {
|
||||
|
||||
// to allow unit testing
|
||||
forwardToExpressStatic: function (req, res, next) {
|
||||
return express['static'](config.paths().activeTheme)(req, res, next);
|
||||
api.settings.read('activeTheme').then(function (activeTheme) {
|
||||
express['static'](path.join(config.paths().themePath, activeTheme.value))(req, res, next);
|
||||
});
|
||||
},
|
||||
|
||||
conditionalCSRF: function (req, res, next) {
|
||||
|
@ -2,19 +2,14 @@
|
||||
var _ = require('underscore'),
|
||||
when = require('when'),
|
||||
errors = require('../errorHandling'),
|
||||
ghostApi,
|
||||
api = require('../api'),
|
||||
loader = require('./loader'),
|
||||
availablePlugins;
|
||||
// Holds the available plugins
|
||||
availablePlugins = {};
|
||||
|
||||
// Holds the available plugins
|
||||
availablePlugins = {};
|
||||
|
||||
function getInstalledPlugins() {
|
||||
if (!ghostApi) {
|
||||
ghostApi = require('../api');
|
||||
}
|
||||
|
||||
return ghostApi.settings.read('installedPlugins').then(function (installed) {
|
||||
return api.settings.read('installedPlugins').then(function (installed) {
|
||||
installed.value = installed.value || '[]';
|
||||
|
||||
try {
|
||||
@ -31,7 +26,7 @@ function saveInstalledPlugins(installedPlugins) {
|
||||
return getInstalledPlugins().then(function (currentInstalledPlugins) {
|
||||
var updatedPluginsInstalled = _.uniq(installedPlugins.concat(currentInstalledPlugins));
|
||||
|
||||
return ghostApi.settings.edit('installedPlugins', updatedPluginsInstalled);
|
||||
return api.settings.edit('installedPlugins', updatedPluginsInstalled);
|
||||
});
|
||||
}
|
||||
|
||||
@ -41,7 +36,9 @@ module.exports = {
|
||||
|
||||
try {
|
||||
// We have to parse the value because it's a string
|
||||
pluginsToLoad = JSON.parse(ghost.settings('activePlugins')) || [];
|
||||
api.settings.read('activePlugins').then(function (aPlugins) {
|
||||
pluginsToLoad = JSON.parse(aPlugins.value) || [];
|
||||
});
|
||||
} catch (e) {
|
||||
errors.logError(
|
||||
'Failed to parse activePlugins setting value: ' + e.message,
|
||||
|
@ -1,14 +1,14 @@
|
||||
var frontend = require('../controllers/frontend'),
|
||||
Ghost = require('../../ghost'),
|
||||
|
||||
ghost = new Ghost();
|
||||
|
||||
api = require('../api');
|
||||
module.exports = function (server) {
|
||||
// ### Frontend routes
|
||||
/* TODO: dynamic routing, homepage generator, filters ETC ETC */
|
||||
server.get('/rss/', frontend.rss);
|
||||
server.get('/rss/:page/', frontend.rss);
|
||||
server.get('/page/:page/', frontend.homepage);
|
||||
server.get(ghost.settings('permalinks'), frontend.single);
|
||||
server.get('/', frontend.homepage);
|
||||
|
||||
api.settings.read('permalinks').then(function (permalinks) {
|
||||
server.get(permalinks.value, frontend.single);
|
||||
});
|
||||
};
|
||||
|
@ -44,22 +44,4 @@ describe("Ghost API", function () {
|
||||
|
||||
should.strictEqual(ghost, ghost2);
|
||||
});
|
||||
|
||||
it("uses init() to initialize", function (done) {
|
||||
var dataProviderInitMock = sandbox.stub(ghost.dataProvider, "init", function () {
|
||||
return when.resolve();
|
||||
});
|
||||
|
||||
should.not.exist(ghost.settings());
|
||||
|
||||
ghost.init().then(function () {
|
||||
|
||||
should.exist(ghost.settings());
|
||||
|
||||
dataProviderInitMock.called.should.equal(true);
|
||||
|
||||
done();
|
||||
}, done);
|
||||
|
||||
});
|
||||
});
|
@ -1,19 +1,19 @@
|
||||
/*globals describe, beforeEach, it*/
|
||||
var testUtils = require('../utils'),
|
||||
should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
when = require('when'),
|
||||
_ = require('underscore'),
|
||||
path = require('path'),
|
||||
should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
when = require('when'),
|
||||
_ = require('underscore'),
|
||||
path = require('path'),
|
||||
|
||||
// Stuff we are testing
|
||||
config = require('../../server/config'),
|
||||
api = require('../../server/api'),
|
||||
template = require('../../server/helpers/template');
|
||||
|
||||
describe('Helpers Template', function () {
|
||||
|
||||
var testTemplatePath = 'core/test/utils/fixtures/',
|
||||
themeTemplatePath = 'core/test/utils/fixtures/theme',
|
||||
sandbox;
|
||||
|
||||
beforeEach(function () {
|
||||
@ -48,26 +48,27 @@ describe('Helpers Template', function () {
|
||||
pathsStub = sandbox.stub(config, "paths", function () {
|
||||
return {
|
||||
// Forcing the theme path to be the same
|
||||
activeTheme: path.join(process.cwd(), testTemplatePath),
|
||||
themePath: path.join(process.cwd(), testTemplatePath),
|
||||
helperTemplates: path.join(process.cwd(), testTemplatePath)
|
||||
};
|
||||
});
|
||||
apiStub = sandbox.stub(api.settings , 'read', function () {
|
||||
return when({value: 'casper'});
|
||||
});
|
||||
|
||||
template.loadTemplate('test').then(function (templateFn) {
|
||||
compileSpy.restore();
|
||||
pathsStub.restore();
|
||||
|
||||
// test that compileTemplate was called with the expected path
|
||||
compileSpy.calledOnce.should.equal(true);
|
||||
compileSpy.calledWith(path.join(process.cwd(), testTemplatePath, 'test.hbs')).should.equal(true);
|
||||
|
||||
should.exist(templateFn);
|
||||
_.isFunction(templateFn).should.equal(true);
|
||||
|
||||
templateFn().should.equal('<h1>HelloWorld</h1>');
|
||||
|
||||
done();
|
||||
}).then(null, done);
|
||||
}).otherwise(done);
|
||||
});
|
||||
|
||||
it("loads templates from themes first", function (done) {
|
||||
@ -79,15 +80,19 @@ describe('Helpers Template', function () {
|
||||
// In order for the test to work, need to replace the path to the template
|
||||
pathsStub = sandbox.stub(config, "paths", function () {
|
||||
return {
|
||||
activeTheme: path.join(process.cwd(), themeTemplatePath),
|
||||
// Forcing the theme path to be the same
|
||||
themePath: path.join(process.cwd(), testTemplatePath),
|
||||
helperTemplates: path.join(process.cwd(), testTemplatePath)
|
||||
};
|
||||
});
|
||||
apiStub = sandbox.stub(api.settings , 'read', function () {
|
||||
return when({value: 'theme'});
|
||||
});
|
||||
|
||||
template.loadTemplate('test').then(function (templateFn) {
|
||||
// test that compileTemplate was called with the expected path
|
||||
compileSpy.calledOnce.should.equal(true);
|
||||
compileSpy.calledWith(path.join(process.cwd(), themeTemplatePath, 'partials', 'test.hbs')).should.equal(true);
|
||||
compileSpy.calledWith(path.join(process.cwd(), testTemplatePath, 'theme', 'partials', 'test.hbs')).should.equal(true);
|
||||
|
||||
should.exist(templateFn);
|
||||
_.isFunction(templateFn).should.equal(true);
|
||||
|
@ -8,7 +8,6 @@ var testUtils = require('../utils'),
|
||||
cp = require('child_process'),
|
||||
|
||||
// Stuff we are testing
|
||||
Ghost = require('../../ghost'),
|
||||
defaultConfig = require('../../../config'),
|
||||
mailer = require('../../server/mail'),
|
||||
SMTP,
|
||||
@ -17,7 +16,6 @@ var testUtils = require('../utils'),
|
||||
fakeSettings,
|
||||
fakeSendmail,
|
||||
sandbox = sinon.sandbox.create(),
|
||||
ghost,
|
||||
config;
|
||||
|
||||
// Mock SMTP config
|
||||
@ -51,14 +49,8 @@ describe("Mail", function () {
|
||||
};
|
||||
fakeSendmail = '/fake/bin/sendmail';
|
||||
|
||||
ghost = new Ghost();
|
||||
|
||||
config = sinon.stub().returns(fakeConfig);
|
||||
|
||||
sandbox.stub(ghost, "settings", function () {
|
||||
return fakeSettings;
|
||||
});
|
||||
|
||||
sandbox.stub(mailer, "isWindows", function () {
|
||||
return false;
|
||||
});
|
||||
@ -80,8 +72,8 @@ describe("Mail", function () {
|
||||
});
|
||||
|
||||
it('should setup SMTP transport on initialization', function (done) {
|
||||
fakeConfig.mail = SMTP;
|
||||
mailer.init(ghost, config).then(function () {
|
||||
fakeConfig[process.env.NODE_ENV].mail = SMTP;
|
||||
mailer.init().then(function () {
|
||||
mailer.should.have.property('transport');
|
||||
mailer.transport.transportType.should.eql('SMTP');
|
||||
mailer.transport.sendMail.should.be.a.function;
|
||||
@ -90,8 +82,8 @@ describe("Mail", function () {
|
||||
});
|
||||
|
||||
it('should setup sendmail transport on initialization', function (done) {
|
||||
fakeConfig.mail = SENDMAIL;
|
||||
mailer.init(ghost, config).then(function () {
|
||||
fakeConfig[process.env.NODE_ENV].mail = SENDMAIL;
|
||||
mailer.init().then(function () {
|
||||
mailer.should.have.property('transport');
|
||||
mailer.transport.transportType.should.eql('SENDMAIL');
|
||||
mailer.transport.sendMail.should.be.a.function;
|
||||
@ -100,8 +92,8 @@ describe("Mail", function () {
|
||||
});
|
||||
|
||||
it('should fallback to sendmail if no config set', function (done) {
|
||||
fakeConfig.mail = null;
|
||||
mailer.init(ghost, config).then(function () {
|
||||
fakeConfig[process.env.NODE_ENV].mail = null;
|
||||
mailer.init().then(function () {
|
||||
mailer.should.have.property('transport');
|
||||
mailer.transport.transportType.should.eql('SENDMAIL');
|
||||
mailer.transport.options.path.should.eql(fakeSendmail);
|
||||
@ -110,8 +102,8 @@ describe("Mail", function () {
|
||||
});
|
||||
|
||||
it('should fallback to sendmail if config is empty', function (done) {
|
||||
fakeConfig.mail = {};
|
||||
mailer.init(ghost, config).then(function () {
|
||||
fakeConfig[process.env.NODE_ENV].mail = {};
|
||||
mailer.init().then(function () {
|
||||
mailer.should.have.property('transport');
|
||||
mailer.transport.transportType.should.eql('SENDMAIL');
|
||||
mailer.transport.options.path.should.eql(fakeSendmail);
|
||||
@ -120,23 +112,23 @@ describe("Mail", function () {
|
||||
});
|
||||
|
||||
it('should disable transport if config is empty & sendmail not found', function (done) {
|
||||
fakeConfig.mail = {};
|
||||
fakeConfig[process.env.NODE_ENV].mail = {};
|
||||
mailer.detectSendmail.restore();
|
||||
sandbox.stub(mailer, "detectSendmail", when.reject);
|
||||
mailer.init(ghost, config).then(function () {
|
||||
mailer.init().then(function () {
|
||||
should.not.exist(mailer.transport);
|
||||
done();
|
||||
}).then(null, done);
|
||||
});
|
||||
|
||||
it('should disable transport if config is empty & platform is win32', function (done) {
|
||||
fakeConfig.mail = {};
|
||||
fakeConfig[process.env.NODE_ENV].mail = {};
|
||||
mailer.detectSendmail.restore();
|
||||
mailer.isWindows.restore();
|
||||
sandbox.stub(mailer, 'isWindows', function () {
|
||||
return true;
|
||||
});
|
||||
mailer.init(ghost, config).then(function () {
|
||||
mailer.init().then(function () {
|
||||
should.not.exist(mailer.transport);
|
||||
done();
|
||||
}).then(null, done);
|
||||
@ -145,7 +137,7 @@ describe("Mail", function () {
|
||||
it('should fail to send messages when no transport is set', function (done) {
|
||||
mailer.detectSendmail.restore();
|
||||
sandbox.stub(mailer, "detectSendmail", when.reject);
|
||||
mailer.init(ghost, config).then(function () {
|
||||
mailer.init().then(function () {
|
||||
mailer.send().then(function () {
|
||||
should.fail();
|
||||
done();
|
||||
|
@ -6,6 +6,7 @@ var assert = require('assert'),
|
||||
_ = require('underscore'),
|
||||
express = require('express'),
|
||||
Ghost = require('../../ghost'),
|
||||
api = require('../../server/api');
|
||||
middleware = require('../../server/middleware').middleware;
|
||||
|
||||
describe('Middleware', function () {
|
||||
@ -13,7 +14,7 @@ describe('Middleware', function () {
|
||||
describe('auth', function () {
|
||||
var req, res, ghost = new Ghost();
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(function (done) {
|
||||
req = {
|
||||
session: {}
|
||||
};
|
||||
@ -22,42 +23,51 @@ describe('Middleware', function () {
|
||||
redirect: sinon.spy()
|
||||
};
|
||||
|
||||
ghost.notifications = [];
|
||||
api.notifications.destroyAll().then(function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should redirect to signin path', function (done) {
|
||||
|
||||
req.path = '';
|
||||
|
||||
middleware.auth(req, res, null);
|
||||
assert(res.redirect.calledWithMatch('/ghost/signin/'));
|
||||
return done();
|
||||
middleware.auth(req, res, null).then(function () {
|
||||
assert(res.redirect.calledWithMatch('/ghost/signin/'));
|
||||
return done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should redirect to signin path with redirect paramater stripped of /ghost/', function(done) {
|
||||
var path = 'test/path/party';
|
||||
|
||||
req.path = '/ghost/' + path;
|
||||
|
||||
middleware.auth(req, res, null);
|
||||
assert(res.redirect.calledWithMatch('/ghost/signin/?r=' + encodeURIComponent(path)));
|
||||
return done();
|
||||
middleware.auth(req, res, null).then(function () {
|
||||
assert(res.redirect.calledWithMatch('/ghost/signin/?r=' + encodeURIComponent(path)));
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should only add one message to the notification array', function (done) {
|
||||
var path = 'test/path/party';
|
||||
|
||||
req.path = '/ghost/' + path;
|
||||
|
||||
middleware.auth(req, res, null);
|
||||
assert(res.redirect.calledWithMatch('/ghost/signin/?r=' + encodeURIComponent(path)));
|
||||
assert.equal(ghost.notifications.length, 1);
|
||||
|
||||
middleware.auth(req, res, null);
|
||||
assert(res.redirect.calledWithMatch('/ghost/signin/?r=' + encodeURIComponent(path)));
|
||||
assert.equal(ghost.notifications.length, 1);
|
||||
|
||||
return done();
|
||||
middleware.auth(req, res, null).then(function () {
|
||||
assert(res.redirect.calledWithMatch('/ghost/signin/?r=' + encodeURIComponent(path)));
|
||||
return api.notifications.browse().then(function (notifications) {
|
||||
assert.equal(notifications.length, 1);
|
||||
return;
|
||||
});
|
||||
}).then(function () {
|
||||
return middleware.auth(req, res, null);
|
||||
}).then(function () {
|
||||
assert(res.redirect.calledWithMatch('/ghost/signin/?r=' + encodeURIComponent(path)));
|
||||
return api.notifications.browse().then(function (notifications) {
|
||||
assert.equal(notifications.length, 1);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should call next if session user exists', function (done) {
|
||||
@ -133,33 +143,37 @@ describe('Middleware', function () {
|
||||
});
|
||||
|
||||
describe('cleanNotifications', function () {
|
||||
var ghost = new Ghost();
|
||||
|
||||
beforeEach(function () {
|
||||
ghost.notifications = [
|
||||
{
|
||||
beforeEach(function (done) {
|
||||
api.notifications.add({
|
||||
id: 0,
|
||||
status: 'passive',
|
||||
message: 'passive-one'
|
||||
},
|
||||
{
|
||||
status: 'passive',
|
||||
message: 'passive-two'
|
||||
},
|
||||
{
|
||||
status: 'aggressive',
|
||||
message: 'aggressive'
|
||||
}
|
||||
];
|
||||
}).then(function () {
|
||||
return api.notifications.add({
|
||||
id: 1,
|
||||
status: 'passive',
|
||||
message: 'passive-two'});
|
||||
}).then(function () {
|
||||
return api.notifications.add({
|
||||
id: 2,
|
||||
status: 'aggressive',
|
||||
message: 'aggressive'});
|
||||
}).then(function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should clean all passive messages', function (done) {
|
||||
middleware.cleanNotifications(null, null, function () {
|
||||
assert.equal(ghost.notifications.length, 1);
|
||||
var passiveMsgs = _.filter(ghost.notifications, function (notification) {
|
||||
return notification.status === 'passive';
|
||||
api.notifications.browse().then(function (notifications) {
|
||||
should(notifications.length).eql(1);
|
||||
var passiveMsgs = _.filter(notifications, function (notification) {
|
||||
return notification.status === 'passive';
|
||||
});
|
||||
assert.equal(passiveMsgs.length, 0);
|
||||
return done();
|
||||
});
|
||||
assert.equal(passiveMsgs.length, 0);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,10 +1,11 @@
|
||||
/*globals describe, beforeEach, it*/
|
||||
var testUtils = require('../utils'),
|
||||
should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
when = require('when'),
|
||||
_ = require('underscore'),
|
||||
path = require('path'),
|
||||
should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
when = require('when'),
|
||||
_ = require('underscore'),
|
||||
path = require('path'),
|
||||
api = require('../../server/api'),
|
||||
|
||||
// Stuff we are testing
|
||||
handlebars = require('express-hbs').handlebars,
|
||||
@ -13,15 +14,37 @@ var testUtils = require('../utils'),
|
||||
|
||||
describe('Core Helpers', function () {
|
||||
|
||||
var ghost;
|
||||
var ghost,
|
||||
sandbox,
|
||||
blogGlobalsStub,
|
||||
apiStub;
|
||||
|
||||
beforeEach(function (done) {
|
||||
ghost = new Ghost();
|
||||
sandbox = sinon.sandbox.create();
|
||||
apiStub = sandbox.stub(api.settings , 'read', function () {
|
||||
return when({value: 'casper'});
|
||||
});
|
||||
|
||||
blogGlobalsStub = sandbox.stub(ghost, 'blogGlobals', function () {
|
||||
return {
|
||||
path: '',
|
||||
//url: 'http://127.0.0.1:2368',
|
||||
title: 'Ghost',
|
||||
description: 'Just a blogging platform.',
|
||||
url: 'http://testurl.com'
|
||||
};
|
||||
});
|
||||
|
||||
helpers.loadCoreHelpers(ghost).then(function () {
|
||||
done();
|
||||
}, done);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('Content Helper', function () {
|
||||
it('has loaded content helper', function () {
|
||||
should.exist(handlebars.helpers.content);
|
||||
@ -292,33 +315,36 @@ describe('Core Helpers', function () {
|
||||
should.exist(handlebars.helpers.url);
|
||||
});
|
||||
|
||||
it('should return a the slug with a prefix slash if the context is a post', function () {
|
||||
var rendered = helpers.url.call({html: 'content', markdown: "ff", title: "title", slug: "slug", created_at: new Date(0)});
|
||||
should.exist(rendered);
|
||||
rendered.should.equal('/slug/');
|
||||
it('should return the slug with a prefix slash if the context is a post', function () {
|
||||
helpers.url.call({html: 'content', markdown: "ff", title: "title", slug: "slug", created_at: new Date(0)}).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.should.equal('/slug/');
|
||||
});
|
||||
});
|
||||
|
||||
it('should output an absolute URL if the option is present', function () {
|
||||
var configStub = sinon.stub(ghost, "blogGlobals", function () {
|
||||
return { url: 'http://testurl.com' };
|
||||
}),
|
||||
|
||||
rendered = helpers.url.call(
|
||||
helpers.url.call(
|
||||
{html: 'content', markdown: "ff", title: "title", slug: "slug", created_at: new Date(0)},
|
||||
{hash: { absolute: 'true'}}
|
||||
);
|
||||
|
||||
should.exist(rendered);
|
||||
rendered.should.equal('http://testurl.com/slug/');
|
||||
|
||||
configStub.restore();
|
||||
{hash: { absolute: 'true'}})
|
||||
.then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.should.equal('http://testurl.com/slug/');
|
||||
});
|
||||
});
|
||||
|
||||
it('should return empty string if not a post', function () {
|
||||
helpers.url.call({markdown: "ff", title: "title", slug: "slug"}).should.equal('');
|
||||
helpers.url.call({html: 'content', title: "title", slug: "slug"}).should.equal('');
|
||||
helpers.url.call({html: 'content', markdown: "ff", slug: "slug"}).should.equal('');
|
||||
helpers.url.call({html: 'content', markdown: "ff", title: "title"}).should.equal('');
|
||||
helpers.url.call({markdown: "ff", title: "title", slug: "slug"}).then(function (rendered) {
|
||||
rendered.should.equal('');
|
||||
});
|
||||
helpers.url.call({html: 'content', title: "title", slug: "slug"}).then(function (rendered) {
|
||||
rendered.should.equal('');
|
||||
});
|
||||
helpers.url.call({html: 'content', markdown: "ff", slug: "slug"}).then(function (rendered) {
|
||||
rendered.should.equal('');
|
||||
});
|
||||
helpers.url.call({html: 'content', markdown: "ff", title: "title"}).then(function (rendered) {
|
||||
rendered.should.equal('');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user