0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

Merge branch '0.3.2-wip'

Conflicts:
	core/test/unit/api_posts_spec.js
This commit is contained in:
Hannah Wolfe 2013-10-10 16:37:35 +01:00
commit 9466a9753b
13 changed files with 155 additions and 79 deletions

@ -1 +1 @@
Subproject commit c4c276653dc751e50fd927bd8c88a72930f4beff
Subproject commit 10beda3f6c02921fa4644d8b33f30eefbf5af9ca

View file

@ -1,5 +1,5 @@
<a class="permalink{{#if featured}} featured{{/if}}" href="#">
<h3 class="entry-title">{{title}}</h3>
<h3 class="entry-title">{{{title}}}</h3>
<section class="entry-meta">
<time datetime="2013-01-04" class="date">
{{#if published}}

View file

@ -285,6 +285,8 @@
this.$('#entry-title').val(this.model.get('title')).focus();
this.$('#entry-markdown').text(this.model.get('markdown'));
this.listenTo(this.model, 'change:title', this.renderTitle);
this.initMarkdown();
this.renderPreview();
@ -365,6 +367,10 @@
}
},
renderTitle: function () {
this.$('#entry-title').val(this.model.get('title'));
},
// This is a hack to remove iOS6 white space on orientation change bug
// See: http://cl.ly/RGx9
orientationChange: function () {

View file

@ -18,7 +18,7 @@
this.addSubview(this.sidebar);
this.listenTo(Ghost.router, "route:settings", this.changePane);
this.listenTo(Ghost.router, 'route:settings', this.changePane);
},
changePane: function (pane) {
@ -155,7 +155,8 @@
},
saveSettings: function () {
var title = this.$('#blog-title').val(),
var self = this,
title = this.$('#blog-title').val(),
description = this.$('#blog-description').val(),
email = this.$('#email-address').val(),
postsPerPage = this.$('#postsPerPage').val();
@ -186,7 +187,7 @@
}, {
success: this.saveSuccess,
error: this.saveError
});
}).then(function () { self.render(); });
}
},
showLogo: function (e) {
@ -212,8 +213,10 @@
self.model.save(data, {
success: self.saveSuccess,
error: self.saveError
}).then(function () {
self.render();
});
self.render();
return true;
},
buttonClass: "button-save right",
@ -271,8 +274,9 @@
self.model.save(data, {
success: self.saveSuccess,
error: self.saveError
}).then(function () {
self.render();
});
self.render();
return true;
},
buttonClass: "button-save right",
@ -311,7 +315,8 @@
},
saveUser: function () {
var userName = this.$('#user-name').val(),
var self = this,
userName = this.$('#user-name').val(),
userEmail = this.$('#user-email').val(),
userLocation = this.$('#user-location').val(),
userWebsite = this.$('#user-website').val(),
@ -350,6 +355,8 @@
}, {
success: this.saveSuccess,
error: this.saveError
}).then(function () {
self.render();
});
}
},
@ -393,6 +400,8 @@
status: 'passive'
});
}
}).then(function () {
self.render();
});
}
},

View file

@ -41,6 +41,8 @@ function writeConfigFile() {
function validateConfigEnvironment() {
var envVal = process.env.NODE_ENV || 'undefined',
hasHostAndPort,
hasSocket,
config,
parsedUrl;
@ -50,6 +52,7 @@ function validateConfigEnvironment() {
}
// Check if we don't even have a config
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');
@ -69,9 +72,12 @@ function validateConfigEnvironment() {
return when.reject();
}
hasHostAndPort = config.server && !!config.server.host && !!config.server.port;
hasSocket = config.server && !!config.server.socket;
// Check for valid server host and port values
if (!config.server || !config.server.host || !config.server.port) {
errors.logError(new Error('Your server values (host and port) in config.js are invalid.'), JSON.stringify(config.server), 'Please provide them before restarting.');
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();
}

View file

@ -4,6 +4,7 @@ var express = require('express'),
_ = require('underscore'),
colors = require('colors'),
semver = require('semver'),
fs = require('fs'),
slashes = require('connect-slashes'),
errors = require('./server/errorHandling'),
admin = require('./server/controllers/admin'),
@ -366,68 +367,87 @@ when(ghost.init()).then(function () {
server.get('/:slug/', frontend.single);
server.get('/', frontend.homepage);
// Are we using sockets? Custom socket or the default?
function getSocket() {
if (ghost.config().server.hasOwnProperty('socket')) {
return _.isString(ghost.config().server.socket) ? ghost.config().server.socket : path.join(__dirname, '../content/', process.env.NODE_ENV + '.socket');
}
return false;
}
function startGhost() {
// Tell users if their node version is not supported, and exit
if (!semver.satisfies(process.versions.node, packageInfo.engines.node)) {
console.log(
"\nERROR: Unsupported version of Node".red,
"\nGhost needs Node version".red,
packageInfo.engines.node.yellow,
"you are using version".red,
process.versions.node.yellow,
"\nPlease go to http://nodejs.org to get the latest version".green
);
process.exit(0);
}
// Startup & Shutdown messages
if (process.env.NODE_ENV === 'production') {
console.log(
"Ghost is running...".green,
"\nYour blog is now available on",
ghost.config().url,
"\nCtrl+C to shut down".grey
);
// ensure that Ghost exits correctly on Ctrl+C
process.on('SIGINT', function () {
console.log(
"\nGhost has shut down".red,
"\nYour blog is now offline"
);
process.exit(0);
});
} else {
console.log(
"Ghost is running...".green,
"\nListening on",
getSocket() || ghost.config().server.host + ':' + ghost.config().server.port,
"\nUrl configured as:",
ghost.config().url,
"\nCtrl+C to shut down".grey
);
// ensure that Ghost exits correctly on Ctrl+C
process.on('SIGINT', function () {
console.log(
"\nGhost has shutdown".red,
"\nGhost was running for",
Math.round(process.uptime()),
"seconds"
);
process.exit(0);
});
}
// Let everyone know we have finished loading
loading.resolve();
}
// ## Start Ghost App
server.listen(
ghost.config().server.port,
ghost.config().server.host,
function () {
if (getSocket()) {
// Make sure the socket is gone before trying to create another
fs.unlink(getSocket(), function (err) {
server.listen(
getSocket(),
startGhost
);
fs.chmod(getSocket(), '0744');
});
// Tell users if their node version is not supported, and exit
if (!semver.satisfies(process.versions.node, packageInfo.engines.node)) {
console.log(
"\nERROR: Unsupported version of Node".red,
"\nGhost needs Node version".red,
packageInfo.engines.node.yellow,
"you are using version".red,
process.versions.node.yellow,
"\nPlease go to http://nodejs.org to get the latest version".green
);
process.exit(0);
}
// Startup & Shutdown messages
if (process.env.NODE_ENV === 'production') {
console.log(
"Ghost is running...".green,
"\nYour blog is now available on",
ghost.config().url,
"\nCtrl+C to shut down".grey
);
// ensure that Ghost exits correctly on Ctrl+C
process.on('SIGINT', function () {
console.log(
"\nGhost has shut down".red,
"\nYour blog is now offline"
);
process.exit(0);
});
} else {
console.log(
"Ghost is running...".green,
"\nListening on",
ghost.config().server.host + ':' + ghost.config().server.port,
"\nUrl configured as:",
ghost.config().url,
"\nCtrl+C to shut down".grey
);
// ensure that Ghost exits correctly on Ctrl+C
process.on('SIGINT', function () {
console.log(
"\nGhost has shutdown".red,
"\nGhost was running for",
Math.round(process.uptime()),
"seconds"
);
process.exit(0);
});
}
// Let everyone know we have finished loading
loading.resolve();
}
);
} else {
server.listen(
ghost.config().server.port,
ghost.config().server.host,
startGhost
);
}
}, errors.logAndThrowError);

View file

@ -191,7 +191,9 @@ coreHelpers = function (ghost) {
});
ghost.registerThemeHelper('body_class', function (options) {
var classes = [];
var classes = [],
tags = this.post && this.post.tags ? this.post.tags : this.tags || [];
if (_.isString(this.path) && this.path.match(/\/page/)) {
classes.push('archive-template');
} else if (!this.path || this.path === '/' || this.path === '') {
@ -200,6 +202,10 @@ coreHelpers = function (ghost) {
classes.push('post-template');
}
if (tags) {
classes = classes.concat(tags.map(function (tag) { return 'tag-' + tag.slug; }));
}
return ghost.doFilter('body_class', classes, function (classes) {
var classString = _.reduce(classes, function (memo, item) { return memo + ' ' + item; }, '');
return new hbs.handlebars.SafeString(classString.trim());
@ -207,10 +213,11 @@ coreHelpers = function (ghost) {
});
ghost.registerThemeHelper('post_class', function (options) {
var classes = ['post'];
var classes = ['post'],
tags = this.post && this.post.tags ? this.post.tags : this.tags || [];
if (this.tags) {
classes = classes.concat(this.tags.map(function (tag) { return 'tag-' + tag.name; }));
if (tags) {
classes = classes.concat(tags.map(function (tag) { return 'tag-' + tag.slug; }));
}
return ghost.doFilter('post_class', classes, function (classes) {

View file

@ -1,7 +1,7 @@
<nav id="site-navigation" role="navigation">
<ul>
{{#links}}
<li class="{{#active}}current-menu-item{{/active}}"><a title="{{title}}" href="{{url}}">{{title}}</a></li>
<li class="{{#active}}current-menu-item{{/active}}"><a title="{{{title}}}" href="{{url}}">{{{title}}}</a></li>
{{/links}}
</ul>
</nav>

View file

@ -5,7 +5,8 @@ var GhostBookshelf,
_ = require('underscore'),
uuid = require('node-uuid'),
config = require('../../../config'),
Validator = require('validator').Validator;
Validator = require('validator').Validator,
sanitize = require('validator').sanitize;
// Initializes Bookshelf as its own instance, so we can modify the Models and not mess up
// others' if they're using the library outside of ghost.
@ -78,6 +79,10 @@ GhostBookshelf.Model = GhostBookshelf.Model.extend({
return attrs;
},
sanitize: function (attr) {
return sanitize(this.get(attr)).xss();
},
// #### generateSlug
// Create a string act as the permalink for an object.
generateSlug: function (Model, base) {

View file

@ -51,7 +51,7 @@ Post = GhostBookshelf.Model.extend({
this.set('html', converter.makeHtml(this.get('markdown')));
this.set('title', this.get('title').trim());
this.set('title', this.sanitize('title').trim());
if (this.hasChanged('status') && this.get('status') === 'published') {
if (!this.get('published_at')) {

View file

@ -73,7 +73,19 @@ Settings = GhostBookshelf.Model.extend({
validation[validationName].apply(validation, validationOptions);
}, this);
}
},
saving: function () {
// All blog setting keys that need their values to be escaped.
if (this.get('type') === 'blog' && _.contains(['title', 'description', 'email'], this.get('key'))) {
this.set('value', this.sanitize('value'));
}
return GhostBookshelf.Model.prototype.saving.apply(this, arguments);
}
}, {
read: function (_key) {
// Allow for just passing the key instead of attributes

View file

@ -55,6 +55,17 @@ User = GhostBookshelf.Model.extend({
}
},
saving: function () {
this.set('name', this.sanitize('name'));
this.set('email', this.sanitize('email'));
this.set('location', this.sanitize('location'));
this.set('website', this.sanitize('website'));
this.set('bio', this.sanitize('bio'));
return GhostBookshelf.Model.prototype.saving.apply(this, arguments);
},
posts: function () {
return this.hasMany(Posts, 'created_by');
},

View file

@ -11,8 +11,8 @@
},
"engineStrict": true,
"dependencies": {
"express": "3.3.4",
"express-hbs": "0.2.2",
"express": "3.4.0",
"express-hbs": "0.3.0",
"connect-slashes": "0.0.9",
"node-polyglot": "0.2.1",
"moment": "2.1.0",