mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-25 11:55:03 +03:00
Merge pull request #1523 from halfdan/527-subdir-support
This commit is contained in:
commit
727b845254
@ -11,6 +11,7 @@ var config = require('../config'),
|
||||
hbs = require('express-hbs'),
|
||||
nodefn = require('when/node/function'),
|
||||
_ = require('underscore'),
|
||||
url = require('url'),
|
||||
Polyglot = require('node-polyglot'),
|
||||
Mailer = require('./server/mail'),
|
||||
models = require('./server/models'),
|
||||
@ -88,10 +89,18 @@ Ghost = function () {
|
||||
},
|
||||
dataProvider: models,
|
||||
blogGlobals: function () {
|
||||
var localPath = url.parse(instance.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: instance.config().url,
|
||||
url: instance.config().url.replace(/\/$/, ''),
|
||||
path: localPath,
|
||||
title: instance.settings('title'),
|
||||
description: instance.settings('description'),
|
||||
logo: instance.settings('logo'),
|
||||
|
@ -41,6 +41,9 @@ function setup(server) {
|
||||
// set the view engine
|
||||
server.set('view engine', 'hbs');
|
||||
|
||||
// set the configured URL
|
||||
server.set('ghost root', ghost.blogGlobals().path);
|
||||
|
||||
// return the correct mime type for woff filess
|
||||
express['static'].mime.define({'application/font-woff': ['woff']});
|
||||
|
||||
@ -163,4 +166,4 @@ function init(app) {
|
||||
setup(app);
|
||||
}
|
||||
|
||||
module.exports = init;
|
||||
module.exports = init;
|
||||
|
@ -1,13 +1,14 @@
|
||||
var _ = require('underscore'),
|
||||
moment = require('moment'),
|
||||
downsize = require('downsize'),
|
||||
path = require('path'),
|
||||
when = require('when'),
|
||||
hbs = require('express-hbs'),
|
||||
errors = require('../errorHandling'),
|
||||
models = require('../models'),
|
||||
packageInfo = require('../../../package.json'),
|
||||
version = packageInfo.version,
|
||||
scriptTemplate = _.template("<script src='/built/scripts/<%= name %>?v=<%= version %>'></script>"),
|
||||
scriptTemplate = _.template("<script src='<%= source %>?v=<%= version %>'></script>"),
|
||||
isProduction = process.env.NODE_ENV === 'production',
|
||||
coreHelpers = {},
|
||||
registerHelpers;
|
||||
@ -88,10 +89,16 @@ coreHelpers.url = function (options) {
|
||||
day: function () { return self.created_at.getDate(); },
|
||||
slug: function () { return self.slug; },
|
||||
id: function () { return self.id; }
|
||||
};
|
||||
},
|
||||
blog = coreHelpers.ghost.blogGlobals(),
|
||||
isAbsolute = options && options.hash.absolute;
|
||||
|
||||
if (options && options.hash.absolute) {
|
||||
output += coreHelpers.ghost.config().url;
|
||||
if (isAbsolute) {
|
||||
output += blog.url;
|
||||
}
|
||||
|
||||
if (blog.path !== '/') {
|
||||
output += blog.path;
|
||||
}
|
||||
|
||||
if (models.isPost(this)) {
|
||||
@ -219,7 +226,8 @@ coreHelpers.fileStorage = function (context, options) {
|
||||
};
|
||||
|
||||
coreHelpers.ghostScriptTags = function () {
|
||||
var scriptFiles = [];
|
||||
var scriptFiles = [],
|
||||
blog = coreHelpers.ghost.blogGlobals();
|
||||
|
||||
if (isProduction) {
|
||||
scriptFiles.push("ghost.min.js");
|
||||
@ -235,7 +243,7 @@ coreHelpers.ghostScriptTags = function () {
|
||||
|
||||
scriptFiles = _.map(scriptFiles, function (fileName) {
|
||||
return scriptTemplate({
|
||||
name: fileName,
|
||||
source: path.join(blog.path, '/built/scripts/', fileName),
|
||||
version: version
|
||||
});
|
||||
});
|
||||
@ -253,9 +261,9 @@ coreHelpers.body_class = function (options) {
|
||||
tags = this.post && this.post.tags ? this.post.tags : this.tags || [],
|
||||
page = this.post && this.post.page ? this.post.page : this.page || false;
|
||||
|
||||
if (_.isString(this.path) && this.path.match(/\/page/)) {
|
||||
if (_.isString(this.ghostRoot) && this.ghostRoot.match(/\/page/)) {
|
||||
classes.push('archive-template');
|
||||
} else if (!this.path || this.path === '/' || this.path === '') {
|
||||
} else if (!this.ghostRoot || this.ghostRoot === '/' || this.ghostRoot === '') {
|
||||
classes.push('home-template');
|
||||
} else {
|
||||
classes.push('post-template');
|
||||
@ -302,17 +310,18 @@ coreHelpers.post_class = function (options) {
|
||||
|
||||
coreHelpers.ghost_head = function (options) {
|
||||
/*jslint unparam:true*/
|
||||
var head = [],
|
||||
var blog = coreHelpers.ghost.blogGlobals(),
|
||||
head = [],
|
||||
majorMinor = /^(\d+\.)?(\d+)/,
|
||||
trimmedVersion = this.version,
|
||||
blog = coreHelpers.ghost.blogGlobals();
|
||||
trimmedVersion = this.version;
|
||||
|
||||
trimmedVersion = trimmedVersion ? trimmedVersion.match(majorMinor)[0] : '?';
|
||||
|
||||
head.push('<meta name="generator" content="Ghost ' + trimmedVersion + '" />');
|
||||
head.push('<link rel="alternate" type="application/rss+xml" title="' + _.escape(blog.title) + '" href="/rss/">');
|
||||
if (this.path) {
|
||||
head.push('<link rel="canonical" href="' + coreHelpers.ghost.config().url + this.path + '" />');
|
||||
|
||||
head.push('<link rel="alternate" type="application/rss+xml" title="' + _.escape(blog.title) + '" href="' + path.join(blog.path, '/rss/') + '">');
|
||||
if (this.ghostRoot) {
|
||||
head.push('<link rel="canonical" href="' + coreHelpers.ghost.blogGlobals().url + this.ghostRoot + '" />');
|
||||
}
|
||||
|
||||
return coreHelpers.ghost.doFilter('ghost_head', head).then(function (head) {
|
||||
@ -324,7 +333,7 @@ coreHelpers.ghost_head = function (options) {
|
||||
coreHelpers.ghost_foot = function (options) {
|
||||
/*jslint unparam:true*/
|
||||
var foot = [];
|
||||
foot.push('<script src="/shared/vendor/jquery/jquery.js"></script>');
|
||||
foot.push('<script src="' + coreHelpers.ghost.blogGlobals().url + '/shared/vendor/jquery/jquery.js"></script>');
|
||||
|
||||
return coreHelpers.ghost.doFilter('ghost_foot', foot).then(function (foot) {
|
||||
var footString = _.reduce(foot, function (memo, item) { return memo + ' ' + item; }, '');
|
||||
@ -336,8 +345,8 @@ coreHelpers.meta_title = function (options) {
|
||||
/*jslint unparam:true*/
|
||||
var title,
|
||||
blog;
|
||||
if (_.isString(this.path)) {
|
||||
if (!this.path || this.path === '/' || this.path === '' || this.path.match(/\/page/)) {
|
||||
if (_.isString(this.ghostRoot)) {
|
||||
if (!this.ghostRoot || this.ghostRoot === '/' || this.ghostRoot === '' || this.ghostRoot.match(/\/page/)) {
|
||||
blog = coreHelpers.ghost.blogGlobals();
|
||||
title = blog.title;
|
||||
} else {
|
||||
@ -356,8 +365,8 @@ coreHelpers.meta_description = function (options) {
|
||||
var description,
|
||||
blog;
|
||||
|
||||
if (_.isString(this.path)) {
|
||||
if (!this.path || this.path === '/' || this.path === '' || this.path.match(/\/page/)) {
|
||||
if (_.isString(this.ghostRoot)) {
|
||||
if (!this.ghostRoot || this.ghostRoot === '/' || this.ghostRoot === '' || this.ghostRoot.match(/\/page/)) {
|
||||
blog = coreHelpers.ghost.blogGlobals();
|
||||
description = blog.description;
|
||||
} else {
|
||||
|
@ -24,6 +24,7 @@ function ghostLocals(req, res, next) {
|
||||
res.locals.version = packageInfo.version;
|
||||
res.locals.path = req.path;
|
||||
res.locals.csrfToken = req.csrfToken();
|
||||
res.locals.ghostRoot = req.path.replace(ghost.blogGlobals().path, '');
|
||||
|
||||
if (res.isAdmin) {
|
||||
api.users.read({id: req.session.user}).then(function (currentUser) {
|
||||
@ -100,7 +101,12 @@ function activateTheme() {
|
||||
// This is used to ensure the right content is served, and is not for security purposes
|
||||
function manageAdminAndTheme(req, res, next) {
|
||||
// TODO improve this regex
|
||||
res.isAdmin = /(^\/ghost\/)/.test(req.url);
|
||||
if (ghost.blogGlobals().path === '/') {
|
||||
res.isAdmin = /(^\/ghost\/)/.test(req.url);
|
||||
} else {
|
||||
res.isAdmin = new RegExp("^\\" + ghost.blogGlobals().path + "\\/ghost\\/").test(req.url);
|
||||
}
|
||||
|
||||
if (res.isAdmin) {
|
||||
ghost.server.enable('admin');
|
||||
ghost.server.disable(ghost.server.get('activeTheme'));
|
||||
@ -127,6 +133,7 @@ function manageAdminAndTheme(req, res, next) {
|
||||
|
||||
module.exports = function (server) {
|
||||
var oneYear = 31536000000,
|
||||
root = ghost.blogGlobals().path === '/' ? '' : ghost.blogGlobals().path,
|
||||
corePath = path.join(ghost.paths().appRoot, 'core');
|
||||
|
||||
// Logging configuration
|
||||
@ -137,15 +144,15 @@ module.exports = function (server) {
|
||||
}
|
||||
|
||||
// Favicon
|
||||
server.use(express.favicon(corePath + '/shared/favicon.ico'));
|
||||
server.use(root, express.favicon(corePath + '/shared/favicon.ico'));
|
||||
|
||||
// Shared static config
|
||||
server.use('/shared', express['static'](path.join(corePath, '/shared')));
|
||||
server.use(root + '/shared', express['static'](path.join(corePath, '/shared')));
|
||||
|
||||
server.use('/content/images', storage.get_storage().serve());
|
||||
server.use(root + '/content/images', storage.get_storage().serve());
|
||||
|
||||
// Serve our built scripts; can't use /scripts here because themes already are
|
||||
server.use('/built/scripts', express['static'](path.join(corePath, '/built/scripts'), {
|
||||
server.use(root + '/built/scripts', express['static'](path.join(corePath, '/built/scripts'), {
|
||||
// Put a maxAge of one year on built scripts
|
||||
maxAge: oneYear
|
||||
}));
|
||||
@ -154,7 +161,7 @@ module.exports = function (server) {
|
||||
server.use(manageAdminAndTheme);
|
||||
|
||||
// Admin only config
|
||||
server.use('/ghost', middleware.whenEnabled('admin', express['static'](path.join(corePath, '/client/assets'))));
|
||||
server.use(root + '/ghost', middleware.whenEnabled('admin', express['static'](path.join(corePath, '/client/assets'))));
|
||||
|
||||
// Theme only config
|
||||
server.use(middleware.whenEnabled(server.get('activeTheme'), middleware.staticTheme(ghost)));
|
||||
@ -164,9 +171,10 @@ module.exports = function (server) {
|
||||
|
||||
server.use(express.json());
|
||||
server.use(express.urlencoded());
|
||||
server.use('/ghost/upload/', express.multipart());
|
||||
server.use('/ghost/upload/', express.multipart({uploadDir: corePath + '/content/images'}));
|
||||
server.use('/ghost/api/v0.1/db/', express.multipart());
|
||||
|
||||
server.use(root + '/ghost/upload/', express.multipart());
|
||||
server.use(root + '/ghost/upload/', express.multipart({uploadDir: __dirname + '/content/images'}));
|
||||
server.use(root + '/ghost/api/v0.1/db/', express.multipart());
|
||||
|
||||
// Session handling
|
||||
server.use(express.cookieParser());
|
||||
@ -187,7 +195,7 @@ module.exports = function (server) {
|
||||
server.use(initViews);
|
||||
|
||||
// process the application routes
|
||||
server.use(server.router);
|
||||
server.use(root, server.router);
|
||||
|
||||
// ### Error handling
|
||||
// 404 Handler
|
||||
@ -198,4 +206,4 @@ module.exports = function (server) {
|
||||
};
|
||||
|
||||
// Export middleware functions directly
|
||||
module.exports.middleware = middleware;
|
||||
module.exports.middleware = middleware;
|
||||
|
@ -35,7 +35,7 @@ var middleware = {
|
||||
}
|
||||
redirect = '?r=' + encodeURIComponent(path);
|
||||
}
|
||||
return res.redirect('/ghost/signin/' + redirect);
|
||||
return res.redirect(ghost.blogGlobals().url + '/ghost/signin/' + redirect);
|
||||
}
|
||||
|
||||
next();
|
||||
@ -57,7 +57,7 @@ var middleware = {
|
||||
// Login and signup forms in particular
|
||||
redirectToDashboard: function (req, res, next) {
|
||||
if (req.session.user) {
|
||||
return res.redirect('/ghost/');
|
||||
return res.redirect(ghost.blogGlobals().url + '/ghost/');
|
||||
}
|
||||
|
||||
next();
|
||||
|
@ -1,13 +1,18 @@
|
||||
var admin = require('../controllers/admin'),
|
||||
api = require('../api'),
|
||||
middleware = require('../middleware').middleware;
|
||||
middleware = require('../middleware').middleware,
|
||||
Ghost = require('../../ghost'),
|
||||
url = require('url'),
|
||||
|
||||
ghost = new Ghost();
|
||||
|
||||
// Redirect to signup if no users are currently created
|
||||
function redirectToSignup(req, res, next) {
|
||||
var root = ghost.server.get('ghost root').replace(/\/$/, '');
|
||||
/*jslint unparam:true*/
|
||||
api.users.browse().then(function (users) {
|
||||
if (users.length === 0) {
|
||||
return res.redirect('/ghost/signup/');
|
||||
return res.redirect(root + '/ghost/signup/');
|
||||
}
|
||||
next();
|
||||
}).otherwise(function (err) {
|
||||
@ -16,16 +21,17 @@ function redirectToSignup(req, res, next) {
|
||||
}
|
||||
|
||||
module.exports = function (server) {
|
||||
var root = server.get('ghost root').replace(/\/$/, '');
|
||||
// ### Admin routes
|
||||
/* TODO: put these somewhere in admin */
|
||||
server.get(/^\/logout\/?$/, function redirect(req, res) {
|
||||
server.get(/logout/, function redirect(req, res) {
|
||||
/*jslint unparam:true*/
|
||||
res.redirect(301, '/signout/');
|
||||
res.redirect(301, root + '/signout/');
|
||||
});
|
||||
server.get(/^\/signout\/?$/, admin.logout);
|
||||
server.get(/signout/, admin.logout);
|
||||
server.get('/ghost/login/', function redirect(req, res) {
|
||||
/*jslint unparam:true*/
|
||||
res.redirect(301, '/ghost/signin/');
|
||||
res.redirect(301, root + '/ghost/signin/');
|
||||
});
|
||||
server.get('/ghost/signin/', redirectToSignup, middleware.redirectToDashboard, admin.login);
|
||||
server.get('/ghost/signup/', middleware.redirectToDashboard, admin.signup);
|
||||
@ -46,13 +52,13 @@ module.exports = function (server) {
|
||||
server.post('/ghost/upload/', middleware.auth, admin.uploader);
|
||||
|
||||
// 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) {
|
||||
server.get(/\/((ghost-admin|admin|wp-admin|dashboard|signin)\/?)$/, function (req, res) {
|
||||
/*jslint unparam:true*/
|
||||
res.redirect('/ghost/');
|
||||
res.redirect(root + '/ghost/');
|
||||
});
|
||||
server.get(/^\/(ghost$\/?)/, middleware.auth, function (req, res) {
|
||||
server.get(/\/(ghost$\/?)/, middleware.auth, function (req, res) {
|
||||
/*jslint unparam:true*/
|
||||
res.redirect('/ghost/');
|
||||
res.redirect(root + '/ghost/');
|
||||
});
|
||||
server.get('/ghost/', redirectToSignup, middleware.auth, admin.index);
|
||||
};
|
4
core/shared/vendor/jquery/jquery.js
vendored
4
core/shared/vendor/jquery/jquery.js
vendored
File diff suppressed because one or more lines are too long
@ -30,7 +30,7 @@ describe('Middleware', function () {
|
||||
req.path = '';
|
||||
|
||||
middleware.auth(req, res, null);
|
||||
assert(res.redirect.calledWith('/ghost/signin/'));
|
||||
assert(res.redirect.calledWithMatch('/ghost/signin/'));
|
||||
return done();
|
||||
});
|
||||
|
||||
@ -40,7 +40,7 @@ describe('Middleware', function () {
|
||||
req.path = '/ghost/' + path;
|
||||
|
||||
middleware.auth(req, res, null);
|
||||
assert(res.redirect.calledWith('/ghost/signin/?r=' + encodeURIComponent(path)));
|
||||
assert(res.redirect.calledWithMatch('/ghost/signin/?r=' + encodeURIComponent(path)));
|
||||
return done();
|
||||
});
|
||||
|
||||
@ -50,11 +50,11 @@ describe('Middleware', function () {
|
||||
req.path = '/ghost/' + path;
|
||||
|
||||
middleware.auth(req, res, null);
|
||||
assert(res.redirect.calledWith('/ghost/signin/?r=' + encodeURIComponent(path)));
|
||||
assert(res.redirect.calledWithMatch('/ghost/signin/?r=' + encodeURIComponent(path)));
|
||||
assert.equal(ghost.notifications.length, 1);
|
||||
|
||||
middleware.auth(req, res, null);
|
||||
assert(res.redirect.calledWith('/ghost/signin/?r=' + encodeURIComponent(path)));
|
||||
assert(res.redirect.calledWithMatch('/ghost/signin/?r=' + encodeURIComponent(path)));
|
||||
assert.equal(ghost.notifications.length, 1);
|
||||
|
||||
return done();
|
||||
@ -119,7 +119,7 @@ describe('Middleware', function () {
|
||||
req.session.user = {};
|
||||
|
||||
middleware.redirectToDashboard(req, res, null);
|
||||
assert(res.redirect.calledWith('/ghost/'));
|
||||
assert(res.redirect.calledWithMatch('/ghost/'));
|
||||
return done();
|
||||
});
|
||||
|
||||
|
@ -176,9 +176,9 @@ describe('Core Helpers', function () {
|
||||
|
||||
it('can render class string for context', function (done) {
|
||||
when.all([
|
||||
helpers.body_class.call({path: '/'}),
|
||||
helpers.body_class.call({path: '/a-post-title'}),
|
||||
helpers.body_class.call({path: '/page/4'})
|
||||
helpers.body_class.call({ghostRoot: '/'}),
|
||||
helpers.body_class.call({ghostRoot: '/a-post-title'}),
|
||||
helpers.body_class.call({ghostRoot: '/page/4'})
|
||||
]).then(function (rendered) {
|
||||
rendered.length.should.equal(3);
|
||||
|
||||
@ -196,7 +196,7 @@ describe('Core Helpers', function () {
|
||||
|
||||
it('can render class for static page', function (done) {
|
||||
helpers.body_class.call({
|
||||
path: '/',
|
||||
ghostRoot: '/',
|
||||
post: {
|
||||
page: true
|
||||
}
|
||||
@ -264,7 +264,7 @@ describe('Core Helpers', function () {
|
||||
it('returns meta tag string', function (done) {
|
||||
helpers.ghost_foot.call().then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<script src="/shared/vendor/jquery/jquery.js"></script>');
|
||||
rendered.string.should.match(/<script src=".*\/shared\/vendor\/jquery\/jquery.js"><\/script>/);
|
||||
|
||||
done();
|
||||
});
|
||||
@ -510,7 +510,7 @@ describe('Core Helpers', function () {
|
||||
});
|
||||
|
||||
it('can return blog title', function (done) {
|
||||
helpers.meta_title.call({path: '/'}).then(function (rendered) {
|
||||
helpers.meta_title.call({ghostRoot: '/'}).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('Ghost');
|
||||
|
||||
@ -519,7 +519,7 @@ describe('Core Helpers', function () {
|
||||
});
|
||||
|
||||
it('can return title of a post', function (done) {
|
||||
var post = {path: '/nice-post', post: {title: 'Post Title'}};
|
||||
var post = {ghostRoot: '/nice-post', post: {title: 'Post Title'}};
|
||||
helpers.meta_title.call(post).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('Post Title');
|
||||
@ -536,7 +536,7 @@ describe('Core Helpers', function () {
|
||||
});
|
||||
|
||||
it('can return blog description', function () {
|
||||
helpers.meta_description.call({path: '/'}).then(function (rendered) {
|
||||
helpers.meta_description.call({ghostRoot: '/'}).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('Just a blogging platform.');
|
||||
|
||||
@ -545,7 +545,7 @@ describe('Core Helpers', function () {
|
||||
});
|
||||
|
||||
it('can return empty description on post', function (done) {
|
||||
var post = {path: '/nice-post', post: {title: 'Post Title'}};
|
||||
var post = {ghostRoot: '/nice-post', post: {title: 'Post Title'}};
|
||||
helpers.meta_description.call(post).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('');
|
||||
|
Loading…
Reference in New Issue
Block a user