diff --git a/core/client/assets/lib/uploader.js b/core/client/assets/lib/uploader.js
index 8c12cd84b7..754ef28ce3 100644
--- a/core/client/assets/lib/uploader.js
+++ b/core/client/assets/lib/uploader.js
@@ -47,7 +47,7 @@
.attr({'src': '', "width": 'auto', "height": 'auto'});
$progress.animate({"opacity": 0}, 250, function () {
- $dropzone.find('span.media').after('
');
+ $dropzone.find('span.media').after('
');
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')
},
diff --git a/core/client/helpers/index.js b/core/client/helpers/index.js
index b44239fe54..b27fa282fc 100644
--- a/core/client/helpers/index.js
+++ b/core/client/helpers/index.js
@@ -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;
+ });
}());
diff --git a/core/client/init.js b/core/client/init.js
index 2aadb42124..28713b6af9 100644
--- a/core/client/init.js
+++ b/core/client/init.js
@@ -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'
});
};
diff --git a/core/client/tpl/login.hbs b/core/client/tpl/login.hbs
index c09f6ace74..896e1106d1 100644
--- a/core/client/tpl/login.hbs
+++ b/core/client/tpl/login.hbs
@@ -7,6 +7,6 @@
diff --git a/core/client/tpl/preview.hbs b/core/client/tpl/preview.hbs
index 55945630ff..75a7c43fad 100644
--- a/core/client/tpl/preview.hbs
+++ b/core/client/tpl/preview.hbs
@@ -53,7 +53,7 @@
You Haven't Written Any Posts Yet!
-
+
{{/unless}}
diff --git a/core/client/views/blog.js b/core/client/views/blog.js
index da0e358fce..bdc8024a53 100644
--- a/core/client/views/blog.js
+++ b/core/client/views/blog.js
@@ -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) {
diff --git a/core/client/views/login.js b/core/client/views/login.js
index ac8eba668d..4a5676f7ce 100644
--- a/core/client/views/login.js
+++ b/core/client/views/login.js
@@ -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')
diff --git a/core/client/views/post-settings.js b/core/client/views/post-settings.js
index f3f8f02b5b..5fcf43c5f0 100644
--- a/core/client/views/post-settings.js
+++ b/core/client/views/post-settings.js
@@ -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',
diff --git a/core/client/views/settings.js b/core/client/views/settings.js
index 9f998852ec..7872b21e4a 100644
--- a/core/client/views/settings.js
+++ b/core/client/views/settings.js
@@ -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')
diff --git a/core/server/api/db.js b/core/server/api/db.js
index dcb7b14264..e28423c0ee 100644
--- a/core/server/api/db.js
+++ b/core/server/api/db.js
@@ -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) {
diff --git a/core/server/api/index.js b/core/server/api/index.js
index f471147a2f..df261516db 100644
--- a/core/server/api/index.js
+++ b/core/server/api/index.js
@@ -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;
}
diff --git a/core/server/config/loader.js b/core/server/config/loader.js
index b3ac64747f..d14943c0ed 100644
--- a/core/server/config/loader.js
+++ b/core/server/config/loader.js
@@ -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);
diff --git a/core/server/config/paths.js b/core/server/config/paths.js
index b525df1f15..7064318365 100644
--- a/core/server/config/paths.js
+++ b/core/server/config/paths.js
@@ -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,
diff --git a/core/server/config/theme.js b/core/server/config/theme.js
index d6630eb7fe..a58ab925b7 100644
--- a/core/server/config/theme.js
+++ b/core/server/config/theme.js
@@ -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 : '';
diff --git a/core/server/controllers/admin.js b/core/server/controllers/admin.js
index be20ead1c9..fa760f713b 100644
--- a/core/server/controllers/admin.js
+++ b/core/server/controllers/admin.js
@@ -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) {
diff --git a/core/server/controllers/frontend.js b/core/server/controllers/frontend.js
index 6cc733f7b0..e6c7ba79ea 100644
--- a/core/server/controllers/frontend.js
+++ b/core/server/controllers/frontend.js
@@ -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) {
diff --git a/core/server/helpers/index.js b/core/server/helpers/index.js
index e1bc07d91c..e563a59175 100644
--- a/core/server/helpers/index.js
+++ b/core/server/helpers/index.js
@@ -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('');
- head.push('');
+ head.push('');
+
if (this.ghostRoot) {
head.push('');
}
@@ -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();
diff --git a/core/server/middleware/index.js b/core/server/middleware/index.js
index 368b4a7413..823c57c230 100644
--- a/core/server/middleware/index.js
+++ b/core/server/middleware/index.js
@@ -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
diff --git a/core/server/middleware/middleware.js b/core/server/middleware/middleware.js
index 39af2a2d97..69f5c0f007 100644
--- a/core/server/middleware/middleware.js
+++ b/core/server/middleware/middleware.js
@@ -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();
diff --git a/core/server/routes/admin.js b/core/server/routes/admin.js
index 54e5389ab1..58f6a6232a 100644
--- a/core/server/routes/admin.js
+++ b/core/server/routes/admin.js
@@ -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);
};
\ No newline at end of file
diff --git a/core/server/storage/localfilesystem.js b/core/server/storage/localfilesystem.js
index 1103ad145a..d6efa1675f 100644
--- a/core/server/storage/localfilesystem.js
+++ b/core/server/storage/localfilesystem.js
@@ -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);
diff --git a/core/test/unit/config_spec.js b/core/test/unit/config_spec.js
index ef9c0b54f6..a0b321d091 100644
--- a/core/test/unit/config_spec.js
+++ b/core/test/unit/config_spec.js
@@ -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);
+ });
+ });
});
\ No newline at end of file
diff --git a/core/test/unit/helpers_template_spec.js b/core/test/unit/server_helpers_template_spec.js
similarity index 100%
rename from core/test/unit/helpers_template_spec.js
rename to core/test/unit/server_helpers_template_spec.js
diff --git a/core/test/unit/storage_localfilesystem_spec.js b/core/test/unit/storage_localfilesystem_spec.js
index 27bdb7a014..c1a4601561 100644
--- a/core/test/unit/storage_localfilesystem_spec.js
+++ b/core/test/unit/storage_localfilesystem_spec.js
@@ -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);
});
});
});