Path, url and subdir cleanup & test

issue #1754

- remove path (it was only used once, and not needed)
- change webroot to subdir
- add unit tests for config.paths
- various other cleanup
- renamed client-side ghostRoot to subdir
- added url helper for client
This commit is contained in:
Hannah Wolfe 2013-12-28 16:01:08 +00:00
parent 32f65759f7
commit 755ad934bf
24 changed files with 180 additions and 98 deletions

View File

@ -47,7 +47,7 @@
.attr({'src': '', "width": 'auto', "height": 'auto'});
$progress.animate({"opacity": 0}, 250, function () {
$dropzone.find('span.media').after('<img class="fileupload-loading" src="' + Ghost.paths.ghostRoot + '/ghost/img/loadingcat.gif" />');
$dropzone.find('span.media').after('<img class="fileupload-loading" src="' + Ghost.paths.subdir + '/ghost/img/loadingcat.gif" />');
if (!settings.editor) {$progress.find('.fileupload-loading').css({"top": "56px"}); }
});
$dropzone.trigger("uploadsuccess", [result]);
@ -62,7 +62,7 @@
var self = this;
$dropzone.find('.js-fileupload').fileupload().fileupload("option", {
url: Ghost.paths.ghostRoot + '/ghost/upload/',
url: Ghost.paths.subdir + '/ghost/upload/',
headers: {
'X-CSRF-Token': $("meta[name='csrf-param']").attr('content')
},

View File

@ -1,5 +1,4 @@
/*globals Handlebars, moment
*/
/*globals Handlebars, moment, Ghost */
(function () {
'use strict';
Handlebars.registerHelper('date', function (context, options) {
@ -29,4 +28,8 @@
}
return date;
});
Handlebars.registerHelper('url', function () {
return Ghost.paths.subdir;
});
}());

View File

@ -4,11 +4,11 @@
function ghostPaths() {
var path = window.location.pathname,
root = path.substr(0, path.search('/ghost/'));
subdir = path.substr(0, path.search('/ghost/'));
return {
ghostRoot: root,
apiRoot: root + '/ghost/api/v0.1'
subdir: subdir,
apiRoot: subdir + '/ghost/api/v0.1'
};
}
@ -61,7 +61,7 @@
Backbone.history.start({
pushState: true,
hashChange: false,
root: Ghost.paths.ghostRoot + '/ghost'
root: Ghost.paths.subdir + '/ghost'
});
};

View File

@ -7,6 +7,6 @@
</div>
<button class="button-save" type="submit">Log in</button>
<section class="meta">
<a class="forgotten-password" href="/ghost/forgotten/">Forgotten password?</a>{{! &bull; <a href="/ghost/signup/">Register new user</a>}}
<a class="forgotten-password" href="{{url}}/ghost/forgotten/">Forgotten password?</a>
</section>
</form>

View File

@ -53,7 +53,7 @@
<div class="no-posts-box">
<div class="no-posts">
<h3>You Haven't Written Any Posts Yet!</h3>
<form action="/ghost/editor/"><button class="button-add large" title="New Post">Write a new Post</button></form>
<form action="{{url}}/ghost/editor/"><button class="button-add large" title="New Post">Write a new Post</button></form>
</div>
</div>
{{/unless}}

View File

@ -213,7 +213,7 @@
e.preventDefault();
// for now this will disable "open in new tab", but when we have a Router implemented
// it can go back to being a normal link to '#/ghost/editor/X'
window.location = Ghost.paths.ghostRoot + '/ghost/editor/' + this.model.get('id') + '/';
window.location = Ghost.paths.subdir + '/ghost/editor/' + this.model.get('id') + '/';
},
toggleFeatured: function (e) {

View File

@ -35,7 +35,7 @@
Ghost.Validate.handleErrors();
} else {
$.ajax({
url: Ghost.paths.ghostRoot + '/ghost/signin/',
url: Ghost.paths.subdir + '/ghost/signin/',
type: 'POST',
headers: {
'X-CSRF-Token': $("meta[name='csrf-param']").attr('content')
@ -100,7 +100,7 @@
Ghost.Validate.handleErrors();
} else {
$.ajax({
url: Ghost.paths.ghostRoot + '/ghost/signup/',
url: Ghost.paths.subdir + '/ghost/signup/',
type: 'POST',
headers: {
'X-CSRF-Token': $("meta[name='csrf-param']").attr('content')
@ -157,7 +157,7 @@
Ghost.Validate.handleErrors();
} else {
$.ajax({
url: Ghost.paths.ghostRoot + '/ghost/forgotten/',
url: Ghost.paths.subdir + '/ghost/forgotten/',
type: 'POST',
headers: {
'X-CSRF-Token': $("meta[name='csrf-param']").attr('content')
@ -224,7 +224,7 @@
this.$('input, button').prop('disabled', true);
$.ajax({
url: Ghost.paths.ghostRoot + '/ghost/reset/' + this.token + '/',
url: Ghost.paths.subdir + '/ghost/reset/' + this.token + '/',
type: 'POST',
headers: {
'X-CSRF-Token': $("meta[name='csrf-param']").attr('content')

View File

@ -221,7 +221,7 @@
}).then(function () {
// Redirect to content screen if deleting post from editor.
if (window.location.pathname.indexOf('editor') > -1) {
window.location = Ghost.paths.ghostRoot + '/ghost/content/';
window.location = Ghost.paths.subdir + '/ghost/content/';
}
Ghost.notifications.addItem({
type: 'success',

View File

@ -383,7 +383,7 @@
} else {
$.ajax({
url: '/ghost/changepw/',
url: Ghost.paths.subdir + '/ghost/changepw/',
type: 'POST',
headers: {
'X-CSRF-Token': $("meta[name='csrf-param']").attr('content')

View File

@ -10,7 +10,7 @@ var dataExport = require('../data/export'),
_ = require('underscore'),
schema = require('../data/schema'),
config = require('../config'),
debugPath = config.paths().webroot + '/ghost/debug/',
debugPath = config.paths().subdir + '/ghost/debug/',
db;
@ -142,7 +142,7 @@ db = {
res.set({
"X-Cache-Invalidate": "/*"
});
res.redirect(config.paths().webroot + '/ghost/signin/');
res.redirect(config.paths().subdir + '/ghost/signin/');
});
}).otherwise(function importFailure(error) {
return apiNotifications.browse().then(function (notifications) {

View File

@ -57,7 +57,7 @@ requestHandler = function (apiMethod) {
// 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) {
if (req.app.routes.get[i].path === config.paths().subdir + permalinks) {
postRouteIndex = i;
break;
}

View File

@ -49,7 +49,8 @@ function writeConfigFile() {
}
function validateConfigEnvironment() {
var envVal = process.env.NODE_ENV || 'undefined',
var envVal = process.env.NODE_ENV || undefined,
rejectMessage = 'Unable to load config',
hasHostAndPort,
hasSocket,
config,
@ -65,20 +66,20 @@ function validateConfigEnvironment() {
if (!config) {
errors.logError(new Error('Cannot find the configuration for the current NODE_ENV'), "NODE_ENV=" + envVal,
'Ensure your config.js has a section for the current NODE_ENV value and is formatted properly.');
return when.reject();
return when.reject(rejectMessage);
}
// Check that our url is valid
parsedUrl = url.parse(config.url || 'invalid', false, true);
if (!parsedUrl.host) {
errors.logError(new Error('Your site url in config.js is invalid.'), config.url, 'Please make sure this is a valid url before restarting');
return when.reject();
return when.reject(rejectMessage);
}
// Check that we have database values
if (!config.database) {
errors.logError(new Error('Your database configuration in config.js is invalid.'), JSON.stringify(config.database), 'Please make sure this is a valid Bookshelf database configuration');
return when.reject();
return when.reject(rejectMessage);
}
hasHostAndPort = config.server && !!config.server.host && !!config.server.port;
@ -87,7 +88,7 @@ function validateConfigEnvironment() {
// Check for valid server host and port values
if (!config.server || !(hasHostAndPort || hasSocket)) {
errors.logError(new Error('Your server values (socket, or host and port) in config.js are invalid.'), JSON.stringify(config.server), 'Please provide them before restarting.');
return when.reject();
return when.reject(rejectMessage);
}
return when.resolve(config);

View File

@ -21,8 +21,7 @@ var path = require('path'),
function paths() {
return {
'appRoot': appRoot,
'path': localPath,
'webroot': localPath === '/' ? '' : localPath,
'subdir': localPath === '/' ? '' : localPath,
'config': path.join(appRoot, 'config.js'),
'configExample': path.join(appRoot, 'config.example.js'),
'contentPath': contentPath,

View File

@ -1,7 +1,7 @@
// Holds all theme configuration information
// that as mostly used by templates and handlebar helpers.
var when = require('when'),
var when = require('when'),
// Variables
themeConfig = {};
@ -23,8 +23,8 @@ function update(settings, configUrl) {
settings.read('logo'),
settings.read('cover')
]).then(function (globals) {
themeConfig.url = configUrl;
// normalise the URL by removing any trailing slash
themeConfig.url = configUrl.replace(/\/$/, '');
themeConfig.title = globals[0].value;
themeConfig.description = globals[1].value;
themeConfig.logo = globals[2] ? globals[2].value : '';

View File

@ -86,7 +86,7 @@ adminControllers = {
req.session.regenerate(function (err) {
if (!err) {
req.session.user = user.id;
var redirect = config.paths().webroot + '/ghost/';
var redirect = config.paths().subdir + '/ghost/';
if (req.body.redirect) {
redirect += decodeURIComponent(req.body.redirect);
}
@ -137,7 +137,7 @@ adminControllers = {
if (req.session.user === undefined) {
req.session.user = user.id;
}
res.json(200, {redirect: config.paths().webroot + '/ghost/'});
res.json(200, {redirect: config.paths().subdir + '/ghost/'});
}
});
});
@ -179,7 +179,7 @@ adminControllers = {
};
return api.notifications.add(notification).then(function () {
res.json(200, {redirect: config.paths().webroot + '/ghost/signin/'});
res.json(200, {redirect: config.paths().subdir + '/ghost/signin/'});
});
}, function failure(error) {
@ -215,7 +215,7 @@ adminControllers = {
errors.logError(err, 'admin.js', "Please check the provided token for validity and expiration.");
return api.notifications.add(notification).then(function () {
res.redirect(config.paths().webroot + '/ghost/forgotten');
res.redirect(config.paths().subdir + '/ghost/forgotten');
});
});
},
@ -233,7 +233,7 @@ adminControllers = {
};
return api.notifications.add(notification).then(function () {
res.json(200, {redirect: config.paths().webroot + '/ghost/signin/'});
res.json(200, {redirect: config.paths().subdir + '/ghost/signin/'});
});
}).otherwise(function (err) {
// TODO: Better error message if we can tell whether the passwords didn't match or something
@ -251,7 +251,7 @@ adminControllers = {
};
return api.notifications.add(notification).then(function () {
res.redirect(config.paths().webroot + '/ghost/signin/');
res.redirect(config.paths().subdir + '/ghost/signin/');
});
},
'index': function (req, res) {

View File

@ -33,7 +33,7 @@ frontendControllers = {
// Redirect '/page/1/' to '/' for all teh good SEO
if (pageParam === 1 && req.route.path === '/page/:page/') {
return res.redirect(config.paths().webroot + '/');
return res.redirect(config.paths().subdir + '/');
}
// No negative posts per page, must be number
@ -54,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 ? config.paths().webroot + '/' : (config.paths().webroot + '/page/' + maxPage + '/'));
return res.redirect(maxPage === 1 ? config.paths().subdir + '/' : (config.paths().subdir + '/page/' + maxPage + '/'));
}
// Render the page of posts
@ -116,11 +116,11 @@ frontendControllers = {
// No negative pages
if (isNaN(pageParam) || pageParam < 1) {
return res.redirect(config.paths().webroot + '/rss/');
return res.redirect(config.paths().subdir + '/rss/');
}
if (pageParam === 1 && req.route.path === config.paths().webroot + '/rss/:page/') {
return res.redirect(config.paths().webroot + '/rss/');
if (pageParam === 1 && req.route.path === config.paths().subdir + '/rss/:page/') {
return res.redirect(config.paths().subdir + '/rss/');
}
api.posts.browse({page: pageParam}).then(function (page) {
@ -134,7 +134,7 @@ frontendControllers = {
// If page is greater than number of pages we have, redirect to last page
if (pageParam > maxPage) {
return res.redirect(config.paths().webroot + '/rss/' + maxPage + '/');
return res.redirect(config.paths().subdir + '/rss/' + maxPage + '/');
}
filters.doFilter('prePostsRender', page.posts).then(function (posts) {

View File

@ -100,14 +100,12 @@ coreHelpers.url = function (options) {
slug: function () { return self.slug; },
id: function () { return self.id; }
},
path = config.paths().path,
isAbsolute = options && options.hash.absolute;
return api.settings.read('permalinks').then(function (permalinks) {
if (isAbsolute) {
output += config().url;
}
if (path && path !== '/') {
output += path;
output += config().url.replace(/\/$/, '');
} else {
output += config.paths().subdir;
}
if (models.isPost(self)) {
output += permalinks.value;
@ -131,14 +129,9 @@ coreHelpers.url = function (options) {
// flag outputs the asset path for the Ghost admin
coreHelpers.asset = function (context, options) {
var output = '',
subDir = config.paths().path,
isAdmin = options && options.hash && options.hash.ghost;
if (subDir === '/') {
output += '/';
} else {
output += subDir + '/';
}
output += config.paths().subdir + '/';
if (isAdmin) {
output += 'ghost/';
@ -269,8 +262,7 @@ coreHelpers.fileStorage = function (context, options) {
};
coreHelpers.ghostScriptTags = function () {
var scriptFiles = [],
webroot = config.paths().webroot;
var scriptFiles = [];
if (isProduction) {
scriptFiles.push("ghost.min.js");
@ -286,7 +278,7 @@ coreHelpers.ghostScriptTags = function () {
scriptFiles = _.map(scriptFiles, function (fileName) {
return scriptTemplate({
source: webroot + '/built/scripts/' + fileName,
source: config.paths().subdir + '/built/scripts/' + fileName,
version: version
});
});
@ -354,7 +346,6 @@ coreHelpers.post_class = function (options) {
coreHelpers.ghost_head = function (options) {
/*jslint unparam:true*/
var blog = config.theme(),
webroot = config.paths().webroot,
head = [],
majorMinor = /^(\d+\.)?(\d+)/,
trimmedVersion = this.version;
@ -363,7 +354,9 @@ coreHelpers.ghost_head = function (options) {
head.push('<meta name="generator" content="Ghost ' + trimmedVersion + '" />');
head.push('<link rel="alternate" type="application/rss+xml" title="' + _.escape(blog.title) + '" href="' + webroot + '/rss/' + '">');
head.push('<link rel="alternate" type="application/rss+xml" title="'
+ _.escape(blog.title) + '" href="' + config.paths().subdir + '/rss/' + '">');
if (this.ghostRoot) {
head.push('<link rel="canonical" href="' + config().url + this.ghostRoot + '" />');
}
@ -376,11 +369,10 @@ coreHelpers.ghost_head = function (options) {
coreHelpers.ghost_foot = function (options) {
/*jslint unparam:true*/
var foot = [],
webroot = config.paths().webroot;
var foot = [];
foot.push(scriptTemplate({
source: (webroot === '/' ? '' : webroot) + '/shared/vendor/jquery/jquery.js',
source: config.paths().subdir + '/shared/vendor/jquery/jquery.js',
version: this.version
}));
@ -394,6 +386,7 @@ coreHelpers.meta_title = function (options) {
/*jslint unparam:true*/
var title,
blog;
if (_.isString(this.ghostRoot)) {
if (!this.ghostRoot || this.ghostRoot === '/' || this.ghostRoot === '' || this.ghostRoot.match(/\/page/)) {
blog = config.theme();

View File

@ -31,7 +31,7 @@ function ghostLocals(req, res, next) {
res.locals.version = packageInfo.version;
res.locals.path = req.path;
// Strip off the subdir part of the path
res.locals.ghostRoot = req.path.replace(config.paths().webroot, '');
res.locals.ghostRoot = req.path.replace(config.paths().subdir, '');
if (res.isAdmin) {
res.locals.csrfToken = req.csrfToken();
@ -99,7 +99,7 @@ function activateTheme(activeTheme) {
expressServer.enable(expressServer.get('activeTheme'));
if (stackLocation) {
expressServer.stack[stackLocation].handle = middleware.whenEnabled(expressServer.get('activeTheme'), middleware.staticTheme());
expressServer.stack[stackLocation].route = config.paths().webroot;
expressServer.stack[stackLocation].route = config.paths().subdir;
}
// set view engine
@ -118,7 +118,7 @@ function activateTheme(activeTheme) {
// Uses the URL to detect whether this response should be an admin response
// This is used to ensure the right content is served, and is not for security purposes
function manageAdminAndTheme(req, res, next) {
res.isAdmin = req.url.lastIndexOf(config.paths().webroot + '/ghost/', 0) === 0;
res.isAdmin = req.url.lastIndexOf(config.paths().subdir + '/ghost/', 0) === 0;
if (res.isAdmin) {
expressServer.enable('admin');
@ -146,11 +146,10 @@ function manageAdminAndTheme(req, res, next) {
// Redirect to signup if no users are currently created
function redirectToSignup(req, res, next) {
var root = config.paths().webroot;
/*jslint unparam:true*/
api.users.browse().then(function (users) {
if (users.length === 0) {
return res.redirect(root + '/ghost/signup/');
return res.redirect(config.paths().subdir + '/ghost/signup/');
}
next();
}).otherwise(function (err) {
@ -190,7 +189,7 @@ function checkSSL(req, res, next) {
module.exports = function (server, dbHash) {
var oneHour = 60 * 60 * 1000,
oneYear = 365 * 24 * oneHour,
root = config.paths().webroot,
subdir = config.paths().subdir,
corePath = config.paths().corePath,
cookie;
@ -206,15 +205,15 @@ module.exports = function (server, dbHash) {
}
// Favicon
expressServer.use(root, express.favicon(corePath + '/shared/favicon.ico'));
expressServer.use(subdir, express.favicon(corePath + '/shared/favicon.ico'));
// Shared static config
expressServer.use(root + '/shared', express['static'](path.join(corePath, '/shared')));
expressServer.use(subdir + '/shared', express['static'](path.join(corePath, '/shared')));
expressServer.use(root + '/content/images', storage.get_storage().serve());
expressServer.use(subdir + '/content/images', storage.get_storage().serve());
// Serve our built scripts; can't use /scripts here because themes already are
expressServer.use(root + '/built/scripts', express['static'](path.join(corePath, '/built/scripts'), {
expressServer.use(subdir + '/built/scripts', express['static'](path.join(corePath, '/built/scripts'), {
// Put a maxAge of one year on built scripts
maxAge: oneYear
}));
@ -226,7 +225,7 @@ module.exports = function (server, dbHash) {
expressServer.use(checkSSL);
// Admin only config
expressServer.use(root + '/ghost', middleware.whenEnabled('admin', express['static'](path.join(corePath, '/client/assets'))));
expressServer.use(subdir + '/ghost', middleware.whenEnabled('admin', express['static'](path.join(corePath, '/client/assets'))));
// Theme only config
expressServer.use(middleware.whenEnabled(expressServer.get('activeTheme'), middleware.staticTheme()));
@ -237,12 +236,12 @@ module.exports = function (server, dbHash) {
expressServer.use(express.json());
expressServer.use(express.urlencoded());
expressServer.use(root + '/ghost/upload/', middleware.busboy);
expressServer.use(root + '/ghost/api/v0.1/db/', middleware.busboy);
expressServer.use(subdir + '/ghost/upload/', middleware.busboy);
expressServer.use(subdir + '/ghost/api/v0.1/db/', middleware.busboy);
// Session handling
cookie = {
path: root + '/ghost',
path: subdir + '/ghost',
maxAge: 12 * oneHour
};
@ -271,7 +270,7 @@ module.exports = function (server, dbHash) {
expressServer.use(initViews);
// process the application routes
expressServer.use(root, expressServer.router);
expressServer.use(subdir, expressServer.router);
// ### Error handling
// 404 Handler

View File

@ -45,7 +45,7 @@ var middleware = {
}
redirect = '?r=' + encodeURIComponent(reqPath);
}
return res.redirect(config.paths().webroot + '/ghost/signin/' + redirect);
return res.redirect(config.paths().subdir + '/ghost/signin/' + redirect);
});
}
next();
@ -67,7 +67,7 @@ var middleware = {
// Login and signup forms in particular
redirectToDashboard: function (req, res, next) {
if (req.session.user) {
return res.redirect(config.paths().webroot + '/ghost/');
return res.redirect(config.paths().subdir + '/ghost/');
}
next();

View File

@ -5,28 +5,28 @@ var admin = require('../controllers/admin'),
url = require('url');
module.exports = function (server) {
var root = config.paths().webroot;
var subdir = config.paths().subdir;
// ### Admin routes
/* TODO: put these somewhere in admin */
server.get('/logout/', function redirect(req, res) {
/*jslint unparam:true*/
res.redirect(301, root + '/ghost/signout/');
res.redirect(301, subdir + '/ghost/signout/');
});
server.get('/signout/', function redirect(req, res) {
/*jslint unparam:true*/
res.redirect(301, root + '/ghost/signout/');
res.redirect(301, subdir + '/ghost/signout/');
});
server.get('/signin/', function redirect(req, res) {
/*jslint unparam:true*/
res.redirect(301, root + '/ghost/signin/');
res.redirect(301, subdir + '/ghost/signin/');
});
server.get('/signup/', function redirect(req, res) {
/*jslint unparam:true*/
res.redirect(301, root + '/ghost/signup/');
res.redirect(301, subdir + '/ghost/signup/');
});
server.get('/ghost/login/', function redirect(req, res) {
/*jslint unparam:true*/
res.redirect(301, root + '/ghost/signin/');
res.redirect(301, subdir + '/ghost/signin/');
});
server.get('/ghost/signout/', admin.logout);
@ -51,11 +51,11 @@ module.exports = function (server) {
// redirect to /ghost and let that do the authentication to prevent redirects to /ghost//admin etc.
server.get(/\/((ghost-admin|admin|wp-admin|dashboard|signin)\/?)$/, function (req, res) {
/*jslint unparam:true*/
res.redirect(root + '/ghost/');
res.redirect(subdir + '/ghost/');
});
server.get(/\/(ghost$\/?)/, middleware.auth, function (req, res) {
/*jslint unparam:true*/
res.redirect(root + '/ghost/');
res.redirect(subdir + '/ghost/');
});
server.get('/ghost/', middleware.redirectToSignup, middleware.auth, admin.index);
};

View File

@ -33,7 +33,7 @@ localFileStore = _.extend(baseStore, {
}).then(function () {
// The src for the image must be in URI format, not a file system path, which in Windows uses \
// For local file system storage can use relative path so add a slash
var fullUrl = (config.paths().webroot + '/' + targetFilename).replace(new RegExp('\\' + path.sep, 'g'), '/');
var fullUrl = (config.paths().subdir + '/' + targetFilename).replace(new RegExp('\\' + path.sep, 'g'), '/');
return saved.resolve(fullUrl);
}).otherwise(function (e) {
errors.logError(e);

View File

@ -3,6 +3,7 @@
var should = require('should'),
sinon = require('sinon'),
when = require('when'),
path = require('path'),
config = require('../../server/config');
@ -11,12 +12,13 @@ describe('Config', function () {
describe('Theme', function () {
var sandbox,
settings,
settingsStub;
beforeEach(function (done) {
sandbox = sinon.sandbox.create();
var settings = {'read': function read() {}};
settings = {'read': function read() {}};
settingsStub = sandbox.stub(settings, 'read', function () {
return when({value: 'casper'});
@ -24,18 +26,26 @@ describe('Config', function () {
config.theme.update(settings, 'http://my-ghost-blog.com')
.then(done)
.otherwise(done);
.then(null, done);
});
afterEach(function () {
afterEach(function (done) {
config.theme.update(settings, config().url)
.then(done)
.then(null, done);
sandbox.restore();
});
it('should have all of the values', function () {
it('should have exactly the right keys', function () {
var themeConfig = config.theme();
// This will fail if there are any extra keys
themeConfig.should.have.keys('url', 'title', 'description', 'logo', 'cover');
});
it('should have the correct values for each key', function () {
var themeConfig = config.theme();
// Check values are as we expect
themeConfig.should.have.property('url', 'http://my-ghost-blog.com');
@ -46,8 +56,85 @@ describe('Config', function () {
// Check settings.read gets called exactly 4 times
settingsStub.callCount.should.equal(4);
});
});
describe('Paths', function () {
var sandbox;
beforeEach(function () {
sandbox = sinon.sandbox.create();
});
afterEach(function (done) {
config.paths.update(config().url)
.then(done)
.then(null, done);
sandbox.restore();
});
it('should have exactly the right keys', function () {
var pathConfig = config.paths();
// This will fail if there are any extra keys
pathConfig.should.have.keys(
'appRoot',
'subdir',
'config',
'configExample',
'contentPath',
'corePath',
'themePath',
'pluginPath',
'imagesPath',
'imagesRelPath',
'adminViews',
'helperTemplates',
'lang',
'availableThemes',
'availablePlugins'
);
});
it('should have the correct values for each key', function () {
var pathConfig = config.paths(),
appRoot = path.resolve(__dirname, '../../../');
pathConfig.should.have.property('appRoot', appRoot);
pathConfig.should.have.property('subdir', '');
});
it('should not return a slash for subdir', function (done) {
config.paths.update('http://my-ghost-blog.com').then(function () {
config.paths().should.have.property('subdir', '');
return config.paths.update('http://my-ghost-blog.com/');
}).then(function () {
config.paths().should.have.property('subdir', '');
done();
}).otherwise(done);
});
it('should handle subdirectories properly', function (done) {
config.paths.update('http://my-ghost-blog.com/blog').then(function () {
config.paths().should.have.property('subdir', '/blog');
return config.paths.update('http://my-ghost-blog.com/blog/');
}).then(function () {
config.paths().should.have.property('subdir', '/blog');
return config.paths.update('http://my-ghost-blog.com/my/blog');
}).then(function () {
config.paths().should.have.property('subdir', '/my/blog');
return config.paths.update('http://my-ghost-blog.com/my/blog/');
}).then(function () {
config.paths().should.have.property('subdir', '/my/blog');
done();
}).otherwise(done);
});
});
});

View File

@ -38,7 +38,7 @@ describe('Local File System Storage', function () {
localfilesystem.save(image).then(function (url) {
url.should.equal('/content/images/2013/Sep/IMAGE.jpg');
return done();
});
}).then(null, done);
});
it('should send correct path to image when original file has spaces', function (done) {
@ -46,7 +46,7 @@ describe('Local File System Storage', function () {
localfilesystem.save(image).then(function (url) {
url.should.equal('/content/images/2013/Sep/AN_IMAGE.jpg');
return done();
});
}).then(null, done);
});
it('should send correct path to image when date is in Jan 2014', function (done) {
@ -55,7 +55,7 @@ describe('Local File System Storage', function () {
localfilesystem.save(image).then(function (url) {
url.should.equal('/content/images/2014/Jan/IMAGE.jpg');
return done();
});
}).then(null, done);
});
it('should create month and year directory', function (done) {
@ -97,7 +97,7 @@ describe('Local File System Storage', function () {
localfilesystem.save(image).then(function (url) {
url.should.equal('/content/images/2013/Sep/IMAGE-1.jpg');
return done();
});
}).then(null, done);
});
it('can upload five different images with the same name without overwriting the first', function (done) {
@ -119,7 +119,7 @@ describe('Local File System Storage', function () {
localfilesystem.save(image).then(function (url) {
url.should.equal('/content/images/2013/Sep/IMAGE-4.jpg');
return done();
});
}).then(null, done);
});
@ -143,7 +143,7 @@ describe('Local File System Storage', function () {
localfilesystem.save(image).then(function (url) {
url.should.equal('/content/images/2013/Sep/IMAGE.jpg');
return done();
});
}).then(null, done);
});
});
});