mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-30 21:40:39 +03:00
Merge pull request #4001 from hswolff/jscs
Add jscs task to grunt file and clean up files to adhere to jscs rules
This commit is contained in:
commit
c38c0cdfe1
72
.jscsrc
Normal file
72
.jscsrc
Normal file
@ -0,0 +1,72 @@
|
||||
{
|
||||
"requireCurlyBraces": [
|
||||
"if",
|
||||
"else",
|
||||
"for",
|
||||
"while",
|
||||
"do",
|
||||
"try",
|
||||
"catch"
|
||||
],
|
||||
"requireSpaceAfterKeywords": [
|
||||
"if",
|
||||
"else",
|
||||
"for",
|
||||
"while",
|
||||
"do",
|
||||
"switch",
|
||||
"case",
|
||||
"return",
|
||||
"try",
|
||||
"catch",
|
||||
"function",
|
||||
"typeof"
|
||||
],
|
||||
"requireSpaceBeforeBlockStatements": true,
|
||||
"requireParenthesesAroundIIFE": true,
|
||||
"requireSpacesInConditionalExpression": true,
|
||||
"disallowSpacesInNamedFunctionExpression": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInFunctionDeclaration": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"requireMultipleVarDecl": "onevar",
|
||||
"requireBlocksOnNewline": 1,
|
||||
"disallowPaddingNewlinesInBlocks": true,
|
||||
"disallowEmptyBlocks": true,
|
||||
"disallowSpacesInsideObjectBrackets": "all",
|
||||
"disallowSpacesInsideArrayBrackets": true,
|
||||
"disallowSpacesInsideParentheses": true,
|
||||
"disallowQuotedKeysInObjects": true,
|
||||
"disallowSpaceAfterObjectKeys": true,
|
||||
"requireCommaBeforeLineBreak": true,
|
||||
"disallowSpaceAfterPrefixUnaryOperators": true,
|
||||
"disallowSpaceBeforePostfixUnaryOperators": true,
|
||||
"disallowSpaceBeforeBinaryOperators": [
|
||||
","
|
||||
],
|
||||
"requireSpaceBeforeBinaryOperators": true,
|
||||
"requireSpaceAfterBinaryOperators": true,
|
||||
"requireCamelCaseOrUpperCaseIdentifiers": "ignoreProperties",
|
||||
"disallowKeywords": [ "with" ],
|
||||
"disallowMultipleLineBreaks": true,
|
||||
"validateQuoteMarks": "'",
|
||||
"validateIndentation": 4,
|
||||
"disallowMixedSpacesAndTabs": true,
|
||||
"disallowTrailingWhitespace": true,
|
||||
"disallowTrailingComma": true,
|
||||
"disallowKeywordsOnNewLine": [ "else" ],
|
||||
"requireLineFeedAtFileEnd": true,
|
||||
"requireCapitalizedConstructors": true,
|
||||
"safeContextKeyword": ["self"],
|
||||
"requireDotNotation": true,
|
||||
"disallowYodaConditions": true,
|
||||
"validateJSDoc": {
|
||||
"checkParamNames": true,
|
||||
"checkRedundantParams": true,
|
||||
"requireParamTypes": true
|
||||
},
|
||||
"requireSpaceAfterLineComment": true,
|
||||
"disallowNewlineBeforeBlockStatements": true
|
||||
}
|
146
Gruntfile.js
146
Gruntfile.js
@ -32,10 +32,47 @@ var _ = require('lodash'),
|
||||
});
|
||||
}()),
|
||||
|
||||
// ## List of files we want to lint through jshint and jscs to make sure
|
||||
// they conform to our desired code styles.
|
||||
lintFiles = {
|
||||
// Linting files for server side or shared javascript code.
|
||||
server: {
|
||||
files: {
|
||||
src: [
|
||||
'*.js',
|
||||
'!config*.js', // note: i added this, do we want this linted?
|
||||
'core/*.js',
|
||||
'core/server/**/*.js',
|
||||
'core/shared/**/*.js',
|
||||
'!core/shared/vendor/**/*.js',
|
||||
'!core/shared/lib/**/*.js'
|
||||
]
|
||||
}
|
||||
},
|
||||
// Linting files for client side javascript code.
|
||||
client: {
|
||||
files: {
|
||||
src: [
|
||||
'core/client/**/*.js',
|
||||
'!core/client/docs/js/*.js',
|
||||
'!core/client/assets/vendor/**/*.js',
|
||||
'!core/client/tpl/**/*.js'
|
||||
]
|
||||
}
|
||||
},
|
||||
// Linting files for test code.
|
||||
test: {
|
||||
files: {
|
||||
src: [
|
||||
'core/test/**/*.js'
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// ## Grunt configuration
|
||||
|
||||
configureGrunt = function (grunt) {
|
||||
|
||||
// *This is not useful but required for jshint*
|
||||
colors.setTheme({silly: 'rainbow'});
|
||||
|
||||
@ -65,7 +102,7 @@ var _ = require('lodash'),
|
||||
files: ['core/shared/**/*.js'],
|
||||
tasks: ['concat:dev']
|
||||
},
|
||||
'emberTemplates': {
|
||||
emberTemplates: {
|
||||
files: ['core/client/**/*.hbs'],
|
||||
tasks: ['emberTemplates:dev']
|
||||
},
|
||||
@ -121,49 +158,56 @@ var _ = require('lodash'),
|
||||
// ### grunt-contrib-jshint
|
||||
// Linting rules, run as part of `grunt validate`. See [grunt validate](#validate) and its subtasks for
|
||||
// more information.
|
||||
jshint: {
|
||||
// Linting rules for server side or shared javascript code
|
||||
server: {
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
jshint: (function () {
|
||||
return _.merge({
|
||||
server: {
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
}
|
||||
},
|
||||
files: {
|
||||
src: [
|
||||
'*.js',
|
||||
'core/*.js',
|
||||
'core/server/**/*.js',
|
||||
'core/shared/**/*.js',
|
||||
'!core/shared/vendor/**/*.js',
|
||||
'!core/shared/lib/**/*.js'
|
||||
]
|
||||
}
|
||||
},
|
||||
// Linting rules for client side javascript code
|
||||
client: {
|
||||
options: {
|
||||
jshintrc: 'core/client/.jshintrc'
|
||||
client: {
|
||||
options: {
|
||||
jshintrc: 'core/client/.jshintrc'
|
||||
}
|
||||
},
|
||||
files: {
|
||||
src: [
|
||||
'core/client/**/*.js',
|
||||
'!core/client/docs/js/*.js',
|
||||
'!core/client/assets/vendor/**/*.js',
|
||||
'!core/client/tpl/**/*.js'
|
||||
]
|
||||
test: {
|
||||
options: {
|
||||
jshintrc: 'core/test/.jshintrc'
|
||||
}
|
||||
}
|
||||
},
|
||||
}, lintFiles);
|
||||
})(),
|
||||
|
||||
test: {
|
||||
options: {
|
||||
jshintrc: 'core/test/.jshintrc'
|
||||
// ### grunt-jscs
|
||||
// Code style rules, run as part of `grunt validate`. See [grunt validate](#validate) and its subtasks for
|
||||
// more information.
|
||||
jscs: (function () {
|
||||
var jscsConfig = _.merge({
|
||||
server: {
|
||||
options: {
|
||||
config: '.jscsrc'
|
||||
}
|
||||
},
|
||||
files: {
|
||||
src: [
|
||||
'core/test/**/*.js'
|
||||
]
|
||||
client: {
|
||||
options: {
|
||||
config: '.jscsrc'
|
||||
}
|
||||
},
|
||||
test: {
|
||||
options: {
|
||||
config: '.jscsrc'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}, lintFiles);
|
||||
|
||||
// JSCS depends on Esprima which doesn't yet support ES6 module
|
||||
// syntax. As such we cannot run JSCS on the client code yet.
|
||||
// Related JSCS issue: https://github.com/jscs-dev/node-jscs/issues/561
|
||||
// @TODO(hswolff): remove this once JSCS supports ES6.
|
||||
delete jscsConfig.client;
|
||||
|
||||
return jscsConfig;
|
||||
})(),
|
||||
|
||||
// ### grunt-mocha-cli
|
||||
// Configuration for the mocha test runner, used to run unit, integration and route tests as part of
|
||||
@ -280,7 +324,7 @@ var _ = require('lodash'),
|
||||
options: {
|
||||
silent: true, // suppress logging
|
||||
map: true, // Use and update the sourcemap
|
||||
browsers: ["last 2 versions", "> 1%", "Explorer 10"]
|
||||
browsers: ['last 2 versions', '> 1%', 'Explorer 10']
|
||||
},
|
||||
single_file: {
|
||||
src: 'core/client/assets/css/<%= pkg.name %>.min.css',
|
||||
@ -288,7 +332,6 @@ var _ = require('lodash'),
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// ### grunt-ember-templates
|
||||
// Compiles handlebar templates for ember
|
||||
emberTemplates: {
|
||||
@ -320,7 +363,7 @@ var _ = require('lodash'),
|
||||
files: {
|
||||
'core/built/scripts/templates.js': 'core/client/templates/**/*.hbs'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
// ### grunt-es6-module-transpiler
|
||||
@ -460,7 +503,7 @@ var _ = require('lodash'),
|
||||
// ### grunt-contrib-concat
|
||||
// concatenate multiple JS files into a single file ready for use
|
||||
concat: {
|
||||
'dev': {
|
||||
dev: {
|
||||
nonull: true,
|
||||
dest: 'core/built/scripts/vendor-dev.js',
|
||||
src: [
|
||||
@ -492,12 +535,12 @@ var _ = require('lodash'),
|
||||
|
||||
'core/shared/lib/showdown/extensions/ghostimagepreview.js',
|
||||
'core/shared/lib/showdown/extensions/ghostgfm.js',
|
||||
|
||||
|
||||
'core/shared/lib/nanoscroller/nanoscroller.js'
|
||||
]
|
||||
},
|
||||
|
||||
'prod': {
|
||||
prod: {
|
||||
nonull: true,
|
||||
dest: 'core/built/scripts/vendor.js',
|
||||
src: [
|
||||
@ -529,7 +572,7 @@ var _ = require('lodash'),
|
||||
|
||||
'core/shared/lib/showdown/extensions/ghostimagepreview.js',
|
||||
'core/shared/lib/showdown/extensions/ghostgfm.js',
|
||||
|
||||
|
||||
'core/shared/lib/nanoscroller/nanoscroller.js'
|
||||
]
|
||||
}
|
||||
@ -562,7 +605,7 @@ var _ = require('lodash'),
|
||||
|
||||
// ### grunt-update-submodules
|
||||
// Grunt task to update git submodules
|
||||
'update_submodules': {
|
||||
update_submodules: {
|
||||
default: {
|
||||
options: {
|
||||
params: '--init'
|
||||
@ -580,7 +623,6 @@ var _ = require('lodash'),
|
||||
// Custom test runner for our Casper.js functional tests
|
||||
// This really ought to be refactored into a separate grunt task module
|
||||
grunt.registerTask('spawnCasperJS', function (target) {
|
||||
|
||||
target = _.contains(['client', 'frontend', 'setup'], target) ? target + '/' : undefined;
|
||||
|
||||
var done = this.async(),
|
||||
@ -650,7 +692,6 @@ var _ = require('lodash'),
|
||||
// Run `grunt docs` to generate annotated source code using the documentation described in the code comments.
|
||||
grunt.registerTask('docs', 'Generate Docs', ['docker']);
|
||||
|
||||
|
||||
// ## Testing
|
||||
|
||||
// Ghost has an extensive set of test suites. The following section documents the various types of tests
|
||||
@ -719,11 +760,11 @@ var _ = require('lodash'),
|
||||
//
|
||||
// `grunt test` will lint and test your pre-built local Ghost codebase.
|
||||
//
|
||||
// `grunt test` runs jshint as well as the 4 test suites. See the individual sub tasks below for details of
|
||||
// `grunt test` runs jshint and jscs as well as the 4 test suites. See the individual sub tasks below for details of
|
||||
// each of the test suites.
|
||||
//
|
||||
grunt.registerTask('test', 'Run tests and lint code',
|
||||
['jshint', 'test-routes', 'test-unit', 'test-integration', 'test-functional']);
|
||||
['jshint', 'jscs', 'test-routes', 'test-unit', 'test-integration', 'test-functional']);
|
||||
|
||||
// ### Unit Tests *(sub task)*
|
||||
// `grunt test-unit` will run just the unit tests
|
||||
@ -840,7 +881,6 @@ var _ = require('lodash'),
|
||||
grunt.registerTask('test-coverage', 'Generate unit and integration (mocha) tests coverage report',
|
||||
['clean:test', 'setTestEnv', 'ensureConfig', 'shell:coverage']);
|
||||
|
||||
|
||||
// ## Building assets
|
||||
//
|
||||
// Ghost's GitHub repository contains the un-built source code for Ghost. If you're looking for the already
|
||||
@ -921,7 +961,7 @@ var _ = require('lodash'),
|
||||
|
||||
grunt.verbose.writeln('Creating contributors template.');
|
||||
grunt.file.write(templatePath,
|
||||
//Map contributors to the template.
|
||||
// Map contributors to the template.
|
||||
_.map(contributors, function (contributor) {
|
||||
return contributorTemplate
|
||||
.replace(/<%githubUrl%>/g, contributor.githubUrl)
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Loader to create the Ember.js application
|
||||
/*global require */
|
||||
|
||||
window.App = require('ghost/app')['default'].create();
|
||||
window.App = require('ghost/app')['default'].create();
|
||||
|
@ -31,12 +31,12 @@ GhostServer.prototype.logStartMessages = function () {
|
||||
// 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,
|
||||
'\nERROR: Unsupported version of Node'.red,
|
||||
'\nGhost needs Node version'.red,
|
||||
packageInfo.engines.node.yellow,
|
||||
"you are using version".red,
|
||||
'you are using version'.red,
|
||||
process.versions.node.yellow,
|
||||
"\nPlease go to http://nodejs.org to get a supported version".green
|
||||
'\nPlease go to http://nodejs.org to get a supported version'.green
|
||||
);
|
||||
|
||||
process.exit(0);
|
||||
@ -45,36 +45,36 @@ GhostServer.prototype.logStartMessages = function () {
|
||||
// Startup & Shutdown messages
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
console.log(
|
||||
"Ghost is running...".green,
|
||||
"\nYour blog is now available on",
|
||||
'Ghost is running...'.green,
|
||||
'\nYour blog is now available on',
|
||||
config.url,
|
||||
"\nCtrl+C to shut down".grey
|
||||
'\nCtrl+C to shut down'.grey
|
||||
);
|
||||
|
||||
// ensure that Ghost exits correctly on Ctrl+C
|
||||
process.removeAllListeners('SIGINT').on('SIGINT', function () {
|
||||
console.log(
|
||||
"\nGhost has shut down".red,
|
||||
"\nYour blog is now offline"
|
||||
'\nGhost has shut down'.red,
|
||||
'\nYour blog is now offline'
|
||||
);
|
||||
process.exit(0);
|
||||
});
|
||||
} else {
|
||||
console.log(
|
||||
("Ghost is running in " + process.env.NODE_ENV + "...").green,
|
||||
"\nListening on",
|
||||
('Ghost is running in ' + process.env.NODE_ENV + '...').green,
|
||||
'\nListening on',
|
||||
config.getSocket() || config.server.host + ':' + config.server.port,
|
||||
"\nUrl configured as:",
|
||||
'\nUrl configured as:',
|
||||
config.url,
|
||||
"\nCtrl+C to shut down".grey
|
||||
'\nCtrl+C to shut down'.grey
|
||||
);
|
||||
// ensure that Ghost exits correctly on Ctrl+C
|
||||
process.removeAllListeners('SIGINT').on('SIGINT', function () {
|
||||
console.log(
|
||||
"\nGhost has shutdown".red,
|
||||
"\nGhost was running for",
|
||||
'\nGhost has shutdown'.red,
|
||||
'\nGhost was running for',
|
||||
Math.round(process.uptime()),
|
||||
"seconds"
|
||||
'seconds'
|
||||
);
|
||||
process.exit(0);
|
||||
});
|
||||
@ -115,7 +115,6 @@ GhostServer.prototype.start = function (externalApp) {
|
||||
);
|
||||
|
||||
fs.chmod(config.getSocket(), '0660');
|
||||
|
||||
} else {
|
||||
self.httpServer = app.listen(
|
||||
config.server.port,
|
||||
|
@ -20,7 +20,7 @@ authentication = {
|
||||
/**
|
||||
* ## Generate Reset Token
|
||||
* generate a reset token for a given email address
|
||||
* @param {{passwordreset}}
|
||||
* @param {Object} object
|
||||
* @returns {Promise(passwordreset)} message
|
||||
*/
|
||||
generateResetToken: function generateResetToken(object) {
|
||||
@ -42,7 +42,7 @@ authentication = {
|
||||
return Promise.reject(new errors.BadRequestError('No email provided.'));
|
||||
}
|
||||
|
||||
return users.read({ context: {internal: true}, email: email, status: 'active' }).then(function () {
|
||||
return users.read({context: {internal: true}, email: email, status: 'active'}).then(function () {
|
||||
return settings.read({context: {internal: true}, key: 'dbHash'});
|
||||
}).then(function (response) {
|
||||
var dbHash = response.settings[0].value;
|
||||
@ -51,7 +51,7 @@ authentication = {
|
||||
var baseUrl = config.forceAdminSSL ? (config.urlSSL || config.url) : config.url,
|
||||
resetUrl = baseUrl.replace(/\/$/, '') + '/ghost/reset/' + resetToken + '/';
|
||||
|
||||
return mail.generateContent({data: { resetUrl: resetUrl }, template: 'reset-password'});
|
||||
return mail.generateContent({data: {resetUrl: resetUrl}, template: 'reset-password'});
|
||||
}).then(function (emailContent) {
|
||||
var payload = {
|
||||
mail: [{
|
||||
@ -76,7 +76,7 @@ authentication = {
|
||||
/**
|
||||
* ## Reset Password
|
||||
* reset password if a valid token and password (2x) is passed
|
||||
* @param {{passwordreset}}
|
||||
* @param {Object} object
|
||||
* @returns {Promise(passwordreset)} message
|
||||
*/
|
||||
resetPassword: function resetPassword(object) {
|
||||
@ -150,14 +150,14 @@ authentication = {
|
||||
|
||||
isSetup: function () {
|
||||
return dataProvider.User.query(function (qb) {
|
||||
qb.whereIn('status', ['active', 'warn-1', 'warn-2', 'warn-3', 'warn-4', 'locked']);
|
||||
}).fetch().then(function (users) {
|
||||
if (users) {
|
||||
return Promise.resolve({ setup: [{status: true}]});
|
||||
} else {
|
||||
return Promise.resolve({ setup: [{status: false}]});
|
||||
}
|
||||
});
|
||||
qb.whereIn('status', ['active', 'warn-1', 'warn-2', 'warn-3', 'warn-4', 'locked']);
|
||||
}).fetch().then(function (users) {
|
||||
if (users) {
|
||||
return Promise.resolve({setup: [{status: true}]});
|
||||
} else {
|
||||
return Promise.resolve({setup: [{status: false}]});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setup: function (object) {
|
||||
@ -226,13 +226,12 @@ authentication = {
|
||||
return mail.send(payload, {context: {internal: true}}).catch(function (error) {
|
||||
errors.logError(
|
||||
error.message,
|
||||
"Unable to send welcome email, your blog will continue to function.",
|
||||
"Please see http://support.ghost.org/mail/ for instructions on configuring email."
|
||||
'Unable to send welcome email, your blog will continue to function.',
|
||||
'Please see http://support.ghost.org/mail/ for instructions on configuring email.'
|
||||
);
|
||||
});
|
||||
|
||||
}).then(function () {
|
||||
return Promise.resolve({ users: [setupUser]});
|
||||
return Promise.resolve({users: [setupUser]});
|
||||
});
|
||||
},
|
||||
|
||||
@ -247,11 +246,11 @@ authentication = {
|
||||
return errors.BadRequestError('Invalid token_type_hint given.');
|
||||
}
|
||||
|
||||
return token.destroyByToken({ token: object.token }).then(function () {
|
||||
return Promise.resolve({ token: object.token });
|
||||
return token.destroyByToken({token: object.token}).then(function () {
|
||||
return Promise.resolve({token: object.token});
|
||||
}, function () {
|
||||
// On error we still want a 200. See https://tools.ietf.org/html/rfc7009#page-5
|
||||
return Promise.resolve({ token: object.token, error: 'Invalid token provided' });
|
||||
return Promise.resolve({token: object.token, error: 'Invalid token provided'});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -10,13 +10,13 @@ var _ = require('lodash'),
|
||||
|
||||
function getValidKeys() {
|
||||
var validKeys = {
|
||||
'fileStorage': config.fileStorage === false ? false : true,
|
||||
'apps': config.apps === true ? true : false,
|
||||
'version': false,
|
||||
'environment': process.env.NODE_ENV,
|
||||
'database': config.database.client,
|
||||
'mail': _.isObject(config.mail) ? config.mail.transport : '',
|
||||
'blogUrl': config.url
|
||||
fileStorage: config.fileStorage === false ? false : true,
|
||||
apps: config.apps === true ? true : false,
|
||||
version: false,
|
||||
environment: process.env.NODE_ENV,
|
||||
database: config.database.client,
|
||||
mail: _.isObject(config.mail) ? config.mail.transport : '',
|
||||
blogUrl: config.url
|
||||
};
|
||||
|
||||
return parsePackageJson('package.json').then(function (json) {
|
||||
@ -39,7 +39,7 @@ configuration = {
|
||||
*/
|
||||
browse: function browse() {
|
||||
return getValidKeys().then(function (result) {
|
||||
return Promise.resolve({ 'configuration': _.map(result, function (value, key) {
|
||||
return Promise.resolve({configuration: _.map(result, function (value, key) {
|
||||
return {
|
||||
key: key,
|
||||
value: value
|
||||
@ -55,7 +55,7 @@ configuration = {
|
||||
read: function read(options) {
|
||||
return getValidKeys().then(function (result) {
|
||||
if (_.has(result, options.key)) {
|
||||
return Promise.resolve({ 'configuration': [{
|
||||
return Promise.resolve({configuration: [{
|
||||
key: options.key,
|
||||
value: result[options.key]
|
||||
}]});
|
||||
|
@ -14,7 +14,6 @@ var dataExport = require('../data/export'),
|
||||
|
||||
api.settings = require('./settings');
|
||||
|
||||
|
||||
function isValidFile(ext) {
|
||||
if (ext === '.json') {
|
||||
return true;
|
||||
@ -35,19 +34,19 @@ db = {
|
||||
* @param {{context}} options
|
||||
* @returns {Promise} Ghost Export JSON format
|
||||
*/
|
||||
'exportContent': function (options) {
|
||||
exportContent: function (options) {
|
||||
options = options || {};
|
||||
|
||||
// Export data, otherwise send error 500
|
||||
return canThis(options.context).exportContent.db().then(function () {
|
||||
return dataExport().then(function (exportedData) {
|
||||
return { db: [exportedData] };
|
||||
}).catch(function (error) {
|
||||
return Promise.reject(new errors.InternalServerError(error.message || error));
|
||||
});
|
||||
}, function () {
|
||||
return Promise.reject(new errors.NoPermissionError('You do not have permission to export data. (no rights)'));
|
||||
return dataExport().then(function (exportedData) {
|
||||
return {db: [exportedData]};
|
||||
}).catch(function (error) {
|
||||
return Promise.reject(new errors.InternalServerError(error.message || error));
|
||||
});
|
||||
}, function () {
|
||||
return Promise.reject(new errors.NoPermissionError('You do not have permission to export data. (no rights)'));
|
||||
});
|
||||
},
|
||||
/**
|
||||
* ### Import Content
|
||||
@ -57,7 +56,7 @@ db = {
|
||||
* @param {{context}} options
|
||||
* @returns {Promise} Success
|
||||
*/
|
||||
'importContent': function (options) {
|
||||
importContent: function (options) {
|
||||
options = options || {};
|
||||
var databaseVersion,
|
||||
type,
|
||||
@ -79,7 +78,7 @@ db = {
|
||||
}
|
||||
}).then(function () {
|
||||
return api.settings.read(
|
||||
{key: 'databaseVersion', context: { internal: true }}
|
||||
{key: 'databaseVersion', context: {internal: true}}
|
||||
).then(function (response) {
|
||||
var setting = response.settings[0];
|
||||
|
||||
@ -113,9 +112,8 @@ db = {
|
||||
|
||||
// Import for the current version
|
||||
return dataImport(databaseVersion, importData);
|
||||
|
||||
}).then(api.settings.updateSettingsCache)
|
||||
.return({ db: [] })
|
||||
.return({db: []})
|
||||
.finally(function () {
|
||||
// Unlink the file after import
|
||||
return Promise.promisify(fs.unlink)(filepath);
|
||||
@ -132,12 +130,12 @@ db = {
|
||||
* @param {{context}} options
|
||||
* @returns {Promise} Success
|
||||
*/
|
||||
'deleteAllContent': function (options) {
|
||||
deleteAllContent: function (options) {
|
||||
options = options || {};
|
||||
|
||||
return canThis(options.context).deleteAllContent.db().then(function () {
|
||||
return Promise.resolve(dataProvider.deleteAllContent())
|
||||
.return({ db: [] })
|
||||
.return({db: []})
|
||||
.catch(function (error) {
|
||||
return Promise.reject(new errors.InternalServerError(error.message || error));
|
||||
});
|
||||
|
@ -146,7 +146,6 @@ contentDispositionHeader = function () {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* ### Format HTTP Errors
|
||||
* Converts the error response from the API into a format which can be returned over HTTP
|
||||
@ -166,7 +165,7 @@ formatHttpErrors = function (error) {
|
||||
_.each(error, function (errorItem) {
|
||||
var errorContent = {};
|
||||
|
||||
//TODO: add logic to set the correct status code
|
||||
// TODO: add logic to set the correct status code
|
||||
statusCode = errorItem.code || 500;
|
||||
|
||||
errorContent.message = _.isString(errorItem) ? errorItem :
|
||||
@ -178,7 +177,6 @@ formatHttpErrors = function (error) {
|
||||
return {errors: errors, statusCode: statusCode};
|
||||
};
|
||||
|
||||
|
||||
addHeaders = function (apiMethod, req, res, result) {
|
||||
var ops = [],
|
||||
cacheInvalidation,
|
||||
@ -198,7 +196,7 @@ addHeaders = function (apiMethod, req, res, result) {
|
||||
location = locationHeader(req, result)
|
||||
.then(function addLocationHeader(header) {
|
||||
if (header) {
|
||||
res.set({'Location': header});
|
||||
res.set({Location: header});
|
||||
// The location header indicates that a new object was created.
|
||||
// In this case the status code should be 201 Created
|
||||
res.status(201);
|
||||
|
@ -45,7 +45,6 @@ mail = {
|
||||
.catch(function (error) {
|
||||
return Promise.reject(new errors.EmailError(error.message));
|
||||
});
|
||||
|
||||
}, function () {
|
||||
return Promise.reject(new errors.NoPermissionError('You do not have permission to send mail.'));
|
||||
});
|
||||
@ -56,7 +55,7 @@ mail = {
|
||||
* Send a test email
|
||||
*
|
||||
* @public
|
||||
* @param {Object} required property 'to' which contains the recipient address
|
||||
* @param {Object} options required property 'to' which contains the recipient address
|
||||
* @returns {Promise}
|
||||
*/
|
||||
sendTest: function (options) {
|
||||
@ -79,14 +78,13 @@ mail = {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {
|
||||
* @param {Object} options {
|
||||
* data: JSON object representing the data that will go into the email
|
||||
* template: which email template to load (files are stored in /core/server/email-templates/)
|
||||
* }
|
||||
* @returns {*}
|
||||
*/
|
||||
generateContent: function (options) {
|
||||
|
||||
var defaultData = {
|
||||
siteUrl: config.forceAdminSSL ? (config.urlSSL || config.url) : config.url
|
||||
},
|
||||
@ -94,28 +92,26 @@ mail = {
|
||||
|
||||
_.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
|
||||
|
||||
//read the proper email body template
|
||||
// read the proper email body template
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.readFile(templatesDir + '/' + options.template + '.html', {encoding: 'utf8'}, function (err, fileContent) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
//insert user-specific data into the email
|
||||
// insert user-specific data into the email
|
||||
var htmlContent = _.template(fileContent, emailData),
|
||||
textContent;
|
||||
|
||||
//generate a plain-text version of the same email
|
||||
// generate a plain-text version of the same email
|
||||
textContent = htmlToText.fromString(htmlContent);
|
||||
|
||||
resolve({
|
||||
html: htmlContent,
|
||||
text: textContent
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -26,7 +26,7 @@ notifications = {
|
||||
*/
|
||||
browse: function browse(options) {
|
||||
return canThis(options.context).browse.notification().then(function () {
|
||||
return { 'notifications': notificationsStore };
|
||||
return {notifications: notificationsStore};
|
||||
}, function () {
|
||||
return Promise.reject(new errors.NoPermissionError('You do not have permission to browse notifications.'));
|
||||
});
|
||||
@ -47,7 +47,6 @@ notifications = {
|
||||
* ```
|
||||
*/
|
||||
add: function add(object, options) {
|
||||
|
||||
var defaults = {
|
||||
dismissible: true,
|
||||
location: 'bottom',
|
||||
@ -62,14 +61,14 @@ notifications = {
|
||||
|
||||
notification = _.assign(defaults, notification, {
|
||||
id: notificationCounter
|
||||
//status: 'persistent'
|
||||
// status: 'persistent'
|
||||
});
|
||||
|
||||
notificationsStore.push(notification);
|
||||
addedNotifications.push(notification);
|
||||
});
|
||||
|
||||
return { notifications: addedNotifications };
|
||||
return {notifications: addedNotifications};
|
||||
});
|
||||
}, function () {
|
||||
return Promise.reject(new errors.NoPermissionError('You do not have permission to add notifications.'));
|
||||
@ -102,7 +101,7 @@ notifications = {
|
||||
notificationsStore = _.reject(notificationsStore, function (element) {
|
||||
return element.id === parseInt(options.id, 10);
|
||||
});
|
||||
return { notifications: [notification] };
|
||||
return {notifications: [notification]};
|
||||
}, function () {
|
||||
return Promise.reject(new errors.NoPermissionError('You do not have permission to destroy notifications.'));
|
||||
});
|
||||
|
@ -85,7 +85,7 @@ posts = {
|
||||
|
||||
return dataProvider.Post.findOne(data, options).then(function (result) {
|
||||
if (result) {
|
||||
return { posts: [ result.toJSON() ]};
|
||||
return {posts: [result.toJSON()]};
|
||||
}
|
||||
|
||||
return Promise.reject(new errors.NotFoundError('Post not found.'));
|
||||
@ -118,7 +118,7 @@ posts = {
|
||||
if (result.updated('status') !== result.get('status')) {
|
||||
post.statusChanged = true;
|
||||
}
|
||||
return { posts: [ post ]};
|
||||
return {posts: [post]};
|
||||
}
|
||||
|
||||
return Promise.reject(new errors.NotFoundError('Post not found.'));
|
||||
@ -154,14 +154,13 @@ posts = {
|
||||
// When creating a new post that is published right now, signal the change
|
||||
post.statusChanged = true;
|
||||
}
|
||||
return { posts: [ post ]};
|
||||
return {posts: [post]};
|
||||
});
|
||||
}, function () {
|
||||
return Promise.reject(new errors.NoPermissionError('You do not have permission to add posts.'));
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* ### Destroy
|
||||
* Delete a post, cleans up tag relations, but not unused tags
|
||||
@ -193,4 +192,4 @@ posts = {
|
||||
|
||||
};
|
||||
|
||||
module.exports = posts;
|
||||
module.exports = posts;
|
||||
|
@ -34,7 +34,6 @@ roles = {
|
||||
return canThis(options.context).browse.role().then(function () {
|
||||
return dataProvider.Role.findAll(options).then(function (foundRoles) {
|
||||
if (options.permissions === 'assign') {
|
||||
|
||||
// Hacky implementation of filtering because when.filter is only available in when 3.4.0,
|
||||
// but that's buggy and kills other tests and introduces Heisenbugs. Until we turn everything
|
||||
// to Bluebird, this works. Sorry.
|
||||
@ -51,12 +50,12 @@ roles = {
|
||||
});
|
||||
|
||||
return Promise.all(permissionMap).then(function (resolved) {
|
||||
return { roles: _.filter(resolved, function (role) {
|
||||
return {roles: _.filter(resolved, function (role) {
|
||||
return role !== null;
|
||||
}) };
|
||||
})};
|
||||
}).catch(errors.logAndThrowError);
|
||||
}
|
||||
return { roles: foundRoles.toJSON() };
|
||||
return {roles: foundRoles.toJSON()};
|
||||
});
|
||||
})
|
||||
.catch(errors.logAndThrowError);
|
||||
|
@ -29,7 +29,6 @@ var _ = require('lodash'),
|
||||
*/
|
||||
settingsCache = {};
|
||||
|
||||
|
||||
/**
|
||||
* ### Updates Config Theme Settings
|
||||
* Maintains the cache of theme specific variables that are reliant on settings.
|
||||
@ -50,7 +49,7 @@ updateConfigTheme = function () {
|
||||
* ### Update Settings Cache
|
||||
* Maintain the internal cache of the settings object
|
||||
* @public
|
||||
* @param settings
|
||||
* @param {Object} settings
|
||||
* @returns {Settings}
|
||||
*/
|
||||
updateSettingsCache = function (settings) {
|
||||
@ -82,8 +81,8 @@ updateSettingsCache = function (settings) {
|
||||
* ### Settings Filter
|
||||
* Filters an object based on a given filter object
|
||||
* @private
|
||||
* @param settings
|
||||
* @param filter
|
||||
* @param {Object} settings
|
||||
* @param {String} filter
|
||||
* @returns {*}
|
||||
*/
|
||||
settingsFilter = function (settings, filter) {
|
||||
@ -118,7 +117,7 @@ filterPaths = function (paths, active) {
|
||||
}
|
||||
|
||||
_.each(pathKeys, function (key) {
|
||||
//do not include hidden files or _messages
|
||||
// do not include hidden files or _messages
|
||||
if (key.indexOf('.') !== 0 &&
|
||||
key !== '_messages' &&
|
||||
key !== 'README.md'
|
||||
@ -141,11 +140,10 @@ filterPaths = function (paths, active) {
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* ### Read Settings Result
|
||||
* @private
|
||||
* @param settingsModels
|
||||
* @param {Array} settingsModels
|
||||
* @returns {Settings}
|
||||
*/
|
||||
readSettingsResult = function (settingsModels) {
|
||||
@ -186,8 +184,8 @@ readSettingsResult = function (settingsModels) {
|
||||
/**
|
||||
* ### Settings Result
|
||||
* @private
|
||||
* @param settings
|
||||
* @param type
|
||||
* @param {Object} settings
|
||||
* @param {String} type
|
||||
* @returns {{settings: *}}
|
||||
*/
|
||||
settingsResult = function (settings, type) {
|
||||
@ -209,8 +207,7 @@ settingsResult = function (settings, type) {
|
||||
/**
|
||||
* ### Populate Default Setting
|
||||
* @private
|
||||
* @param key
|
||||
* @param type
|
||||
* @param {String} key
|
||||
* @returns Promise(Setting)
|
||||
*/
|
||||
populateDefaultSetting = function (key) {
|
||||
@ -238,7 +235,7 @@ populateDefaultSetting = function (key) {
|
||||
* ### Can Edit All Settings
|
||||
* Check that this edit request is allowed for all settings requested to be updated
|
||||
* @private
|
||||
* @param settingsInfo
|
||||
* @param {Object} settingsInfo
|
||||
* @returns {*}
|
||||
*/
|
||||
canEditAllSettings = function (settingsInfo, options) {
|
||||
@ -252,7 +249,6 @@ canEditAllSettings = function (settingsInfo, options) {
|
||||
return canThis(options.context).edit.setting(setting.key).catch(function () {
|
||||
return Promise.reject(new errors.NoPermissionError('You do not have permission to edit settings.'));
|
||||
});
|
||||
|
||||
},
|
||||
checks = _.map(settingsInfo, function (settingInfo) {
|
||||
var setting = settingsCache[settingInfo.key];
|
||||
@ -280,7 +276,7 @@ settings = {
|
||||
|
||||
/**
|
||||
* ### Browse
|
||||
* @param options
|
||||
* @param {Object} options
|
||||
* @returns {*}
|
||||
*/
|
||||
browse: function browse(options) {
|
||||
@ -314,12 +310,12 @@ settings = {
|
||||
|
||||
/**
|
||||
* ### Read
|
||||
* @param options
|
||||
* @param {Object} options
|
||||
* @returns {*}
|
||||
*/
|
||||
read: function read(options) {
|
||||
if (_.isString(options)) {
|
||||
options = { key: options };
|
||||
options = {key: options};
|
||||
}
|
||||
|
||||
var getSettingsResult = function () {
|
||||
@ -372,10 +368,10 @@ settings = {
|
||||
|
||||
// Allow shorthand syntax where a single key and value are passed to edit instead of object and options
|
||||
if (_.isString(object)) {
|
||||
object = { settings: [{ key: object, value: options }]};
|
||||
object = {settings: [{key: object, value: options}]};
|
||||
}
|
||||
|
||||
//clean data
|
||||
// clean data
|
||||
_.each(object.settings, function (setting) {
|
||||
if (!_.isString(setting.value)) {
|
||||
setting.value = JSON.stringify(setting.value);
|
||||
|
@ -43,7 +43,7 @@ slugs = {
|
||||
return Promise.reject(new errors.InternalServerError('Could not generate slug.'));
|
||||
}
|
||||
|
||||
return { slugs: [{ slug: slug }] };
|
||||
return {slugs: [{slug: slug}]};
|
||||
});
|
||||
}).catch(function (err) {
|
||||
if (err) {
|
||||
|
@ -20,9 +20,8 @@ tags = {
|
||||
browse: function browse(options) {
|
||||
return canThis(options.context).browse.tag().then(function () {
|
||||
return dataProvider.Tag.findAll(options).then(function (result) {
|
||||
return { tags: result.toJSON() };
|
||||
return {tags: result.toJSON()};
|
||||
});
|
||||
|
||||
}, function () {
|
||||
return Promise.reject(new errors.NoPermissionError('You do not have permission to browse tags.'));
|
||||
});
|
||||
|
@ -38,7 +38,6 @@ themes = {
|
||||
&& key !== '_messages'
|
||||
&& key !== 'README.md'
|
||||
) {
|
||||
|
||||
var item = {
|
||||
uuid: key
|
||||
};
|
||||
@ -53,7 +52,7 @@ themes = {
|
||||
}
|
||||
});
|
||||
|
||||
return { themes: themes };
|
||||
return {themes: themes};
|
||||
});
|
||||
}, function () {
|
||||
return Promise.reject(new errors.NoPermissionError('You do not have permission to browse themes.'));
|
||||
@ -92,10 +91,10 @@ themes = {
|
||||
|
||||
// Activate the theme
|
||||
return settings.edit(
|
||||
{settings: [{ key: 'activeTheme', value: themeName }]}, {context: {internal: true }}
|
||||
{settings: [{key: 'activeTheme', value: themeName}]}, {context: {internal: true}}
|
||||
).then(function () {
|
||||
theme.active = true;
|
||||
return { themes: [theme]};
|
||||
return {themes: [theme]};
|
||||
});
|
||||
});
|
||||
}, function () {
|
||||
|
@ -27,8 +27,8 @@ sendInviteEmail = function sendInviteEmail(user) {
|
||||
var emailData;
|
||||
|
||||
return Promise.join(
|
||||
users.read({'id': user.created_by}),
|
||||
settings.read({'key': 'title'}),
|
||||
users.read({id: user.created_by}),
|
||||
settings.read({key: 'title'}),
|
||||
settings.read({context: {internal: true}, key: 'dbHash'})
|
||||
).then(function (values) {
|
||||
var invitedBy = values[0].users[0],
|
||||
@ -111,7 +111,7 @@ users = {
|
||||
|
||||
return dataProvider.User.findOne(data, options).then(function (result) {
|
||||
if (result) {
|
||||
return { users: [result.toJSON()] };
|
||||
return {users: [result.toJSON()]};
|
||||
}
|
||||
|
||||
return Promise.reject(new errors.NotFoundError('User not found.'));
|
||||
@ -140,7 +140,7 @@ users = {
|
||||
return dataProvider.User.edit(data.users[0], options)
|
||||
.then(function (result) {
|
||||
if (result) {
|
||||
return { users: [result.toJSON()]};
|
||||
return {users: [result.toJSON()]};
|
||||
}
|
||||
|
||||
return Promise.reject(new errors.NotFoundError('User not found.'));
|
||||
@ -245,8 +245,8 @@ users = {
|
||||
|
||||
// If sending the invitation failed, set status to invited-pending
|
||||
return dataProvider.User.edit({status: 'invited-pending'}, {id: user.id}).then(function (user) {
|
||||
return dataProvider.User.findOne({ id: user.id, status: 'all' }, options).then(function (user) {
|
||||
return { users: [user] };
|
||||
return dataProvider.User.findOne({id: user.id, status: 'all'}, options).then(function (user) {
|
||||
return {users: [user]};
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -273,13 +273,11 @@ users = {
|
||||
|
||||
return addOperation();
|
||||
});
|
||||
|
||||
}).catch(function (error) {
|
||||
return errors.handleAPIError(error, 'You do not have permission to add this user');
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* ### Destroy
|
||||
* @param {{id, context}} options
|
||||
@ -287,7 +285,7 @@ users = {
|
||||
*/
|
||||
destroy: function destroy(options) {
|
||||
return canThis(options.context).destroy.user(options.id).then(function () {
|
||||
return users.read(_.merge(options, { status: 'all'})).then(function (result) {
|
||||
return users.read(_.merge(options, {status: 'all'})).then(function (result) {
|
||||
return dataProvider.Base.transaction(function (t) {
|
||||
options.transacting = t;
|
||||
|
||||
@ -315,7 +313,6 @@ users = {
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* ### Change Password
|
||||
* @param {password} object
|
||||
@ -348,7 +345,7 @@ users = {
|
||||
}).then(function () {
|
||||
return utils.checkObject(object, 'owner').then(function (checkedOwnerTransfer) {
|
||||
return dataProvider.User.transferOwnership(checkedOwnerTransfer.owner[0], options).then(function (updatedUsers) {
|
||||
return Promise.resolve({ users: updatedUsers });
|
||||
return Promise.resolve({users: updatedUsers});
|
||||
}).catch(function (error) {
|
||||
return Promise.reject(new errors.ValidationError(error.message));
|
||||
});
|
||||
|
@ -19,8 +19,7 @@ AppDependencies.prototype.install = function installAppDependencies() {
|
||||
if (!exists) {
|
||||
// Nothing to do, resolve right away?
|
||||
resolve();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Run npm install in the app directory
|
||||
spawnOpts = {
|
||||
cwd: self.appPath
|
||||
@ -47,7 +46,7 @@ AppDependencies.prototype.spawnCommand = function (command, args, opt) {
|
||||
|
||||
opt = opt || {};
|
||||
|
||||
return spawn(winCommand, winArgs, _.defaults({ stdio: 'inherit' }, opt));
|
||||
return spawn(winCommand, winArgs, _.defaults({stdio: 'inherit'}, opt));
|
||||
};
|
||||
|
||||
module.exports = AppDependencies;
|
||||
|
@ -66,7 +66,7 @@ loader = {
|
||||
|
||||
return perms.read().catch(function (err) {
|
||||
// Provide a helpful error about which app
|
||||
return Promise.reject(new Error("Error loading app named " + name + "; problem reading permissions: " + err.message));
|
||||
return Promise.reject(new Error('Error loading app named ' + name + '; problem reading permissions: ' + err.message));
|
||||
});
|
||||
})
|
||||
.then(function (appPerms) {
|
||||
@ -76,7 +76,7 @@ loader = {
|
||||
|
||||
// Check for an install() method on the app.
|
||||
if (!_.isFunction(app.install)) {
|
||||
return Promise.reject(new Error("Error loading app named " + name + "; no install() method defined."));
|
||||
return Promise.reject(new Error('Error loading app named ' + name + '; no install() method defined.'));
|
||||
}
|
||||
|
||||
// Run the app.install() method
|
||||
@ -97,7 +97,7 @@ loader = {
|
||||
|
||||
// Check for an activate() method on the app.
|
||||
if (!_.isFunction(app.activate)) {
|
||||
return Promise.reject(new Error("Error loading app named " + name + "; no activate() method defined."));
|
||||
return Promise.reject(new Error('Error loading app named ' + name + '; no activate() method defined.'));
|
||||
}
|
||||
|
||||
// Wrapping the activate() with a when because it's possible
|
||||
|
@ -13,23 +13,23 @@ AppPermissions.prototype.read = function () {
|
||||
var self = this;
|
||||
|
||||
return this.checkPackageContentsExists().then(function (exists) {
|
||||
if (!exists) {
|
||||
// If no package.json, return default permissions
|
||||
if (!exists) {
|
||||
// If no package.json, return default permissions
|
||||
return Promise.resolve(AppPermissions.DefaultPermissions);
|
||||
}
|
||||
|
||||
// Read and parse the package.json
|
||||
return self.getPackageContents().then(function (parsed) {
|
||||
// If no permissions in the package.json then return the default permissions.
|
||||
if (!(parsed.ghost && parsed.ghost.permissions)) {
|
||||
return Promise.resolve(AppPermissions.DefaultPermissions);
|
||||
}
|
||||
|
||||
// Read and parse the package.json
|
||||
return self.getPackageContents().then(function (parsed) {
|
||||
// If no permissions in the package.json then return the default permissions.
|
||||
if (!(parsed.ghost && parsed.ghost.permissions)) {
|
||||
return Promise.resolve(AppPermissions.DefaultPermissions);
|
||||
}
|
||||
// TODO: Validation on permissions object?
|
||||
|
||||
// TODO: Validation on permissions object?
|
||||
|
||||
return Promise.resolve(parsed.ghost.permissions);
|
||||
});
|
||||
return Promise.resolve(parsed.ghost.permissions);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
AppPermissions.prototype.checkPackageContentsExists = function () {
|
||||
|
@ -1,9 +1,10 @@
|
||||
var _ = require('lodash'),
|
||||
api = require('../api'),
|
||||
helpers = require('../helpers'),
|
||||
filters = require('../filters');
|
||||
filters = require('../filters'),
|
||||
generateProxyFunctions;
|
||||
|
||||
var generateProxyFunctions = function (name, permissions) {
|
||||
generateProxyFunctions = function (name, permissions) {
|
||||
var getPermission = function (perm) {
|
||||
return permissions[perm];
|
||||
},
|
||||
@ -82,7 +83,6 @@ var generateProxyFunctions = function (name, permissions) {
|
||||
};
|
||||
|
||||
function AppProxy(options) {
|
||||
|
||||
if (!options.name) {
|
||||
throw new Error('Must provide an app name for api context');
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ AppSandbox.prototype.loadModule = function loadModuleSandboxed(modulePath) {
|
||||
currentModule.require = function requireProxy(module) {
|
||||
// check whitelist, plugin config, etc.
|
||||
if (_.contains(self.opts.blacklist, module)) {
|
||||
throw new Error("Unsafe App require: " + module);
|
||||
throw new Error('Unsafe App require: ' + module);
|
||||
}
|
||||
|
||||
var firstTwo = module.slice(0, 2),
|
||||
|
@ -19,7 +19,6 @@ var path = require('path'),
|
||||
defaultConfig = {},
|
||||
knexInstance;
|
||||
|
||||
|
||||
function ConfigManager(config) {
|
||||
/**
|
||||
* Our internal true representation of our current config object.
|
||||
@ -108,27 +107,27 @@ ConfigManager.prototype.set = function (config) {
|
||||
knex: knexInstance
|
||||
},
|
||||
paths: {
|
||||
'appRoot': appRoot,
|
||||
'subdir': subdir,
|
||||
'config': this._config.paths.config || path.join(appRoot, 'config.js'),
|
||||
'configExample': path.join(appRoot, 'config.example.js'),
|
||||
'corePath': corePath,
|
||||
appRoot: appRoot,
|
||||
subdir: subdir,
|
||||
config: this._config.paths.config || path.join(appRoot, 'config.js'),
|
||||
configExample: path.join(appRoot, 'config.example.js'),
|
||||
corePath: corePath,
|
||||
|
||||
'contentPath': contentPath,
|
||||
'themePath': path.resolve(contentPath, 'themes'),
|
||||
'appPath': path.resolve(contentPath, 'apps'),
|
||||
'imagesPath': path.resolve(contentPath, 'images'),
|
||||
'imagesRelPath': 'content/images',
|
||||
contentPath: contentPath,
|
||||
themePath: path.resolve(contentPath, 'themes'),
|
||||
appPath: path.resolve(contentPath, 'apps'),
|
||||
imagesPath: path.resolve(contentPath, 'images'),
|
||||
imagesRelPath: 'content/images',
|
||||
|
||||
'adminViews': path.join(corePath, '/server/views/'),
|
||||
'helperTemplates': path.join(corePath, '/server/helpers/tpl/'),
|
||||
'exportPath': path.join(corePath, '/server/data/export/'),
|
||||
'lang': path.join(corePath, '/shared/lang/'),
|
||||
'debugPath': subdir + '/ghost/debug/',
|
||||
adminViews: path.join(corePath, '/server/views/'),
|
||||
helperTemplates: path.join(corePath, '/server/helpers/tpl/'),
|
||||
exportPath: path.join(corePath, '/server/data/export/'),
|
||||
lang: path.join(corePath, '/shared/lang/'),
|
||||
debugPath: subdir + '/ghost/debug/',
|
||||
|
||||
'availableThemes': this._config.paths.availableThemes || {},
|
||||
'availableApps': this._config.paths.availableApps || {},
|
||||
'builtScriptPath': path.join(corePath, 'built/scripts/')
|
||||
availableThemes: this._config.paths.availableThemes || {},
|
||||
availableApps: this._config.paths.availableApps || {},
|
||||
builtScriptPath: path.join(corePath, 'built/scripts/')
|
||||
},
|
||||
theme: {
|
||||
// normalise the URL by removing any trailing slash
|
||||
@ -258,7 +257,7 @@ ConfigManager.prototype.validate = function () {
|
||||
}
|
||||
|
||||
// Check that our url is valid
|
||||
if (!validator.isURL(config.url, { protocols: ['http', 'https'], require_protocol: true })) {
|
||||
if (!validator.isURL(config.url, {protocols: ['http', 'https'], require_protocol: true})) {
|
||||
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 Promise.reject(new Error('invalid site url'));
|
||||
@ -294,7 +293,7 @@ ConfigManager.prototype.validate = function () {
|
||||
|
||||
/**
|
||||
* Helper method for checking the state of a particular privacy flag
|
||||
* @param privacyFlag The flag to check
|
||||
* @param {String} privacyFlag The flag to check
|
||||
* @returns {boolean}
|
||||
*/
|
||||
ConfigManager.prototype.isPrivacyDisabled = function (privacyFlag) {
|
||||
@ -324,11 +323,9 @@ ConfigManager.prototype.checkDeprecated = function () {
|
||||
|
||||
errors.logWarn(errorText, explinationText, helpText);
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
if (testingEnvs.indexOf(process.env.NODE_ENV) > -1) {
|
||||
defaultConfig = require('../../../config.example')[process.env.NODE_ENV];
|
||||
}
|
||||
|
@ -106,9 +106,9 @@ function urlFor(context, data, absolute) {
|
||||
|
||||
// this will become really big
|
||||
knownPaths = {
|
||||
'home': '/',
|
||||
'rss': '/rss/',
|
||||
'api': '/ghost/api/v0.1'
|
||||
home: '/',
|
||||
rss: '/rss/',
|
||||
api: '/ghost/api/v0.1'
|
||||
};
|
||||
|
||||
// Make data properly optional
|
||||
|
@ -35,8 +35,8 @@ adminControllers = {
|
||||
};
|
||||
|
||||
return api.notifications.browse({context: {internal: true}}).then(function (results) {
|
||||
if (!_.some(results.notifications, { message: notification.message })) {
|
||||
return api.notifications.add({ notifications: [notification] }, {context: {internal: true}});
|
||||
if (!_.some(results.notifications, {message: notification.message})) {
|
||||
return api.notifications.add({notifications: [notification]}, {context: {internal: true}});
|
||||
}
|
||||
});
|
||||
}).finally(function () {
|
||||
|
@ -115,7 +115,7 @@ function getActiveThemePaths() {
|
||||
}
|
||||
|
||||
frontendControllers = {
|
||||
'homepage': function (req, res, next) {
|
||||
homepage: function (req, res, next) {
|
||||
// Parse the page number
|
||||
var pageParam = req.params.page !== undefined ? parseInt(req.params.page, 10) : 1,
|
||||
options = {
|
||||
@ -128,7 +128,6 @@ frontendControllers = {
|
||||
}
|
||||
|
||||
return getPostPage(options).then(function (page) {
|
||||
|
||||
// If page is greater than number of pages we have, redirect to last page
|
||||
if (pageParam > page.meta.pagination.pages) {
|
||||
return res.redirect(page.meta.pagination.pages === 1 ? config.paths.subdir + '/' : (config.paths.subdir + '/page/' + page.meta.pagination.pages + '/'));
|
||||
@ -152,7 +151,7 @@ frontendControllers = {
|
||||
});
|
||||
}).catch(handleError(next));
|
||||
},
|
||||
'tag': function (req, res, next) {
|
||||
tag: function (req, res, next) {
|
||||
// Parse the page number
|
||||
var pageParam = req.params.page !== undefined ? parseInt(req.params.page, 10) : 1,
|
||||
options = {
|
||||
@ -206,8 +205,7 @@ frontendControllers = {
|
||||
});
|
||||
}).catch(handleError(next));
|
||||
},
|
||||
'author': function (req, res, next) {
|
||||
|
||||
author: function (req, res, next) {
|
||||
// Parse the page number
|
||||
var pageParam = req.params.page !== undefined ? parseInt(req.params.page, 10) : 1,
|
||||
options = {
|
||||
@ -215,8 +213,6 @@ frontendControllers = {
|
||||
author: req.params.slug
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Get url for tag page
|
||||
function authorUrl(author, page) {
|
||||
var url = config.paths.subdir + '/author/' + author + '/';
|
||||
@ -264,7 +260,7 @@ frontendControllers = {
|
||||
}).catch(handleError(next));
|
||||
},
|
||||
|
||||
'single': function (req, res, next) {
|
||||
single: function (req, res, next) {
|
||||
var path = req.path,
|
||||
params,
|
||||
editFormat,
|
||||
@ -377,7 +373,6 @@ frontendControllers = {
|
||||
}
|
||||
|
||||
return render();
|
||||
|
||||
}).catch(function (err) {
|
||||
// If we've thrown an error message
|
||||
// of type: 'NotFound' then we found
|
||||
@ -389,7 +384,7 @@ frontendControllers = {
|
||||
return handleError(next)(err);
|
||||
});
|
||||
},
|
||||
'rss': function (req, res, next) {
|
||||
rss: function (req, res, next) {
|
||||
function isPaginated() {
|
||||
return req.route.path.indexOf(':page') !== -1;
|
||||
}
|
||||
@ -486,7 +481,7 @@ frontendControllers = {
|
||||
categories: _.pluck(post.tags, 'name'),
|
||||
author: post.author ? post.author.name : null
|
||||
},
|
||||
htmlContent = cheerio.load(post.html, { decodeEntities: false });
|
||||
htmlContent = cheerio.load(post.html, {decodeEntities: false});
|
||||
|
||||
// convert relative resource urls to absolute
|
||||
['href', 'src'].forEach(function (attributeName) {
|
||||
|
@ -25,7 +25,6 @@ var Promise = require('bluebird'),
|
||||
populate,
|
||||
update;
|
||||
|
||||
|
||||
logInfo = function logInfo(message) {
|
||||
errors.logInfo('Migrations', message);
|
||||
};
|
||||
|
@ -55,13 +55,12 @@ addAllRolesPermissions = function () {
|
||||
return Promise.all(ops);
|
||||
};
|
||||
|
||||
|
||||
addAllPermissions = function (options) {
|
||||
var ops = [];
|
||||
_.each(fixtures.permissions, function (permissions, object_type) {
|
||||
_.each(fixtures.permissions, function (permissions, objectType) {
|
||||
_.each(permissions, function (permission) {
|
||||
ops.push(function () {
|
||||
permission.object_type = object_type;
|
||||
permission.object_type = objectType;
|
||||
return models.Permission.add(permission, options);
|
||||
});
|
||||
});
|
||||
|
@ -5,7 +5,6 @@ var Promise = require('bluebird'),
|
||||
|
||||
Importer000;
|
||||
|
||||
|
||||
Importer000 = function () {
|
||||
_.bindAll(this, 'doImport');
|
||||
|
||||
@ -34,13 +33,12 @@ Importer000.prototype.canImport = function (data) {
|
||||
return Promise.reject('Unsupported version of data: ' + data.meta.version);
|
||||
};
|
||||
|
||||
|
||||
Importer000.prototype.loadUsers = function () {
|
||||
var users = {all: {}};
|
||||
|
||||
return models.User.findAll({include: 'roles'}).then(function (_users) {
|
||||
_users.forEach(function (user) {
|
||||
users.all[user.get('email')] = {'realId': user.get('id')};
|
||||
users.all[user.get('email')] = {realId: user.get('id')};
|
||||
if (user.related('roles').toJSON()[0] && user.related('roles').toJSON()[0].name === 'Owner') {
|
||||
users.owner = user.toJSON();
|
||||
}
|
||||
@ -54,9 +52,9 @@ Importer000.prototype.loadUsers = function () {
|
||||
});
|
||||
};
|
||||
|
||||
//Importer000.prototype.importerFunction = function (t) {
|
||||
// Importer000.prototype.importerFunction = function (t) {
|
||||
//
|
||||
//};
|
||||
// };
|
||||
|
||||
Importer000.prototype.doUserImport = function (t, tableData, users, errors) {
|
||||
var userOps = [],
|
||||
@ -104,7 +102,6 @@ Importer000.prototype.doImport = function (data) {
|
||||
users = result.all;
|
||||
|
||||
return models.Base.transaction(function (t) {
|
||||
|
||||
// Step 1: Attempt to handle adding new users
|
||||
self.doUserImport(t, tableData, users, errors).then(function (result) {
|
||||
var importResults = [];
|
||||
@ -167,7 +164,7 @@ Importer000.prototype.doImport = function (data) {
|
||||
*/
|
||||
});
|
||||
}).then(function () {
|
||||
//TODO: could return statistics of imported items
|
||||
// TODO: could return statistics of imported items
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
|
@ -5,4 +5,4 @@ module.exports = {
|
||||
importData: function (data) {
|
||||
return new Importer000.importData(data);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -5,4 +5,4 @@ module.exports = {
|
||||
importData: function (data) {
|
||||
return new Importer000.importData(data);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -5,4 +5,4 @@ module.exports = {
|
||||
importData: function (data) {
|
||||
return new Importer000.importData(data);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -44,7 +44,6 @@ cleanError = function cleanError(error) {
|
||||
return new errors.DataImportError(message, offendingProperty, value);
|
||||
};
|
||||
|
||||
|
||||
handleErrors = function handleErrors(errorList) {
|
||||
var processedErrors = [];
|
||||
|
||||
@ -67,11 +66,9 @@ handleErrors = function handleErrors(errorList) {
|
||||
};
|
||||
|
||||
sanitize = function sanitize(data) {
|
||||
|
||||
// Check for correct UUID and fix if neccessary
|
||||
_.each(_.keys(data.data), function (tableName) {
|
||||
_.each(data.data[tableName], function (importValues) {
|
||||
|
||||
var uuidMissing = (!importValues.uuid && tables[tableName].uuid) ? true : false,
|
||||
uuidMalformed = (importValues.uuid && !validator.isUUID(importValues.uuid)) ? true : false;
|
||||
|
||||
|
@ -49,11 +49,11 @@ utils = {
|
||||
if (tableData[obj]) {
|
||||
// For each object in the tableData that matches
|
||||
_.each(tableData[obj], function (data) {
|
||||
//console.log('checking ' + obj + ' ' + data.slug);
|
||||
// console.log('checking ' + obj + ' ' + data.slug);
|
||||
// For each possible user foreign key
|
||||
_.each(userKeys, function (key) {
|
||||
if (_.has(data, key) && data[key] !== null) {
|
||||
//console.log('found ' + key + ' with value ' + data[key]);
|
||||
// console.log('found ' + key + ' with value ' + data[key]);
|
||||
userMap[data[key]] = {};
|
||||
}
|
||||
});
|
||||
@ -105,23 +105,22 @@ utils = {
|
||||
var postTags,
|
||||
postsWithTags = {};
|
||||
|
||||
|
||||
postTags = tableData.posts_tags;
|
||||
_.each(postTags, function (post_tag) {
|
||||
if (!postsWithTags.hasOwnProperty(post_tag.post_id)) {
|
||||
postsWithTags[post_tag.post_id] = [];
|
||||
_.each(postTags, function (postTag) {
|
||||
if (!postsWithTags.hasOwnProperty(postTag.post_id)) {
|
||||
postsWithTags[postTag.post_id] = [];
|
||||
}
|
||||
postsWithTags[post_tag.post_id].push(post_tag.tag_id);
|
||||
postsWithTags[postTag.post_id].push(postTag.tag_id);
|
||||
});
|
||||
|
||||
_.each(postsWithTags, function (tag_ids, post_id) {
|
||||
_.each(postsWithTags, function (tagIds, postId) {
|
||||
var post, tags;
|
||||
post = _.find(tableData.posts, function (post) {
|
||||
return post.id === parseInt(post_id, 10);
|
||||
return post.id === parseInt(postId, 10);
|
||||
});
|
||||
if (post) {
|
||||
tags = _.filter(tableData.tags, function (tag) {
|
||||
return _.indexOf(tag_ids, tag.id) !== -1;
|
||||
return _.indexOf(tagIds, tag.id) !== -1;
|
||||
});
|
||||
post.tags = [];
|
||||
_.each(tags, function (tag) {
|
||||
@ -136,13 +135,13 @@ utils = {
|
||||
},
|
||||
|
||||
preProcessRolesUsers: function preProcessRolesUsers(tableData) {
|
||||
_.each(tableData.roles_users, function (role_user) {
|
||||
_.each(tableData.roles_users, function (roleUser) {
|
||||
var user = _.find(tableData.users, function (user) {
|
||||
return user.id === parseInt(role_user.user_id, 10);
|
||||
return user.id === parseInt(roleUser.user_id, 10);
|
||||
});
|
||||
// just the one role for now
|
||||
if (user && !user.roles) {
|
||||
user.roles = [role_user.role_id];
|
||||
user.roles = [roleUser.role_id];
|
||||
}
|
||||
});
|
||||
|
||||
@ -265,10 +264,9 @@ utils = {
|
||||
datum.key = updatedSettingKeys[datum.key] || datum.key;
|
||||
});
|
||||
|
||||
ops.push(models.Settings.edit(tableData, _.extend(internal, {transacting: transaction}))
|
||||
.catch(function (error) {
|
||||
return Promise.reject({raw: error, model: 'setting', data: tableData});
|
||||
}));
|
||||
ops.push(models.Settings.edit(tableData, _.extend(internal, {transacting: transaction})).catch(function (error) {
|
||||
return Promise.reject({raw: error, model: 'setting', data: tableData});
|
||||
}));
|
||||
|
||||
return Promise.settle(ops);
|
||||
},
|
||||
|
@ -3,7 +3,6 @@ var _ = require('lodash'),
|
||||
utils = require('../utils'),
|
||||
schema = require('../schema').tables,
|
||||
|
||||
|
||||
// private
|
||||
logInfo,
|
||||
|
||||
@ -13,7 +12,6 @@ var _ = require('lodash'),
|
||||
addColumnCommands,
|
||||
modifyUniqueCommands;
|
||||
|
||||
|
||||
logInfo = function logInfo(message) {
|
||||
errors.logInfo('Migrations', message);
|
||||
};
|
||||
@ -26,7 +24,6 @@ getDeleteCommands = function getDeleteCommands(oldTables, newTables) {
|
||||
return utils.deleteTable(table);
|
||||
};
|
||||
});
|
||||
|
||||
};
|
||||
getAddCommands = function getAddCommands(oldTables, newTables) {
|
||||
var addTables = _.difference(newTables, oldTables);
|
||||
@ -74,4 +71,4 @@ module.exports = {
|
||||
getAddCommands: getAddCommands,
|
||||
addColumnCommands: addColumnCommands,
|
||||
modifyUniqueCommands: modifyUniqueCommands
|
||||
};
|
||||
};
|
||||
|
@ -118,11 +118,11 @@ reset = function () {
|
||||
migrateUpFreshDb = function (tablesOnly) {
|
||||
var tableSequence,
|
||||
tables = _.map(schemaTables, function (table) {
|
||||
return function () {
|
||||
logInfo('Creating table: ' + table);
|
||||
return utils.createTable(table);
|
||||
};
|
||||
});
|
||||
return function () {
|
||||
logInfo('Creating table: ' + table);
|
||||
return utils.createTable(table);
|
||||
};
|
||||
});
|
||||
logInfo('Creating tables...');
|
||||
tableSequence = sequence(tables);
|
||||
|
||||
@ -168,7 +168,6 @@ migrateUp = function (fromVersion, toVersion) {
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
}).then(function () {
|
||||
migrateOps = migrateOps.concat(_.compact(modifyUniCommands));
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
var db = {
|
||||
posts: {
|
||||
id: {type: 'increments', nullable: false, primary: true},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {'isUUID': true}},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {isUUID: true}},
|
||||
title: {type: 'string', maxlength: 150, nullable: false},
|
||||
slug: {type: 'string', maxlength: 150, nullable: false, unique: true},
|
||||
markdown: {type: 'text', maxlength: 16777215, fieldtype: 'medium', nullable: true},
|
||||
html: {type: 'text', maxlength: 16777215, fieldtype: 'medium', nullable: true},
|
||||
image: {type: 'text', maxlength: 2000, nullable: true},
|
||||
featured: {type: 'bool', nullable: false, defaultTo: false, validations: {'isIn': [[0, 1, false, true]]}},
|
||||
page: {type: 'bool', nullable: false, defaultTo: false, validations: {'isIn': [[0, 1, false, true]]}},
|
||||
featured: {type: 'bool', nullable: false, defaultTo: false, validations: {isIn: [[0, 1, false, true]]}},
|
||||
page: {type: 'bool', nullable: false, defaultTo: false, validations: {isIn: [[0, 1, false, true]]}},
|
||||
status: {type: 'string', maxlength: 150, nullable: false, defaultTo: 'draft'},
|
||||
language: {type: 'string', maxlength: 6, nullable: false, defaultTo: 'en_US'},
|
||||
meta_title: {type: 'string', maxlength: 150, nullable: true},
|
||||
@ -23,15 +23,15 @@ var db = {
|
||||
},
|
||||
users: {
|
||||
id: {type: 'increments', nullable: false, primary: true},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {'isUUID': true}},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {isUUID: true}},
|
||||
name: {type: 'string', maxlength: 150, nullable: false},
|
||||
slug: {type: 'string', maxlength: 150, nullable: false, unique: true},
|
||||
password: {type: 'string', maxlength: 60, nullable: false},
|
||||
email: {type: 'string', maxlength: 254, nullable: false, unique: true, validations: {'isEmail': true}},
|
||||
email: {type: 'string', maxlength: 254, nullable: false, unique: true, validations: {isEmail: true}},
|
||||
image: {type: 'text', maxlength: 2000, nullable: true},
|
||||
cover: {type: 'text', maxlength: 2000, nullable: true},
|
||||
bio: {type: 'string', maxlength: 200, nullable: true},
|
||||
website: {type: 'text', maxlength: 2000, nullable: true, validations: {'isEmptyOrURL': true}},
|
||||
website: {type: 'text', maxlength: 2000, nullable: true, validations: {isEmptyOrURL: true}},
|
||||
location: {type: 'text', maxlength: 65535, nullable: true},
|
||||
accessibility: {type: 'text', maxlength: 65535, nullable: true},
|
||||
status: {type: 'string', maxlength: 150, nullable: false, defaultTo: 'active'},
|
||||
@ -46,7 +46,7 @@ var db = {
|
||||
},
|
||||
roles: {
|
||||
id: {type: 'increments', nullable: false, primary: true},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {'isUUID': true}},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {isUUID: true}},
|
||||
name: {type: 'string', maxlength: 150, nullable: false},
|
||||
description: {type: 'string', maxlength: 200, nullable: true},
|
||||
created_at: {type: 'dateTime', nullable: false},
|
||||
@ -61,7 +61,7 @@ var db = {
|
||||
},
|
||||
permissions: {
|
||||
id: {type: 'increments', nullable: false, primary: true},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {'isUUID': true}},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {isUUID: true}},
|
||||
name: {type: 'string', maxlength: 150, nullable: false},
|
||||
object_type: {type: 'string', maxlength: 150, nullable: false},
|
||||
action_type: {type: 'string', maxlength: 150, nullable: false},
|
||||
@ -88,10 +88,10 @@ var db = {
|
||||
},
|
||||
settings: {
|
||||
id: {type: 'increments', nullable: false, primary: true},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {'isUUID': true}},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {isUUID: true}},
|
||||
key: {type: 'string', maxlength: 150, nullable: false, unique: true},
|
||||
value: {type: 'text', maxlength: 65535, nullable: true},
|
||||
type: {type: 'string', maxlength: 150, nullable: false, defaultTo: 'core', validations: {'isIn': [['core', 'blog', 'theme', 'app', 'plugin']]}},
|
||||
type: {type: 'string', maxlength: 150, nullable: false, defaultTo: 'core', validations: {isIn: [['core', 'blog', 'theme', 'app', 'plugin']]}},
|
||||
created_at: {type: 'dateTime', nullable: false},
|
||||
created_by: {type: 'integer', nullable: false},
|
||||
updated_at: {type: 'dateTime', nullable: true},
|
||||
@ -99,12 +99,12 @@ var db = {
|
||||
},
|
||||
tags: {
|
||||
id: {type: 'increments', nullable: false, primary: true},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {'isUUID': true}},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {isUUID: true}},
|
||||
name: {type: 'string', maxlength: 150, nullable: false},
|
||||
slug: {type: 'string', maxlength: 150, nullable: false, unique: true},
|
||||
description: {type: 'string', maxlength: 200, nullable: true},
|
||||
image: {type: 'text', maxlength: 2000, nullable: true},
|
||||
hidden: {type: 'bool', nullable: false, defaultTo: false, validations: {'isIn': [[0, 1, false, true]]}},
|
||||
hidden: {type: 'bool', nullable: false, defaultTo: false, validations: {isIn: [[0, 1, false, true]]}},
|
||||
parent_id: {type: 'integer', nullable: true},
|
||||
meta_title: {type: 'string', maxlength: 150, nullable: true},
|
||||
meta_description: {type: 'string', maxlength: 200, nullable: true},
|
||||
@ -120,7 +120,7 @@ var db = {
|
||||
},
|
||||
apps: {
|
||||
id: {type: 'increments', nullable: false, primary: true},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {'isUUID': true}},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {isUUID: true}},
|
||||
name: {type: 'string', maxlength: 150, nullable: false, unique: true},
|
||||
slug: {type: 'string', maxlength: 150, nullable: false, unique: true},
|
||||
version: {type: 'string', maxlength: 150, nullable: false},
|
||||
@ -132,7 +132,7 @@ var db = {
|
||||
},
|
||||
app_settings: {
|
||||
id: {type: 'increments', nullable: false, primary: true},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {'isUUID': true}},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {isUUID: true}},
|
||||
key: {type: 'string', maxlength: 150, nullable: false, unique: true},
|
||||
value: {type: 'text', maxlength: 65535, nullable: true},
|
||||
app_id: {type: 'integer', nullable: false, unsigned: true, references: 'apps.id'},
|
||||
@ -143,14 +143,14 @@ var db = {
|
||||
},
|
||||
app_fields: {
|
||||
id: {type: 'increments', nullable: false, primary: true},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {'isUUID': true}},
|
||||
uuid: {type: 'string', maxlength: 36, nullable: false, validations: {isUUID: true}},
|
||||
key: {type: 'string', maxlength: 150, nullable: false},
|
||||
value: {type: 'text', maxlength: 65535, nullable: true},
|
||||
type: {type: 'string', maxlength: 150, nullable: false, defaultTo: 'html'},
|
||||
app_id: {type: 'integer', nullable: false, unsigned: true, references: 'apps.id'},
|
||||
relatable_id: {type: 'integer', nullable: false, unsigned: true},
|
||||
relatable_type: {type: 'string', maxlength: 150, nullable: false, defaultTo: 'posts'},
|
||||
active: {type: 'bool', nullable: false, defaultTo: true, validations: {'isIn': [[0, 1, false, true]]}},
|
||||
active: {type: 'bool', nullable: false, defaultTo: true, validations: {isIn: [[0, 1, false, true]]}},
|
||||
created_at: {type: 'dateTime', nullable: false},
|
||||
created_by: {type: 'integer', nullable: false},
|
||||
updated_at: {type: 'dateTime', nullable: true},
|
||||
|
@ -2,7 +2,6 @@ var sqlite3 = require('./sqlite3'),
|
||||
mysql = require('./mysql'),
|
||||
pg = require('./pg');
|
||||
|
||||
|
||||
module.exports = {
|
||||
sqlite3: sqlite3,
|
||||
mysql: mysql,
|
||||
|
@ -1,7 +1,7 @@
|
||||
var _ = require('lodash'),
|
||||
config = require('../../../config/index'),
|
||||
|
||||
//private
|
||||
// private
|
||||
doRawAndFlatten,
|
||||
|
||||
// public
|
||||
|
@ -9,7 +9,6 @@ var _ = require('lodash'),
|
||||
getIndexes,
|
||||
getColumns;
|
||||
|
||||
|
||||
doRawFlattenAndPluck = function doRaw(query, name) {
|
||||
return config.database.knex.raw(query).then(function (response) {
|
||||
return _.flatten(_.pluck(response.rows, name));
|
||||
@ -41,4 +40,4 @@ module.exports = {
|
||||
getTables: getTables,
|
||||
getIndexes: getIndexes,
|
||||
getColumns: getColumns
|
||||
};
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
var _ = require('lodash'),
|
||||
config = require('../../../config/index'),
|
||||
|
||||
//private
|
||||
// private
|
||||
doRaw,
|
||||
|
||||
// public
|
||||
@ -9,7 +9,6 @@ var _ = require('lodash'),
|
||||
getIndexes,
|
||||
getColumns;
|
||||
|
||||
|
||||
doRaw = function doRaw(query, fn) {
|
||||
return config.database.knex.raw(query).then(function (response) {
|
||||
return fn(response);
|
||||
@ -40,4 +39,4 @@ module.exports = {
|
||||
getTables: getTables,
|
||||
getIndexes: getIndexes,
|
||||
getColumns: getColumns
|
||||
};
|
||||
};
|
||||
|
@ -6,7 +6,6 @@ var _ = require('lodash'),
|
||||
|
||||
dbConfig;
|
||||
|
||||
|
||||
function addTableColumn(tablename, table, columnname) {
|
||||
var column,
|
||||
columnSpec = schema[tablename][columnname];
|
||||
@ -35,7 +34,7 @@ function addTableColumn(tablename, table, columnname) {
|
||||
column.unsigned();
|
||||
}
|
||||
if (columnSpec.hasOwnProperty('references')) {
|
||||
//check if table exists?
|
||||
// check if table exists?
|
||||
column.references(columnSpec.references);
|
||||
}
|
||||
if (columnSpec.hasOwnProperty('defaultTo')) {
|
||||
@ -131,4 +130,4 @@ module.exports = {
|
||||
dropUnique: dropUnique,
|
||||
addColumn: addColumn,
|
||||
getColumns: getColumns
|
||||
};
|
||||
};
|
||||
|
@ -24,7 +24,7 @@ validator.extend('notContains', function (str, badString) {
|
||||
});
|
||||
|
||||
validator.extend('isEmptyOrURL', function (str) {
|
||||
return (_.isEmpty(str) || validator.isURL(str, { require_protocol: false }));
|
||||
return (_.isEmpty(str) || validator.isURL(str, {require_protocol: false}));
|
||||
});
|
||||
|
||||
// Validation validation against schema attributes
|
||||
@ -57,12 +57,12 @@ validateSchema = function (tableName, model) {
|
||||
}
|
||||
}
|
||||
|
||||
//check validations objects
|
||||
// check validations objects
|
||||
if (schema[tableName][columnKey].hasOwnProperty('validations')) {
|
||||
validationErrors = validationErrors.concat(validate(model[columnKey], columnKey, schema[tableName][columnKey].validations));
|
||||
}
|
||||
|
||||
//check type
|
||||
// check type
|
||||
if (schema[tableName][columnKey].hasOwnProperty('type')) {
|
||||
if (schema[tableName][columnKey].type === 'integer' && !validator.isInt(model[columnKey])) {
|
||||
message = 'Value in [' + tableName + '.' + columnKey + '] is not an integer.';
|
||||
|
@ -56,11 +56,11 @@ function getDatabaseVersion() {
|
||||
function setDatabaseVersion() {
|
||||
return config.database.knex('settings')
|
||||
.where('key', 'databaseVersion')
|
||||
.update({ 'value': defaultDatabaseVersion });
|
||||
.update({value: defaultDatabaseVersion});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getDefaultDatabaseVersion: getDefaultDatabaseVersion,
|
||||
getDatabaseVersion: getDatabaseVersion,
|
||||
setDatabaseVersion: setDatabaseVersion
|
||||
};
|
||||
};
|
||||
|
@ -11,5 +11,4 @@ function BadRequestError(message) {
|
||||
BadRequestError.prototype = Object.create(Error.prototype);
|
||||
BadRequestError.prototype.name = 'BadRequestError';
|
||||
|
||||
|
||||
module.exports = BadRequestError;
|
||||
module.exports = BadRequestError;
|
||||
|
@ -13,5 +13,4 @@ function DataImportError(message, offendingProperty, value) {
|
||||
DataImportError.prototype = Object.create(Error.prototype);
|
||||
DataImportError.prototype.name = 'DataImportError';
|
||||
|
||||
|
||||
module.exports = DataImportError;
|
||||
module.exports = DataImportError;
|
||||
|
@ -11,5 +11,4 @@ function EmailError(message) {
|
||||
EmailError.prototype = Object.create(Error.prototype);
|
||||
EmailError.prototype.name = 'EmailError';
|
||||
|
||||
|
||||
module.exports = EmailError;
|
||||
module.exports = EmailError;
|
||||
|
@ -63,7 +63,6 @@ errors = {
|
||||
if ((process.env.NODE_ENV === 'development' ||
|
||||
process.env.NODE_ENV === 'staging' ||
|
||||
process.env.NODE_ENV === 'production')) {
|
||||
|
||||
var msg = [component.cyan + ':'.cyan, info.cyan];
|
||||
|
||||
console.info.apply(console, msg);
|
||||
@ -74,7 +73,6 @@ errors = {
|
||||
if ((process.env.NODE_ENV === 'development' ||
|
||||
process.env.NODE_ENV === 'staging' ||
|
||||
process.env.NODE_ENV === 'production')) {
|
||||
|
||||
var msgs = ['\nWarning:'.yellow, warn.yellow, '\n'];
|
||||
|
||||
if (context) {
|
||||
@ -109,19 +107,18 @@ errors = {
|
||||
stack = err ? err.stack : null;
|
||||
|
||||
err = _.isString(err) ? err : (_.isObject(err) ? err.message : 'An unknown error occurred.');
|
||||
|
||||
|
||||
// Overwrite error to provide information that this is probably a permission problem
|
||||
// TODO: https://github.com/TryGhost/Ghost/issues/3687
|
||||
if (err.indexOf('SQLITE_READONLY') !== -1) {
|
||||
context = "Your database is in read only mode. Visitors can read your blog, but you can't log in or add posts.";
|
||||
help = "Check your database file and make sure that file owner and permissions are correct.";
|
||||
context = 'Your database is in read only mode. Visitors can read your blog, but you can\'t log in or add posts.';
|
||||
help = 'Check your database file and make sure that file owner and permissions are correct.';
|
||||
}
|
||||
// TODO: Logging framework hookup
|
||||
// Eventually we'll have better logging which will know about envs
|
||||
if ((process.env.NODE_ENV === 'development' ||
|
||||
process.env.NODE_ENV === 'staging' ||
|
||||
process.env.NODE_ENV === 'production')) {
|
||||
|
||||
msgs = ['\nERROR:'.red, err.red, '\n'];
|
||||
|
||||
if (context) {
|
||||
@ -216,8 +213,8 @@ errors = {
|
||||
}
|
||||
|
||||
return {
|
||||
'function': parts[1],
|
||||
'at': parts[2]
|
||||
function: parts[1],
|
||||
at: parts[2]
|
||||
};
|
||||
})
|
||||
.filter(function (line) {
|
||||
|
@ -11,5 +11,4 @@ function InternalServerError(message) {
|
||||
InternalServerError.prototype = Object.create(Error.prototype);
|
||||
InternalServerError.prototype.name = 'InternalServerError';
|
||||
|
||||
|
||||
module.exports = InternalServerError;
|
||||
module.exports = InternalServerError;
|
||||
|
@ -11,5 +11,4 @@ function NoPermissionError(message) {
|
||||
NoPermissionError.prototype = Object.create(Error.prototype);
|
||||
NoPermissionError.prototype.name = 'NoPermissionError';
|
||||
|
||||
|
||||
module.exports = NoPermissionError;
|
||||
module.exports = NoPermissionError;
|
||||
|
@ -11,5 +11,4 @@ function NotFoundError(message) {
|
||||
NotFoundError.prototype = Object.create(Error.prototype);
|
||||
NotFoundError.prototype.name = 'NotFoundError';
|
||||
|
||||
|
||||
module.exports = NotFoundError;
|
||||
module.exports = NotFoundError;
|
||||
|
@ -11,5 +11,4 @@ function RequestEntityTooLargeError(message) {
|
||||
RequestEntityTooLargeError.prototype = Object.create(Error.prototype);
|
||||
RequestEntityTooLargeError.prototype.name = 'RequestEntityTooLargeError';
|
||||
|
||||
|
||||
module.exports = RequestEntityTooLargeError;
|
||||
module.exports = RequestEntityTooLargeError;
|
||||
|
@ -11,5 +11,4 @@ function UnauthorizedError(message) {
|
||||
UnauthorizedError.prototype = Object.create(Error.prototype);
|
||||
UnauthorizedError.prototype.name = 'UnauthorizedError';
|
||||
|
||||
|
||||
module.exports = UnauthorizedError;
|
||||
module.exports = UnauthorizedError;
|
||||
|
@ -11,5 +11,4 @@ function UnsupportedMediaTypeError(message) {
|
||||
UnsupportedMediaTypeError.prototype = Object.create(Error.prototype);
|
||||
UnsupportedMediaTypeError.prototype.name = 'UnsupportedMediaTypeError';
|
||||
|
||||
|
||||
module.exports = UnsupportedMediaTypeError;
|
||||
module.exports = UnsupportedMediaTypeError;
|
||||
|
@ -14,5 +14,4 @@ function ValidationError(message, offendingProperty) {
|
||||
ValidationError.prototype = Object.create(Error.prototype);
|
||||
ValidationError.prototype.name = 'ValidationError';
|
||||
|
||||
|
||||
module.exports = ValidationError;
|
||||
|
@ -13,13 +13,13 @@ defaults = {
|
||||
maxPriority: 9
|
||||
};
|
||||
|
||||
var Filters = function () {
|
||||
function Filters() {
|
||||
// Holds the filters
|
||||
this.filterCallbacks = [];
|
||||
|
||||
// Holds the filter hooks (that are built in to Ghost Core)
|
||||
this.filters = [];
|
||||
};
|
||||
}
|
||||
|
||||
// Register a new filter callback function
|
||||
Filters.prototype.registerFilter = function (name, priority, fn) {
|
||||
|
@ -22,7 +22,7 @@ var downsize = require('downsize'),
|
||||
scriptFiles = {
|
||||
production: [
|
||||
'vendor.min.js',
|
||||
'ghost.min.js',
|
||||
'ghost.min.js'
|
||||
],
|
||||
development: [
|
||||
'vendor-dev.js',
|
||||
@ -60,7 +60,6 @@ coreHelpers.date = function (context, options) {
|
||||
timeago = options.hash.timeago,
|
||||
date;
|
||||
|
||||
|
||||
if (timeago) {
|
||||
date = moment(context).fromNow();
|
||||
} else {
|
||||
@ -154,7 +153,6 @@ coreHelpers.url = function (options) {
|
||||
return Promise.resolve(config.urlFor('author', {author: this}, absolute));
|
||||
}
|
||||
|
||||
|
||||
return Promise.resolve(config.urlFor(this, absolute));
|
||||
};
|
||||
|
||||
@ -291,7 +289,6 @@ coreHelpers.content = function (options) {
|
||||
});
|
||||
|
||||
if (truncateOptions.hasOwnProperty('words') || truncateOptions.hasOwnProperty('characters')) {
|
||||
|
||||
// Legacy function: {{content words="0"}} should return leading tags.
|
||||
if (truncateOptions.hasOwnProperty('words') && truncateOptions.words === 0) {
|
||||
return new hbs.handlebars.SafeString(
|
||||
@ -314,7 +311,7 @@ coreHelpers.content = function (options) {
|
||||
};
|
||||
|
||||
coreHelpers.title = function () {
|
||||
return new hbs.handlebars.SafeString(hbs.handlebars.Utils.escapeExpression(this.title || ''));
|
||||
return new hbs.handlebars.SafeString(hbs.handlebars.Utils.escapeExpression(this.title || ''));
|
||||
};
|
||||
|
||||
// ### Excerpt Helper
|
||||
@ -416,7 +413,6 @@ 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 (this.tag !== undefined) {
|
||||
classes.push('tag-template');
|
||||
classes.push('tag-' + this.tag.slug);
|
||||
@ -431,7 +427,6 @@ coreHelpers.body_class = function (options) {
|
||||
classes.push('paged');
|
||||
// To be removed from pages by #2597 when we're ready to deprecate this
|
||||
classes.push('archive-template');
|
||||
|
||||
} else if (!this.relativeUrl || this.relativeUrl === '/' || this.relativeUrl === '') {
|
||||
classes.push('home-template');
|
||||
} else if (post) {
|
||||
@ -653,7 +648,7 @@ coreHelpers.foreach = function (context, options) {
|
||||
data.first = data.rowEnd = data.rowStart = data.last = data.even = data.odd = false;
|
||||
data = setKeys(data, i, j, columns);
|
||||
}
|
||||
ret = ret + fn(context[i], { data: data });
|
||||
ret = ret + fn(context[i], {data: data});
|
||||
}
|
||||
} else {
|
||||
for (key in context) {
|
||||
@ -785,9 +780,9 @@ coreHelpers.plural = function (context, options) {
|
||||
if (context === 0) {
|
||||
return new hbs.handlebars.SafeString(options.hash.empty);
|
||||
} else if (context === 1) {
|
||||
return new hbs.handlebars.SafeString(options.hash.singular.replace("%", context));
|
||||
return new hbs.handlebars.SafeString(options.hash.singular.replace('%', context));
|
||||
} else if (context >= 2) {
|
||||
return new hbs.handlebars.SafeString(options.hash.plural.replace("%", context));
|
||||
return new hbs.handlebars.SafeString(options.hash.plural.replace('%', context));
|
||||
}
|
||||
};
|
||||
|
||||
@ -836,17 +831,13 @@ function registerAdminHelper(name, fn) {
|
||||
coreHelpers.adminHbs.registerHelper(name, fn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
registerHelpers = function (adminHbs, assetHash) {
|
||||
|
||||
// Expose hbs instance for admin
|
||||
coreHelpers.adminHbs = adminHbs;
|
||||
|
||||
// Store hash for assets
|
||||
coreHelpers.assetHash = assetHash;
|
||||
|
||||
|
||||
// Register theme helpers
|
||||
registerThemeHelper('asset', coreHelpers.asset);
|
||||
|
||||
@ -892,7 +883,6 @@ registerHelpers = function (adminHbs, assetHash) {
|
||||
|
||||
registerAsyncThemeHelper('url', coreHelpers.url);
|
||||
|
||||
|
||||
// Register admin helpers
|
||||
registerAdminHelper('ghost_script_tags', coreHelpers.ghost_script_tags);
|
||||
|
||||
|
@ -7,7 +7,6 @@ var templates = {},
|
||||
// Execute a template helper
|
||||
// All template helpers are register as partial view.
|
||||
templates.execute = function (name, context) {
|
||||
|
||||
var partial = hbs.handlebars.partials[name];
|
||||
|
||||
if (partial === undefined) {
|
||||
@ -66,4 +65,4 @@ templates.getThemeViewForTag = function (themePaths, tag) {
|
||||
return view;
|
||||
};
|
||||
|
||||
module.exports = templates;
|
||||
module.exports = templates;
|
||||
|
@ -36,10 +36,10 @@ function doFirstRun() {
|
||||
'See <a href="http://support.ghost.org/" target="_blank">http://support.ghost.org</a> for instructions.'
|
||||
];
|
||||
|
||||
return api.notifications.add({ notifications: [{
|
||||
return api.notifications.add({notifications: [{
|
||||
type: 'info',
|
||||
message: firstRunMessage.join(' ')
|
||||
}] }, {context: {internal: true}});
|
||||
}]}, {context: {internal: true}});
|
||||
}
|
||||
|
||||
function initDbHashAndFirstRun() {
|
||||
@ -73,9 +73,9 @@ function builtFilesExist() {
|
||||
helpers.scriptFiles.production : helpers.scriptFiles.development;
|
||||
|
||||
function checkExist(fileName) {
|
||||
var errorMessage = "Javascript files have not been built.",
|
||||
errorHelp = "\nPlease read the getting started instructions at:" +
|
||||
"\nhttps://github.com/TryGhost/Ghost#getting-started-guide-for-developers";
|
||||
var errorMessage = 'Javascript files have not been built.',
|
||||
errorHelp = '\nPlease read the getting started instructions at:' +
|
||||
'\nhttps://github.com/TryGhost/Ghost#getting-started-guide-for-developers';
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.exists(fileName, function (exists) {
|
||||
@ -105,23 +105,23 @@ function builtFilesExist() {
|
||||
// in the future apps will want to hook into here
|
||||
function initNotifications() {
|
||||
if (mailer.state && mailer.state.usingDirect) {
|
||||
api.notifications.add({ notifications: [{
|
||||
api.notifications.add({notifications: [{
|
||||
type: 'info',
|
||||
message: [
|
||||
"Ghost is attempting to use a direct method to send e-mail.",
|
||||
"It is recommended that you explicitly configure an e-mail service.",
|
||||
"See <a href=\"http://support.ghost.org/mail\" target=\"_blank\">http://support.ghost.org/mail</a> for instructions"
|
||||
'Ghost is attempting to use a direct method to send e-mail.',
|
||||
'It is recommended that you explicitly configure an e-mail service.',
|
||||
'See <a href=\'http://support.ghost.org/mail\' target=\'_blank\'>http://support.ghost.org/mail</a> for instructions'
|
||||
].join(' ')
|
||||
}] }, {context: {internal: true}});
|
||||
}]}, {context: {internal: true}});
|
||||
}
|
||||
if (mailer.state && mailer.state.emailDisabled) {
|
||||
api.notifications.add({ notifications: [{
|
||||
api.notifications.add({notifications: [{
|
||||
type: 'warn',
|
||||
message: [
|
||||
"Ghost is currently unable to send e-mail.",
|
||||
"See <a href=\"http://support.ghost.org/mail\" target=\"_blank\">http://support.ghost.org/mail</a> for instructions"
|
||||
'Ghost is currently unable to send e-mail.',
|
||||
'See <a href=\'http://support.ghost.org/mail\' target=\'_blank\'>http://support.ghost.org/mail</a> for instructions'
|
||||
].join(' ')
|
||||
}] }, {context: {internal: true}});
|
||||
}]}, {context: {internal: true}});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,6 @@ GhostMailer.prototype.createTransport = function () {
|
||||
this.transport = nodemailer.createTransport(config.mail.transport, _.clone(config.mail.options) || {});
|
||||
};
|
||||
|
||||
|
||||
GhostMailer.prototype.fromAddress = function () {
|
||||
var from = config.mail && config.mail.fromaddress,
|
||||
domain;
|
||||
@ -79,21 +78,21 @@ GhostMailer.prototype.send = function (message) {
|
||||
return resolve(response);
|
||||
}
|
||||
|
||||
response.statusHandler.once("failed", function (data) {
|
||||
response.statusHandler.once('failed', function (data) {
|
||||
var reason = 'Email Error: Failed sending email';
|
||||
if (data.error.errno === "ENOTFOUND") {
|
||||
if (data.error.errno === 'ENOTFOUND') {
|
||||
reason += ': there is no mail server at this address: ' + data.domain;
|
||||
}
|
||||
reason += '.';
|
||||
return reject(new Error(reason));
|
||||
});
|
||||
|
||||
response.statusHandler.once("requeue", function (data) {
|
||||
return reject(new Error("Email Error: message was not sent, requeued. Probably will not be sent. :( \nMore info: " + data.error.message));
|
||||
response.statusHandler.once('requeue', function (data) {
|
||||
return reject(new Error('Email Error: message was not sent, requeued. Probably will not be sent. :( \nMore info: ' + data.error.message));
|
||||
});
|
||||
|
||||
response.statusHandler.once("sent", function () {
|
||||
return resolve("Message was accepted by the mail server. Make sure to check inbox and spam folders. :)");
|
||||
response.statusHandler.once('sent', function () {
|
||||
return resolve('Message was accepted by the mail server. Make sure to check inbox and spam folders. :)');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -50,7 +50,7 @@ passport.use(new BearerStrategy(
|
||||
.then(function (model) {
|
||||
if (model) {
|
||||
var user = model.toJSON(),
|
||||
info = { scope: '*' };
|
||||
info = {scope: '*'};
|
||||
return done(null, {id: user.id}, info);
|
||||
}
|
||||
return done(null, false);
|
||||
@ -64,4 +64,3 @@ passport.use(new BearerStrategy(
|
||||
});
|
||||
}
|
||||
));
|
||||
|
||||
|
@ -16,7 +16,7 @@ function ghostBusBoy(req, res, next) {
|
||||
return next();
|
||||
}
|
||||
|
||||
busboy = new BusBoy({ headers: req.headers });
|
||||
busboy = new BusBoy({headers: req.headers});
|
||||
tmpDir = os.tmpdir();
|
||||
|
||||
req.files = req.files || {};
|
||||
@ -59,7 +59,6 @@ function ghostBusBoy(req, res, next) {
|
||||
});
|
||||
|
||||
file.pipe(stream);
|
||||
|
||||
});
|
||||
|
||||
busboy.on('error', function (error) {
|
||||
@ -78,4 +77,4 @@ function ghostBusBoy(req, res, next) {
|
||||
req.pipe(busboy);
|
||||
}
|
||||
|
||||
module.exports = ghostBusBoy;
|
||||
module.exports = ghostBusBoy;
|
||||
|
@ -63,7 +63,7 @@ function activateTheme(activeTheme) {
|
||||
expressServer.cache = {};
|
||||
|
||||
// set view engine
|
||||
hbsOptions = { partialsDir: [ config.paths.helperTemplates ] };
|
||||
hbsOptions = {partialsDir: [config.paths.helperTemplates]};
|
||||
|
||||
fs.stat(themePartials, function (err, stats) {
|
||||
// Check that the theme has a partials directory before trying to use it
|
||||
@ -98,7 +98,7 @@ function configHbsForContext(req, res, next) {
|
||||
} else {
|
||||
expressServer.disable('admin');
|
||||
var themeData = initThemeData(req.secure);
|
||||
hbs.updateTemplateOptions({ data: {blog: themeData} });
|
||||
hbs.updateTemplateOptions({data: {blog: themeData}});
|
||||
expressServer.engine('hbs', expressServer.get('theme view engine'));
|
||||
expressServer.set('views', path.join(config.paths.themePath, expressServer.get('activeTheme')));
|
||||
}
|
||||
@ -161,7 +161,7 @@ function uncapitalise(req, res, next) {
|
||||
if (isSignupOrReset) {
|
||||
pathToTest = isSignupOrReset[1];
|
||||
}
|
||||
|
||||
|
||||
// Do not lowercase anything after /api/v0.1/ to protect :key/:slug
|
||||
if (isAPI) {
|
||||
pathToTest = isAPI[1];
|
||||
@ -218,7 +218,7 @@ function robots() {
|
||||
filePath = path.join(config.paths.corePath, '/shared/robots.txt');
|
||||
|
||||
return function robots(req, res, next) {
|
||||
if ('/robots.txt' === req.url) {
|
||||
if (req.url === '/robots.txt') {
|
||||
if (content) {
|
||||
res.writeHead(200, content.headers);
|
||||
res.end(content.body);
|
||||
@ -314,7 +314,7 @@ setupMiddleware = function (server) {
|
||||
|
||||
// Body parsing
|
||||
expressServer.use(bodyParser.json());
|
||||
expressServer.use(bodyParser.urlencoded({ extended: true }));
|
||||
expressServer.use(bodyParser.urlencoded({extended: true}));
|
||||
|
||||
expressServer.use(passport.initialize());
|
||||
|
||||
@ -322,7 +322,6 @@ setupMiddleware = function (server) {
|
||||
expressServer.use(middleware.cacheControl('public'));
|
||||
expressServer.use('/ghost/', middleware.cacheControl('private'));
|
||||
|
||||
|
||||
// enable authentication
|
||||
expressServer.use(middleware.authenticate);
|
||||
|
||||
|
@ -12,6 +12,7 @@ var _ = require('lodash'),
|
||||
errors = require('../errors'),
|
||||
utils = require('../utils'),
|
||||
|
||||
middleware,
|
||||
expressServer,
|
||||
oauthServer,
|
||||
loginSecurity = [],
|
||||
@ -31,7 +32,7 @@ function cacheOauthServer(server) {
|
||||
oauthServer = server;
|
||||
}
|
||||
|
||||
var middleware = {
|
||||
middleware = {
|
||||
|
||||
// ### Authenticate Middleware
|
||||
// authentication has to be done for /ghost/* routes with
|
||||
@ -52,14 +53,13 @@ var middleware = {
|
||||
if (res.isAdmin) {
|
||||
if (subPath.indexOf('/ghost/api/') === 0
|
||||
&& path.indexOf('/ghost/api/v0.1/authentication/') !== 0) {
|
||||
|
||||
return passport.authenticate('bearer', { session: false, failWithError: true },
|
||||
return passport.authenticate('bearer', {session: false, failWithError: true},
|
||||
function (err, user, info) {
|
||||
if (err) {
|
||||
return next(err); // will generate a 500 error
|
||||
}
|
||||
// Generate a JSON response reflecting authentication status
|
||||
if (! user) {
|
||||
if (!user) {
|
||||
var msg = {
|
||||
type: 'error',
|
||||
message: 'Please Sign In',
|
||||
@ -84,8 +84,8 @@ var middleware = {
|
||||
cacheControl: function (options) {
|
||||
/*jslint unparam:true*/
|
||||
var profiles = {
|
||||
'public': 'public, max-age=0',
|
||||
'private': 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'
|
||||
public: 'public, max-age=0',
|
||||
private: 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'
|
||||
},
|
||||
output;
|
||||
|
||||
@ -212,8 +212,6 @@ var middleware = {
|
||||
deniedEmailRateLimit = (forgottenSecurity[index].count > rateForgottenAttempts);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (deniedEmailRateLimit) {
|
||||
errors.logError(
|
||||
'Only ' + rateForgottenAttempts + ' forgotten password attempts per email every ' +
|
||||
@ -254,7 +252,7 @@ var middleware = {
|
||||
// ### Authenticate Client Middleware
|
||||
// authenticate client that is asking for an access token
|
||||
authenticateClient: function (req, res, next) {
|
||||
return passport.authenticate(['oauth2-client-password'], { session: false })(req, res, next);
|
||||
return passport.authenticate(['oauth2-client-password'], {session: false})(req, res, next);
|
||||
},
|
||||
|
||||
// ### Generate access token Middleware
|
||||
|
@ -5,11 +5,9 @@ var oauth2orize = require('oauth2orize'),
|
||||
|
||||
oauth;
|
||||
|
||||
|
||||
oauth = {
|
||||
|
||||
init: function (oauthServer, resetSpamCounter) {
|
||||
|
||||
// remove all expired accesstokens on startup
|
||||
models.Accesstoken.destroyAllExpired();
|
||||
|
||||
@ -30,8 +28,7 @@ oauth = {
|
||||
}
|
||||
// Validate the user
|
||||
return models.User.check({email: username, password: password}).then(function (user) {
|
||||
|
||||
//Everything validated, return the access- and refreshtoken
|
||||
// Everything validated, return the access- and refreshtoken
|
||||
var accessToken = utils.uid(256),
|
||||
refreshToken = utils.uid(256),
|
||||
accessExpires = Date.now() + utils.ONE_HOUR_MS,
|
||||
@ -53,7 +50,7 @@ oauth = {
|
||||
|
||||
// Exchange the refresh token to obtain an access token. The callback accepts the
|
||||
// `client`, which is exchanging a `refreshToken` previously issued by the server
|
||||
// for verification. If these values are validated, the application issues an
|
||||
// for verification. If these values are validated, the application issues an
|
||||
// access token on behalf of the user who authorized the code.
|
||||
oauthServer.exchange(oauth2orize.exchange.refreshToken(function (client, refreshToken, scope, done) {
|
||||
models.Refreshtoken.forge({token: refreshToken})
|
||||
@ -89,4 +86,4 @@ oauth = {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = oauth;
|
||||
module.exports = oauth;
|
||||
|
@ -15,4 +15,4 @@ Accesstokens = ghostBookshelf.Collection.extend({
|
||||
module.exports = {
|
||||
Accesstoken: ghostBookshelf.model('Accesstoken', Accesstoken),
|
||||
Accesstokens: ghostBookshelf.collection('Accesstokens', Accesstokens)
|
||||
};
|
||||
};
|
||||
|
@ -2,8 +2,6 @@ var ghostBookshelf = require('./base'),
|
||||
App,
|
||||
Apps;
|
||||
|
||||
|
||||
|
||||
App = ghostBookshelf.Model.extend({
|
||||
tableName: 'apps',
|
||||
|
||||
|
@ -17,4 +17,4 @@ AppFields = ghostBookshelf.Collection.extend({
|
||||
module.exports = {
|
||||
AppField: ghostBookshelf.model('AppField', AppField),
|
||||
AppFields: ghostBookshelf.collection('AppFields', AppFields)
|
||||
};
|
||||
};
|
||||
|
@ -17,4 +17,4 @@ AppSettings = ghostBookshelf.Collection.extend({
|
||||
module.exports = {
|
||||
AppSetting: ghostBookshelf.model('AppSetting', AppSetting),
|
||||
AppSettings: ghostBookshelf.collection('AppSettings', AppSettings)
|
||||
};
|
||||
};
|
||||
|
@ -319,7 +319,7 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
|
||||
|
||||
checkIfSlugExists = function (slugToFind) {
|
||||
var args = {slug: slugToFind};
|
||||
//status is needed for posts
|
||||
// status is needed for posts
|
||||
if (options && options.status) {
|
||||
args.status = options.status;
|
||||
}
|
||||
@ -356,7 +356,7 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
|
||||
slug = /^(ghost|ghost\-admin|admin|wp\-admin|wp\-login|dashboard|logout|login|setup|signin|signup|signout|register|archive|archives|category|categories|tag|tags|page|pages|post|posts|public|user|users|rss|feed|app|apps)$/g
|
||||
.test(slug) ? slug + '-' + baseName : slug;
|
||||
|
||||
//if slug is empty after trimming use the model name
|
||||
// if slug is empty after trimming use the model name
|
||||
if (!slug) {
|
||||
slug = baseName;
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ Basetoken = ghostBookshelf.Model.extend({
|
||||
}
|
||||
|
||||
return Promise.reject(new errors.NotFoundError('Token not found'));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Basetoken;
|
||||
module.exports = Basetoken;
|
||||
|
@ -3,7 +3,6 @@ var ghostBookshelf = require('./base'),
|
||||
Client,
|
||||
Clients;
|
||||
|
||||
|
||||
Client = ghostBookshelf.Model.extend({
|
||||
tableName: 'clients'
|
||||
});
|
||||
@ -15,4 +14,4 @@ Clients = ghostBookshelf.Collection.extend({
|
||||
module.exports = {
|
||||
Client: ghostBookshelf.model('Client', Client),
|
||||
Clients: ghostBookshelf.collection('Clients', Clients)
|
||||
};
|
||||
};
|
||||
|
@ -20,11 +20,9 @@ models = {
|
||||
|
||||
// Require all files in this directory
|
||||
return requireTree.readAll(__dirname).then(function (modelFiles) {
|
||||
|
||||
// For each found file, excluding those we don't want,
|
||||
// we will require it and cache it here.
|
||||
_.each(modelFiles, function (path, fileName) {
|
||||
|
||||
// Return early if this fileName is one of the ones we want
|
||||
// to exclude.
|
||||
if (_.contains(self.excludeFiles, fileName)) {
|
||||
@ -36,7 +34,6 @@ models = {
|
||||
|
||||
// Cache its `export` object onto this object.
|
||||
_.extend(self, file);
|
||||
|
||||
});
|
||||
|
||||
return;
|
||||
|
@ -62,7 +62,7 @@ Post = ghostBookshelf.Model.extend({
|
||||
this.set('html', converter.makeHtml(this.get('markdown')));
|
||||
|
||||
// disabling sanitization until we can implement a better version
|
||||
//this.set('title', this.sanitize('title').trim());
|
||||
// this.set('title', this.sanitize('title').trim());
|
||||
this.set('title', this.get('title').trim());
|
||||
|
||||
if ((this.hasChanged('status') || !this.get('published_at')) && this.get('status') === 'published') {
|
||||
@ -83,7 +83,6 @@ Post = ghostBookshelf.Model.extend({
|
||||
self.set({slug: slug});
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
creating: function (newPage, attr, options) {
|
||||
@ -244,16 +243,15 @@ Post = ghostBookshelf.Model.extend({
|
||||
/**
|
||||
* ### Find All
|
||||
*
|
||||
* @param options
|
||||
* @param {Object} options
|
||||
* @returns {*}
|
||||
*/
|
||||
findAll: function (options) {
|
||||
options = options || {};
|
||||
options.withRelated = _.union([ 'tags', 'fields' ], options.include);
|
||||
options.withRelated = _.union(['tags', 'fields'], options.include);
|
||||
return ghostBookshelf.Model.findAll.call(this, options);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* #### findPage
|
||||
* Find results by page - returns an object containing the
|
||||
@ -272,7 +270,7 @@ Post = ghostBookshelf.Model.extend({
|
||||
* total: __
|
||||
* }
|
||||
*
|
||||
* @params {Object} options
|
||||
* @param {Object} options
|
||||
*/
|
||||
findPage: function (options) {
|
||||
options = options || {};
|
||||
@ -323,7 +321,7 @@ Post = ghostBookshelf.Model.extend({
|
||||
}
|
||||
|
||||
// Add related objects
|
||||
options.withRelated = _.union([ 'tags', 'fields' ], options.include);
|
||||
options.withRelated = _.union(['tags', 'fields'], options.include);
|
||||
|
||||
// If a query param for a tag is attached
|
||||
// we need to fetch the tag model to find its id
|
||||
@ -468,7 +466,7 @@ Post = ghostBookshelf.Model.extend({
|
||||
}
|
||||
|
||||
// Add related objects
|
||||
options.withRelated = _.union([ 'tags', 'fields' ], options.include);
|
||||
options.withRelated = _.union(['tags', 'fields'], options.include);
|
||||
|
||||
return ghostBookshelf.Model.findOne.call(this, data, options);
|
||||
},
|
||||
@ -524,7 +522,6 @@ Post = ghostBookshelf.Model.extend({
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* ### destroyByAuthor
|
||||
* @param {[type]} options has context and id. Context is the user doing the destroy, id is the user to destroy
|
||||
@ -548,7 +545,6 @@ Post = ghostBookshelf.Model.extend({
|
||||
return Promise.reject(new errors.NotFoundError('No user found'));
|
||||
},
|
||||
|
||||
|
||||
permissible: function (postModelOrId, action, context, loadedPermissions, hasUserPermission, hasAppPermission) {
|
||||
var self = this,
|
||||
postModel = postModelOrId,
|
||||
|
@ -15,4 +15,4 @@ Refreshtokens = ghostBookshelf.Collection.extend({
|
||||
module.exports = {
|
||||
Refreshtoken: ghostBookshelf.model('Refreshtoken', Refreshtoken),
|
||||
Refreshtokens: ghostBookshelf.collection('Refreshtokens', Refreshtokens)
|
||||
};
|
||||
};
|
||||
|
@ -39,7 +39,6 @@ Role = ghostBookshelf.Model.extend({
|
||||
return options;
|
||||
},
|
||||
|
||||
|
||||
permissible: function (roleModelOrId, action, context, loadedPermissions, hasUserPermission, hasAppPermission) {
|
||||
var self = this,
|
||||
checkAgainst = [],
|
||||
@ -60,11 +59,11 @@ Role = ghostBookshelf.Model.extend({
|
||||
}
|
||||
|
||||
if (action === 'assign' && loadedPermissions.user) {
|
||||
if (_.any(loadedPermissions.user.roles, { 'name': 'Owner' })) {
|
||||
if (_.any(loadedPermissions.user.roles, {name: 'Owner'})) {
|
||||
checkAgainst = ['Owner', 'Administrator', 'Editor', 'Author'];
|
||||
} else if (_.any(loadedPermissions.user.roles, { 'name': 'Administrator' })) {
|
||||
} else if (_.any(loadedPermissions.user.roles, {name: 'Administrator'})) {
|
||||
checkAgainst = ['Administrator', 'Editor', 'Author'];
|
||||
} else if (_.any(loadedPermissions.user.roles, { 'name': 'Editor' })) {
|
||||
} else if (_.any(loadedPermissions.user.roles, {name: 'Editor'})) {
|
||||
checkAgainst = ['Author'];
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ Settings = ghostBookshelf.Model.extend({
|
||||
findOne: function (options) {
|
||||
// Allow for just passing the key instead of attributes
|
||||
if (!_.isObject(options)) {
|
||||
options = { key: options };
|
||||
options = {key: options};
|
||||
}
|
||||
return Promise.resolve(ghostBookshelf.Model.findOne.call(this, options));
|
||||
},
|
||||
@ -102,14 +102,12 @@ Settings = ghostBookshelf.Model.extend({
|
||||
|
||||
item = self.filterData(item);
|
||||
|
||||
return Settings.forge({ key: item.key }).fetch(options).then(function (setting) {
|
||||
|
||||
return Settings.forge({key: item.key}).fetch(options).then(function (setting) {
|
||||
if (setting) {
|
||||
return setting.save({value: item.value}, options);
|
||||
}
|
||||
|
||||
return Promise.reject(new errors.NotFoundError('Unable to find setting to update: ' + item.key));
|
||||
|
||||
}, errors.logAndThrowError);
|
||||
});
|
||||
},
|
||||
@ -119,7 +117,7 @@ Settings = ghostBookshelf.Model.extend({
|
||||
return Promise.reject(new errors.NotFoundError('Unable to find default setting: ' + key));
|
||||
}
|
||||
|
||||
return this.findOne({ key: key }).then(function (foundSetting) {
|
||||
return this.findOne({key: key}).then(function (foundSetting) {
|
||||
if (foundSetting) {
|
||||
return foundSetting;
|
||||
}
|
||||
|
@ -143,12 +143,12 @@ User = ghostBookshelf.Model.extend({
|
||||
/**
|
||||
* ### Find All
|
||||
*
|
||||
* @param options
|
||||
* @param {Object} options
|
||||
* @returns {*}
|
||||
*/
|
||||
findAll: function (options) {
|
||||
options = options || {};
|
||||
options.withRelated = _.union([ 'roles' ], options.include);
|
||||
options.withRelated = _.union(['roles'], options.include);
|
||||
return ghostBookshelf.Model.findAll.call(this, options);
|
||||
},
|
||||
|
||||
@ -172,7 +172,7 @@ User = ghostBookshelf.Model.extend({
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @params {Object} options
|
||||
* @param {Object} options
|
||||
*/
|
||||
findPage: function (options) {
|
||||
options = options || {};
|
||||
@ -199,14 +199,14 @@ User = ghostBookshelf.Model.extend({
|
||||
whereIn: {}
|
||||
}, options);
|
||||
|
||||
//TODO: there are multiple statuses that make a user "active" or "invited" - we a way to translate/map them:
|
||||
//TODO (cont'd from above): * valid "active" statuses: active, warn-1, warn-2, warn-3, warn-4, locked
|
||||
//TODO (cont'd from above): * valid "invited" statuses" invited, invited-pending
|
||||
// TODO: there are multiple statuses that make a user "active" or "invited" - we a way to translate/map them:
|
||||
// TODO (cont'd from above): * valid "active" statuses: active, warn-1, warn-2, warn-3, warn-4, locked
|
||||
// TODO (cont'd from above): * valid "invited" statuses" invited, invited-pending
|
||||
|
||||
// Filter on the status. A status of 'all' translates to no filter since we want all statuses
|
||||
if (options.status && options.status !== 'all') {
|
||||
// make sure that status is valid
|
||||
//TODO: need a better way of getting a list of statuses other than hard-coding them...
|
||||
// TODO: need a better way of getting a list of statuses other than hard-coding them...
|
||||
options.status = _.indexOf(
|
||||
['active', 'warn-1', 'warn-2', 'warn-3', 'warn-4', 'locked', 'invited', 'inactive'],
|
||||
options.status) !== -1 ? options.status : 'active';
|
||||
@ -227,9 +227,9 @@ User = ghostBookshelf.Model.extend({
|
||||
}
|
||||
|
||||
// Add related objects
|
||||
options.withRelated = _.union([ 'roles' ], options.include);
|
||||
options.withRelated = _.union(['roles'], options.include);
|
||||
|
||||
//only include a limit-query if a numeric limit is provided
|
||||
// only include a limit-query if a numeric limit is provided
|
||||
if (_.isNumber(options.limit)) {
|
||||
userCollection
|
||||
.query('limit', options.limit)
|
||||
@ -245,7 +245,6 @@ User = ghostBookshelf.Model.extend({
|
||||
|
||||
return Promise.resolve(fetchRoleQuery())
|
||||
.then(function () {
|
||||
|
||||
if (roleInstance) {
|
||||
userCollection
|
||||
.query('join', 'roles_users', 'roles_users.user_id', '=', 'users.id')
|
||||
@ -325,7 +324,6 @@ User = ghostBookshelf.Model.extend({
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return data;
|
||||
})
|
||||
.catch(errors.logAndThrowError);
|
||||
@ -348,12 +346,12 @@ User = ghostBookshelf.Model.extend({
|
||||
delete data.status;
|
||||
|
||||
options = options || {};
|
||||
options.withRelated = _.union([ 'roles' ], options.include);
|
||||
options.withRelated = _.union(['roles'], options.include);
|
||||
|
||||
// Support finding by role
|
||||
if (data.role) {
|
||||
options.withRelated = [{
|
||||
'roles': function (qb) {
|
||||
roles: function (qb) {
|
||||
qb.where('name', data.role);
|
||||
}
|
||||
}];
|
||||
@ -365,13 +363,12 @@ User = ghostBookshelf.Model.extend({
|
||||
|
||||
data = this.filterData(data);
|
||||
|
||||
|
||||
if (status === 'active') {
|
||||
query.query('whereIn', 'status', activeStates);
|
||||
} else if (status === 'invited') {
|
||||
query.query('whereIn', 'status', invitedStates);
|
||||
} else if (status !== 'all') {
|
||||
query.query('where', { 'status': options.status});
|
||||
query.query('where', {status: options.status});
|
||||
}
|
||||
|
||||
options = this.filterOptions(options, 'findOne');
|
||||
@ -390,10 +387,9 @@ User = ghostBookshelf.Model.extend({
|
||||
roleId;
|
||||
|
||||
options = options || {};
|
||||
options.withRelated = _.union([ 'roles' ], options.include);
|
||||
options.withRelated = _.union(['roles'], options.include);
|
||||
|
||||
return ghostBookshelf.Model.edit.call(this, data, options).then(function (user) {
|
||||
|
||||
if (data.roles) {
|
||||
roleId = parseInt(data.roles[0].id || data.roles[0], 10);
|
||||
|
||||
@ -443,7 +439,7 @@ User = ghostBookshelf.Model.extend({
|
||||
roles;
|
||||
|
||||
options = this.filterOptions(options, 'add');
|
||||
options.withRelated = _.union([ 'roles' ], options.include);
|
||||
options.withRelated = _.union(['roles'], options.include);
|
||||
|
||||
return ghostBookshelf.model('Role').findOne({name: 'Author'}, _.pick(options, 'transacting')).then(function (authorRole) {
|
||||
// Get the role we're going to assign to this user, or the author role if there isn't one
|
||||
@ -473,7 +469,7 @@ User = ghostBookshelf.Model.extend({
|
||||
}).then(function (addedUser) {
|
||||
// Assign the userData to our created user so we can pass it back
|
||||
userData = addedUser;
|
||||
//if we are given a "role" object, only pass in the role ID in place of the full object
|
||||
// if we are given a "role" object, only pass in the role ID in place of the full object
|
||||
roles = _.map(roles, function (role) {
|
||||
if (_.isString(role)) {
|
||||
return parseInt(role, 10);
|
||||
@ -496,7 +492,7 @@ User = ghostBookshelf.Model.extend({
|
||||
userData = this.filterData(data);
|
||||
|
||||
options = this.filterOptions(options, 'setup');
|
||||
options.withRelated = _.union([ 'roles' ], options.include);
|
||||
options.withRelated = _.union(['roles'], options.include);
|
||||
|
||||
return validatePasswordLength(userData.password).then(function () {
|
||||
// Generate a new password hash
|
||||
@ -524,7 +520,6 @@ User = ghostBookshelf.Model.extend({
|
||||
|
||||
// If we passed in an id instead of a model, get the model then check the permissions
|
||||
if (_.isNumber(userModelOrId) || _.isString(userModelOrId)) {
|
||||
|
||||
// Grab the original args without the first one
|
||||
origArgs = _.toArray(arguments).slice(1);
|
||||
// Get the actual post model
|
||||
@ -539,12 +534,12 @@ User = ghostBookshelf.Model.extend({
|
||||
if (action === 'edit') {
|
||||
// Users with the role 'Editor' and 'Author' have complex permissions when the action === 'edit'
|
||||
// We now have all the info we need to construct the permissions
|
||||
if (_.any(loadedPermissions.user.roles, { 'name': 'Author' })) {
|
||||
if (_.any(loadedPermissions.user.roles, {name: 'Author'})) {
|
||||
// If this is the same user that requests the operation allow it.
|
||||
hasUserPermission = hasUserPermission || context.user === userModel.get('id');
|
||||
}
|
||||
|
||||
if (_.any(loadedPermissions.user.roles, { 'name': 'Editor' })) {
|
||||
if (_.any(loadedPermissions.user.roles, {name: 'Editor'})) {
|
||||
// If this is the same user that requests the operation allow it.
|
||||
hasUserPermission = context.user === userModel.get('id');
|
||||
|
||||
@ -560,7 +555,7 @@ User = ghostBookshelf.Model.extend({
|
||||
}
|
||||
|
||||
// Users with the role 'Editor' have complex permissions when the action === 'destroy'
|
||||
if (_.any(loadedPermissions.user.roles, { 'name': 'Editor' })) {
|
||||
if (_.any(loadedPermissions.user.roles, {name: 'Editor'})) {
|
||||
// If this is the same user that requests the operation allow it.
|
||||
hasUserPermission = context.user === userModel.get('id');
|
||||
|
||||
@ -620,7 +615,6 @@ User = ghostBookshelf.Model.extend({
|
||||
|
||||
// Use comma structure, not .catch, because we don't want to catch incorrect passwords
|
||||
}, function (error) {
|
||||
|
||||
// If we get a validation or other error during this save, catch it and log it, but don't
|
||||
// cause a login error because of it. The user validation is not important here.
|
||||
errors.logError(
|
||||
@ -632,7 +626,7 @@ User = ghostBookshelf.Model.extend({
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(user.set({status : 'active', last_login : new Date()}).save({validate: false}))
|
||||
return Promise.resolve(user.set({status: 'active', last_login: new Date()}).save({validate: false}))
|
||||
.catch(function (error) {
|
||||
// If we get a validation or other error during this save, catch it and log it, but don't
|
||||
// cause a login error because of it. The user validation is not important here.
|
||||
@ -648,7 +642,6 @@ User = ghostBookshelf.Model.extend({
|
||||
return Promise.reject(new errors.NoPermissionError('Your account is locked due to too many ' +
|
||||
'login attempts. Please reset your password to log in again by clicking ' +
|
||||
'the "Forgotten password?" link!'));
|
||||
|
||||
}, function (error) {
|
||||
if (error.message === 'NotFound' || error.message === 'EmptyResponse') {
|
||||
return Promise.reject(new errors.NotFoundError('There is no user with that email address.'));
|
||||
@ -660,7 +653,10 @@ User = ghostBookshelf.Model.extend({
|
||||
|
||||
/**
|
||||
* Naive change password method
|
||||
* @param {object} _userdata email, old pw, new pw, new pw2
|
||||
* @param {String} oldPassword
|
||||
* @param {String} newPassword
|
||||
* @param {String} ne2Password
|
||||
* @param {Object} options
|
||||
*/
|
||||
changePassword: function (oldPassword, newPassword, ne2Password, options) {
|
||||
var self = this,
|
||||
@ -818,7 +814,6 @@ User = ghostBookshelf.Model.extend({
|
||||
contextUser = ctxUser;
|
||||
return User.findOne({id: object.id});
|
||||
}).then(function (user) {
|
||||
|
||||
var currentRoles = user.toJSON().roles;
|
||||
if (!_.contains(currentRoles, adminRole.id)) {
|
||||
return Promise.reject(new errors.ValidationError('Only administrators can be assigned the owner role.'));
|
||||
@ -833,9 +828,9 @@ User = ghostBookshelf.Model.extend({
|
||||
}).then(function () {
|
||||
return Users.forge()
|
||||
.query('whereIn', 'id', [contextUser.id, assignUser.id])
|
||||
.fetch({ withRelated: ['roles'] });
|
||||
.fetch({withRelated: ['roles']});
|
||||
}).then(function (users) {
|
||||
return users.toJSON({ include: ['roles'] });
|
||||
return users.toJSON({include: ['roles']});
|
||||
});
|
||||
},
|
||||
|
||||
@ -856,7 +851,7 @@ User = ghostBookshelf.Model.extend({
|
||||
|
||||
resolve(userData);
|
||||
}).on('error', function () {
|
||||
//Error making request just continue.
|
||||
// Error making request just continue.
|
||||
resolve(userData);
|
||||
});
|
||||
});
|
||||
|
@ -1,10 +1,11 @@
|
||||
var _ = require('lodash'),
|
||||
Models = require('../models'),
|
||||
errors = require('../errors');
|
||||
errors = require('../errors'),
|
||||
effective;
|
||||
|
||||
var effective = {
|
||||
effective = {
|
||||
user: function (id) {
|
||||
return Models.User.findOne({id: id, status: 'all'}, { include: ['permissions', 'roles', 'roles.permissions'] })
|
||||
return Models.User.findOne({id: id, status: 'all'}, {include: ['permissions', 'roles', 'roles.permissions']})
|
||||
.then(function (foundUser) {
|
||||
var seenPerms = {},
|
||||
rolePerms = _.map(foundUser.related('roles').models, function (role) {
|
||||
@ -34,7 +35,7 @@ var effective = {
|
||||
},
|
||||
|
||||
app: function (appName) {
|
||||
return Models.App.findOne({name: appName}, { withRelated: ['permissions'] })
|
||||
return Models.App.findOne({name: appName}, {withRelated: ['permissions']})
|
||||
.then(function (foundApp) {
|
||||
if (!foundApp) {
|
||||
return [];
|
||||
@ -45,4 +46,4 @@ var effective = {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = effective;
|
||||
module.exports = effective;
|
||||
|
@ -49,18 +49,18 @@ CanThisResult = function () {
|
||||
return;
|
||||
};
|
||||
|
||||
CanThisResult.prototype.buildObjectTypeHandlers = function (obj_types, act_type, context, permissionLoad) {
|
||||
CanThisResult.prototype.buildObjectTypeHandlers = function (objTypes, actType, context, permissionLoad) {
|
||||
// @TODO: remove this lazy require
|
||||
var objectTypeModelMap = require('./objectTypeModelMap');
|
||||
|
||||
// Iterate through the object types, i.e. ['post', 'tag', 'user']
|
||||
return _.reduce(obj_types, function (obj_type_handlers, obj_type) {
|
||||
return _.reduce(objTypes, function (objTypeHandlers, objType) {
|
||||
// Grab the TargetModel through the objectTypeModelMap
|
||||
var TargetModel = objectTypeModelMap[obj_type];
|
||||
var TargetModel = objectTypeModelMap[objType];
|
||||
|
||||
// Create the 'handler' for the object type;
|
||||
// the '.post()' in canThis(user).edit.post()
|
||||
obj_type_handlers[obj_type] = function (modelOrId) {
|
||||
objTypeHandlers[objType] = function (modelOrId) {
|
||||
var modelId;
|
||||
|
||||
// If it's an internal request, resolve immediately
|
||||
@ -86,7 +86,7 @@ CanThisResult.prototype.buildObjectTypeHandlers = function (obj_types, act_type,
|
||||
var permObjId;
|
||||
|
||||
// Look for a matching action type and object type first
|
||||
if (perm.get('action_type') !== act_type || perm.get('object_type') !== obj_type) {
|
||||
if (perm.get('action_type') !== actType || perm.get('object_type') !== objType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -106,13 +106,12 @@ CanThisResult.prototype.buildObjectTypeHandlers = function (obj_types, act_type,
|
||||
};
|
||||
// Check user permissions for matching action, object and id.
|
||||
|
||||
if (_.any(loadedPermissions.user.roles, { 'name': 'Owner' })) {
|
||||
if (_.any(loadedPermissions.user.roles, {name: 'Owner'})) {
|
||||
hasUserPermission = true;
|
||||
} else if (!_.isEmpty(userPermissions)) {
|
||||
hasUserPermission = _.any(userPermissions, checkPermission);
|
||||
}
|
||||
|
||||
|
||||
// Check app permissions if they were passed
|
||||
hasAppPermission = true;
|
||||
if (!_.isNull(appPermissions)) {
|
||||
@ -122,7 +121,7 @@ CanThisResult.prototype.buildObjectTypeHandlers = function (obj_types, act_type,
|
||||
// Offer a chance for the TargetModel to override the results
|
||||
if (TargetModel && _.isFunction(TargetModel.permissible)) {
|
||||
return TargetModel.permissible(
|
||||
modelId, act_type, context, loadedPermissions, hasUserPermission, hasAppPermission
|
||||
modelId, actType, context, loadedPermissions, hasUserPermission, hasAppPermission
|
||||
);
|
||||
}
|
||||
|
||||
@ -134,7 +133,7 @@ CanThisResult.prototype.buildObjectTypeHandlers = function (obj_types, act_type,
|
||||
});
|
||||
};
|
||||
|
||||
return obj_type_handlers;
|
||||
return objTypeHandlers;
|
||||
}, {});
|
||||
};
|
||||
|
||||
@ -148,7 +147,7 @@ CanThisResult.prototype.beginCheck = function (context) {
|
||||
context = parseContext(context);
|
||||
|
||||
if (!hasActionsMap()) {
|
||||
throw new Error("No actions map found, please call permissions.init() before use.");
|
||||
throw new Error('No actions map found, please call permissions.init() before use.');
|
||||
}
|
||||
|
||||
// Kick off loading of effective user permissions if necessary
|
||||
@ -159,7 +158,6 @@ CanThisResult.prototype.beginCheck = function (context) {
|
||||
userPermissionLoad = Promise.resolve(null);
|
||||
}
|
||||
|
||||
|
||||
// Kick off loading of effective app permissions if necessary
|
||||
if (context.app) {
|
||||
appPermissionLoad = effectivePerms.app(context.app);
|
||||
@ -177,18 +175,18 @@ CanThisResult.prototype.beginCheck = function (context) {
|
||||
});
|
||||
|
||||
// Iterate through the actions and their related object types
|
||||
_.each(exported.actionsMap, function (obj_types, act_type) {
|
||||
_.each(exported.actionsMap, function (objTypes, actType) {
|
||||
// Build up the object type handlers;
|
||||
// the '.post()' parts in canThis(user).edit.post()
|
||||
var obj_type_handlers = self.buildObjectTypeHandlers(obj_types, act_type, context, permissionsLoad);
|
||||
var objTypeHandlers = self.buildObjectTypeHandlers(objTypes, actType, context, permissionsLoad);
|
||||
|
||||
// Define a property for the action on the result;
|
||||
// the '.edit' in canThis(user).edit.post()
|
||||
Object.defineProperty(self, act_type, {
|
||||
Object.defineProperty(self, actType, {
|
||||
writable: false,
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
value: obj_type_handlers
|
||||
value: objTypeHandlers
|
||||
});
|
||||
});
|
||||
|
||||
@ -218,19 +216,19 @@ init = refresh = function () {
|
||||
}
|
||||
*/
|
||||
_.each(perms.models, function (perm) {
|
||||
var action_type = perm.get('action_type'),
|
||||
object_type = perm.get('object_type');
|
||||
var actionType = perm.get('action_type'),
|
||||
objectType = perm.get('object_type');
|
||||
|
||||
exported.actionsMap[action_type] = exported.actionsMap[action_type] || [];
|
||||
seenActions[action_type] = seenActions[action_type] || {};
|
||||
exported.actionsMap[actionType] = exported.actionsMap[actionType] || [];
|
||||
seenActions[actionType] = seenActions[actionType] || {};
|
||||
|
||||
// Check if we've already seen this action -> object combo
|
||||
if (seenActions[action_type][object_type]) {
|
||||
if (seenActions[actionType][objectType]) {
|
||||
return;
|
||||
}
|
||||
|
||||
exported.actionsMap[action_type].push(object_type);
|
||||
seenActions[action_type][object_type] = true;
|
||||
exported.actionsMap[actionType].push(objectType);
|
||||
seenActions[actionType][objectType] = true;
|
||||
});
|
||||
|
||||
return exported.actionsMap;
|
||||
|
@ -1,7 +1,7 @@
|
||||
module.exports = {
|
||||
'post': require('../models/post').Post,
|
||||
'role': require('../models/role').Role,
|
||||
'user': require('../models/user').User,
|
||||
'permission': require('../models/permission').Permission,
|
||||
'setting': require('../models/settings').Settings
|
||||
post: require('../models/post').Post,
|
||||
role: require('../models/role').Role,
|
||||
user: require('../models/user').User,
|
||||
permission: require('../models/permission').Permission,
|
||||
setting: require('../models/settings').Settings
|
||||
};
|
||||
|
@ -110,7 +110,7 @@ var _ = require('lodash'),
|
||||
|
||||
return paths;
|
||||
}).catch(function () {
|
||||
return {'_messages': messages};
|
||||
return {_messages: messages};
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -32,4 +32,4 @@ adminRoutes = function (middleware) {
|
||||
return router;
|
||||
};
|
||||
|
||||
module.exports = adminRoutes;
|
||||
module.exports = adminRoutes;
|
||||
|
@ -65,7 +65,6 @@ apiRoutes = function (middleware) {
|
||||
api.http(api.mail.sendTest)(req, res);
|
||||
});
|
||||
|
||||
|
||||
// ## Authentication
|
||||
router.post('/authentication/passwordreset',
|
||||
middleware.spamForgottenPrevention,
|
||||
|
@ -38,4 +38,4 @@ frontendRoutes = function () {
|
||||
return router;
|
||||
};
|
||||
|
||||
module.exports = frontendRoutes;
|
||||
module.exports = frontendRoutes;
|
||||
|
@ -7,4 +7,4 @@ module.exports = {
|
||||
api: api,
|
||||
admin: admin,
|
||||
frontend: frontend
|
||||
};
|
||||
};
|
||||
|
@ -23,4 +23,4 @@ function getStorage(storageChoice) {
|
||||
return storage[storageChoice];
|
||||
}
|
||||
|
||||
module.exports.getStorage = getStorage;
|
||||
module.exports.getStorage = getStorage;
|
||||
|
@ -168,7 +168,7 @@ function updateCheck() {
|
||||
// 1. updateCheck is defined as false in config.js
|
||||
// 2. we've already done a check this session
|
||||
// 3. we're not in production or development mode
|
||||
//TODO: need to remove config.updateCheck in favor of config.privacy.updateCheck in future version (it is now deprecated)
|
||||
// TODO: need to remove config.updateCheck in favor of config.privacy.updateCheck in future version (it is now deprecated)
|
||||
if (config.updateCheck === false || config.isPrivacyDisabled('useUpdateCheck') || _.indexOf(allowedCheckEnvironments, process.env.NODE_ENV) === -1) {
|
||||
// No update check
|
||||
return Promise.resolve();
|
||||
|
@ -1,50 +1,48 @@
|
||||
// Functions to imitate the behavior of Downsize@0.0.5 with 'words: "0"' (heavily based on Downsize)
|
||||
|
||||
var stack, tagName, tagBuffer, truncatedText, parseState, pointer,
|
||||
states = {unitialized: 0, tag_commenced: 1, tag_string: -1, tag_string_single: -2, comment: -3 },
|
||||
states = {unitialized: 0, tag_commenced: 1, tag_string: -1, tag_string_single: -2, comment: -3},
|
||||
voidElements = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input',
|
||||
'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
|
||||
'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
|
||||
|
||||
function getTagName(tag) {
|
||||
var tagName = (tag || "").match(/<\/*([a-z0-9\:\-\_]+)/i);
|
||||
var tagName = (tag || '').match(/<\/*([a-z0-9\:\-\_]+)/i);
|
||||
return tagName ? tagName[1] : null;
|
||||
}
|
||||
|
||||
function closeTag(openingTag) {
|
||||
var tagName = (getTagName(openingTag)) ? "</" + getTagName(openingTag) + ">" : "";
|
||||
var tagName = (getTagName(openingTag)) ? '</' + getTagName(openingTag) + '>' : '';
|
||||
return tagName;
|
||||
}
|
||||
|
||||
function downzero(text) {
|
||||
|
||||
stack = [];
|
||||
tagName = '';
|
||||
tagBuffer = '';
|
||||
truncatedText = "";
|
||||
truncatedText = '';
|
||||
parseState = 0;
|
||||
pointer = 0;
|
||||
|
||||
for (; pointer < text.length; pointer += 1) {
|
||||
|
||||
if (parseState !== states.unitialized) {
|
||||
tagBuffer += text[pointer];
|
||||
}
|
||||
|
||||
switch (text[pointer]) {
|
||||
case "<":
|
||||
case '<':
|
||||
if (parseState === states.unitialized && text[pointer + 1].match(/[a-z0-9\-\_\/\!]/)) {
|
||||
parseState = states.tag_commenced;
|
||||
tagBuffer += text[pointer];
|
||||
}
|
||||
|
||||
break;
|
||||
case "!":
|
||||
if (parseState === states.tag_commenced && text[pointer - 1] === "<") {
|
||||
case '!':
|
||||
if (parseState === states.tag_commenced && text[pointer - 1] === '<') {
|
||||
parseState = states.comment;
|
||||
}
|
||||
|
||||
break;
|
||||
case "\"":
|
||||
case '\"':
|
||||
if (parseState === states.tag_string) {
|
||||
parseState = states.tag_commenced;
|
||||
} else if (parseState === states.tag_string_single) {
|
||||
@ -55,7 +53,7 @@ function downzero(text) {
|
||||
}
|
||||
|
||||
break;
|
||||
case "'":
|
||||
case '\'':
|
||||
if (parseState === states.tag_string_single) {
|
||||
parseState = states.tag_commenced;
|
||||
} else if (parseState === states.tag_string) {
|
||||
@ -65,7 +63,7 @@ function downzero(text) {
|
||||
}
|
||||
|
||||
break;
|
||||
case ">":
|
||||
case '>':
|
||||
if (parseState === states.tag_commenced) {
|
||||
parseState = states.unitialized;
|
||||
truncatedText += tagBuffer;
|
||||
@ -76,21 +74,21 @@ function downzero(text) {
|
||||
} else if (voidElements.indexOf(tagName) < 0 && !tagBuffer.match(/\/\s*>$/)) {
|
||||
stack.push(tagBuffer);
|
||||
}
|
||||
tagBuffer = "";
|
||||
tagBuffer = '';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parseState === states.comment && text.substring(pointer - 2, pointer) === "--") {
|
||||
if (parseState === states.comment && text.substring(pointer - 2, pointer) === '--') {
|
||||
parseState = states.unitialized;
|
||||
truncatedText += tagBuffer;
|
||||
tagBuffer = "";
|
||||
tagBuffer = '';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
case "-":
|
||||
case '-':
|
||||
break;
|
||||
}
|
||||
|
||||
@ -108,4 +106,4 @@ function downzero(text) {
|
||||
return truncatedText;
|
||||
}
|
||||
|
||||
module.exports = downzero;
|
||||
module.exports = downzero;
|
||||
|
@ -67,4 +67,4 @@ utils = {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = utils;
|
||||
module.exports = utils;
|
||||
|
@ -7,10 +7,13 @@ var _ = require('lodash'),
|
||||
pingList;
|
||||
|
||||
// ToDo: Make this configurable
|
||||
pingList = [
|
||||
{ host: 'blogsearch.google.com', path: '/ping/RPC2' },
|
||||
{ host: 'rpc.pingomatic.com', path: '/' }
|
||||
];
|
||||
pingList = [{
|
||||
host: 'blogsearch.google.com',
|
||||
path: '/ping/RPC2'
|
||||
}, {
|
||||
host: 'rpc.pingomatic.com',
|
||||
path: '/'
|
||||
}];
|
||||
|
||||
function ping(post) {
|
||||
var pingXML,
|
||||
@ -31,19 +34,25 @@ function ping(post) {
|
||||
|
||||
// Need to require here because of circular dependency
|
||||
return config.urlForPost(api.settings, post, true).then(function (url) {
|
||||
|
||||
// Build XML object.
|
||||
pingXML = xml({
|
||||
methodCall: [
|
||||
{ methodName: 'weblogUpdate.ping' },
|
||||
{
|
||||
params: [{
|
||||
param: [{ value: [{ string: title }]}],
|
||||
}, {
|
||||
param: [{ value: [{ string: url }]}],
|
||||
methodCall: [{
|
||||
methodName: 'weblogUpdate.ping'
|
||||
}, {
|
||||
params: [{
|
||||
param: [{
|
||||
value: [{
|
||||
string: title
|
||||
}]
|
||||
}]
|
||||
}
|
||||
]
|
||||
}, {
|
||||
param: [{
|
||||
value: [{
|
||||
string: url
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}, {declaration: true});
|
||||
|
||||
// Ping each of the defined services.
|
||||
@ -60,8 +69,8 @@ function ping(post) {
|
||||
req.on('error', function (error) {
|
||||
errors.logError(
|
||||
error,
|
||||
"Pinging services for updates on your blog failed, your blog will continue to function.",
|
||||
"If you get this error repeatedly, please seek help from https://ghost.org/forum."
|
||||
'Pinging services for updates on your blog failed, your blog will continue to function.',
|
||||
'If you get this error repeatedly, please seek help from https://ghost.org/forum.'
|
||||
);
|
||||
});
|
||||
req.end();
|
||||
@ -71,4 +80,4 @@ function ping(post) {
|
||||
|
||||
module.exports = {
|
||||
ping: ping
|
||||
};
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Posts
|
||||
/*jshint unused:false */
|
||||
var blanket = require('blanket')({
|
||||
'pattern': ['/core/server/', '/core/client/', '/core/shared/'],
|
||||
pattern: ['/core/server/', '/core/client/', '/core/shared/'],
|
||||
'data-cover-only': ['/core/server/', '/core/client/', '/core/shared/']
|
||||
}),
|
||||
requireDir = require('require-dir');
|
||||
|
@ -52,25 +52,30 @@ var DEBUG = false, // TOGGLE THIS TO GET MORE SCREENSHOTS
|
||||
title: 'Bacon ipsum dolor sit amet',
|
||||
html: 'I am a test post.\n#I have some small content'
|
||||
},
|
||||
screens;
|
||||
screens,
|
||||
CasperTest,
|
||||
// ## Debugging
|
||||
jsErrors = [],
|
||||
pageErrors = [],
|
||||
resourceErrors = [];
|
||||
|
||||
screens = {
|
||||
'root': {
|
||||
root: {
|
||||
url: 'ghost/',
|
||||
linkSelector: '.nav-content',
|
||||
selector: '.nav-content.active'
|
||||
},
|
||||
'content': {
|
||||
content: {
|
||||
url: 'ghost/content/',
|
||||
linkSelector: '.nav-content',
|
||||
selector: '.nav-content.active'
|
||||
},
|
||||
'editor': {
|
||||
editor: {
|
||||
url: 'ghost/editor/',
|
||||
linkSelector: '.nav-new',
|
||||
selector: '#entry-title'
|
||||
},
|
||||
'settings': {
|
||||
settings: {
|
||||
url: 'ghost/settings/',
|
||||
linkSelector: '.nav-settings',
|
||||
selector: '.nav-settings.active'
|
||||
@ -89,26 +94,26 @@ screens = {
|
||||
linkSelector: '.user-menu-profile',
|
||||
selector: '.user-profile'
|
||||
},
|
||||
'signin': {
|
||||
signin: {
|
||||
url: 'ghost/signin/',
|
||||
selector: '.btn-blue'
|
||||
},
|
||||
'signin-authenticated': {
|
||||
url: 'ghost/signin/',
|
||||
//signin with authenticated user redirects to posts
|
||||
// signin with authenticated user redirects to posts
|
||||
selector: '.nav-content.active'
|
||||
},
|
||||
'signout': {
|
||||
signout: {
|
||||
url: 'ghost/signout/',
|
||||
linkSelector: '.user-menu-signout',
|
||||
// When no user exists we get redirected to setup which has btn-green
|
||||
selector: '.btn-blue, .btn-green'
|
||||
},
|
||||
'signup': {
|
||||
signup: {
|
||||
url: 'ghost/signup/',
|
||||
selector: '.btn-blue'
|
||||
},
|
||||
'setup': {
|
||||
setup: {
|
||||
url: 'ghost/setup/',
|
||||
selector: '.btn-green'
|
||||
},
|
||||
@ -162,7 +167,6 @@ casper.waitForTransparent = function (classname, then, timeout) {
|
||||
casper.waitForOpacity(classname, '0', then, timeout);
|
||||
};
|
||||
|
||||
|
||||
// ### Then Open And Wait For Page Load
|
||||
// Always wait for the `.page-content` element as some indication that the ember app has loaded.
|
||||
casper.thenOpenAndWaitForPageLoad = function (screen, then, timeout) {
|
||||
@ -211,11 +215,6 @@ casper.fillAndAdd = function (selector, data) {
|
||||
});
|
||||
};
|
||||
|
||||
// ## Debugging
|
||||
var jsErrors = [],
|
||||
pageErrors = [],
|
||||
resourceErrors = [];
|
||||
|
||||
// ## Echo Concise
|
||||
// Does casper.echo but checks for the presence of the --concise flag
|
||||
casper.echoConcise = function (message, style) {
|
||||
@ -303,8 +302,7 @@ casper.test.on('exit', function () {
|
||||
}
|
||||
});
|
||||
|
||||
var CasperTest = (function () {
|
||||
|
||||
CasperTest = (function () {
|
||||
var _beforeDoneHandler,
|
||||
_noop = function noop() { },
|
||||
_isUserRegistered = false;
|
||||
@ -330,7 +328,6 @@ var CasperTest = (function () {
|
||||
if (!doNotAutoLogin) {
|
||||
// Only call register once for the lifetime of CasperTest
|
||||
if (!_isUserRegistered) {
|
||||
|
||||
CasperTest.Routines.signout.run();
|
||||
CasperTest.Routines.setup.run();
|
||||
|
||||
@ -350,7 +347,6 @@ var CasperTest = (function () {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
if (typeof expect === 'function') {
|
||||
doNotAutoLogin = suite;
|
||||
suite = expect;
|
||||
@ -374,11 +370,9 @@ var CasperTest = (function () {
|
||||
begin: begin,
|
||||
beforeDone: beforeDone
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
CasperTest.Routines = (function () {
|
||||
|
||||
function setup() {
|
||||
casper.thenOpenAndWaitForPageLoad('setup', function then() {
|
||||
casper.captureScreenshot('setting_up1.png');
|
||||
@ -399,13 +393,11 @@ CasperTest.Routines = (function () {
|
||||
}, 2000);
|
||||
|
||||
casper.captureScreenshot('setting_up3.png');
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function signin() {
|
||||
casper.thenOpenAndWaitForPageLoad('signin', function then() {
|
||||
|
||||
casper.waitForOpaque('.login-box', function then() {
|
||||
casper.captureScreenshot('signing_in.png');
|
||||
this.fillAndSave('#login', user);
|
||||
@ -476,10 +468,10 @@ CasperTest.Routines = (function () {
|
||||
|
||||
function _createRunner(fn) {
|
||||
fn.run = function run(test) {
|
||||
var routine = this;
|
||||
var self = this;
|
||||
|
||||
casper.then(function () {
|
||||
routine.call(casper, test);
|
||||
self.call(casper, test);
|
||||
});
|
||||
};
|
||||
|
||||
@ -493,5 +485,4 @@ CasperTest.Routines = (function () {
|
||||
createTestPost: _createRunner(createTestPost),
|
||||
togglePermalinks: _createRunner(togglePermalinks)
|
||||
};
|
||||
|
||||
}());
|
||||
|
@ -97,19 +97,17 @@ CasperTest.begin('Content list shows correct post status', 5, function testStati
|
||||
// test.assert(false, 'status did not change');
|
||||
// });
|
||||
// });
|
||||
|
||||
});
|
||||
|
||||
|
||||
// TODO: Implement this test... much needed!
|
||||
//CasperTest.begin('Infinite scrolling', 2, function suite(test) {
|
||||
// CasperTest.begin('Infinite scrolling', 2, function suite(test) {
|
||||
// // Placeholder for infinite scrolling/pagination tests (will need to setup 16+ posts).
|
||||
//
|
||||
// casper.thenOpenAndWaitForPageLoad('content', function testTitleAndUrl() {
|
||||
// test.assertTitle('Ghost Admin', 'Title is "Ghost Admin"');
|
||||
// test.assertUrlMatch(/ghost\/\d+\/$/, 'Landed on the correct URL');
|
||||
// });
|
||||
//});
|
||||
// });
|
||||
|
||||
CasperTest.begin('Posts can be marked as featured', 8, function suite(test) {
|
||||
// Create a sample post
|
||||
@ -129,7 +127,7 @@ CasperTest.begin('Posts can be marked as featured', 8, function suite(test) {
|
||||
});
|
||||
|
||||
casper.waitForResource(/\/posts\/\d+\/\?include=tags/, function (resource) {
|
||||
test.assert(400 > resource.status);
|
||||
test.assert(resource.status < 400);
|
||||
});
|
||||
|
||||
casper.waitForSelector('.content-list-content li.featured:first-of-type', function () {
|
||||
@ -143,7 +141,7 @@ CasperTest.begin('Posts can be marked as featured', 8, function suite(test) {
|
||||
casper.thenClick('.content-preview .featured');
|
||||
|
||||
casper.waitForResource(/\/posts\/\d+\/\?include=tags/, function waitForSuccess(resource) {
|
||||
test.assert(400 > resource.status);
|
||||
test.assert(resource.status < 400);
|
||||
});
|
||||
|
||||
casper.then(function untoggledFeaturedTest() {
|
||||
@ -152,4 +150,4 @@ CasperTest.begin('Posts can be marked as featured', 8, function suite(test) {
|
||||
}, function onTimeout() {
|
||||
test.assert(false, 'Couldn\'t unfeature post.');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -516,7 +516,6 @@ CasperTest.begin('Publish menu - existing post status is correct after failed sa
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// test the markdown help modal
|
||||
CasperTest.begin('Markdown help modal', 5, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('editor', function testTitleAndUrl() {
|
||||
@ -580,7 +579,7 @@ CasperTest.begin('Title input is set correctly after using the Post-Settings-Men
|
||||
});
|
||||
|
||||
casper.waitForResource(/\/posts\/\d+\/\?include=tags/, function testGoodResponse(resource) {
|
||||
test.assert(400 > resource.status);
|
||||
test.assert(resource.status < 400);
|
||||
});
|
||||
|
||||
casper.then(function checkTitleInput() {
|
||||
@ -627,7 +626,7 @@ CasperTest.begin('Editor content is set correctly after using the Post-Settings-
|
||||
});
|
||||
|
||||
casper.waitForResource(/\/posts\/\d+\/\?include=tags/, function testGoodResponse(resource) {
|
||||
test.assert(400 > resource.status);
|
||||
test.assert(resource.status < 400);
|
||||
});
|
||||
|
||||
casper.waitForSelectorTextChange('.entry-preview .rendered-markdown', function onSuccess() {
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
/*globals CasperTest, casper, __utils__ */
|
||||
|
||||
|
||||
CasperTest.begin('Post settings menu', 14, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('editor', function testTitleAndUrl() {
|
||||
test.assertTitle('Ghost Admin', 'Ghost admin has no title');
|
||||
@ -56,7 +55,6 @@ CasperTest.begin('Post settings menu', 14, function suite(test) {
|
||||
casper.waitUntilVisible('.post-settings-menu button.delete', function onSuccess() {
|
||||
test.assert(true, 'delete post button should be visible for saved drafts');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
CasperTest.begin('Delete post modal', 7, function testDeleteModal(test) {
|
||||
@ -135,11 +133,11 @@ CasperTest.begin('Post url can be changed', 4, function suite(test) {
|
||||
});
|
||||
|
||||
casper.waitForResource(/\/posts\/\d+\/\?include=tags/, function testGoodResponse(resource) {
|
||||
test.assert(400 > resource.status);
|
||||
test.assert(resource.status < 400);
|
||||
});
|
||||
|
||||
casper.then(function checkValueMatches() {
|
||||
//using assertField(name) checks the htmls initial "value" attribute, so have to hack around it.
|
||||
// using assertField(name) checks the htmls initial "value" attribute, so have to hack around it.
|
||||
var slugVal = this.evaluate(function () {
|
||||
return __utils__.getFieldValue('post-setting-slug');
|
||||
});
|
||||
@ -173,11 +171,11 @@ CasperTest.begin('Post published date can be changed', 4, function suite(test) {
|
||||
});
|
||||
|
||||
casper.waitForResource(/\/posts\/\d+\/\?include=tags/, function testGoodResponse(resource) {
|
||||
test.assert(400 > resource.status);
|
||||
test.assert(resource.status < 400);
|
||||
});
|
||||
|
||||
casper.then(function checkValueMatches() {
|
||||
//using assertField(name) checks the htmls initial "value" attribute, so have to hack around it.
|
||||
// using assertField(name) checks the htmls initial "value" attribute, so have to hack around it.
|
||||
var dateVal = this.evaluate(function () {
|
||||
return __utils__.getFieldValue('post-setting-date');
|
||||
});
|
||||
@ -204,7 +202,7 @@ CasperTest.begin('Post can be changed to static page', 6, function suite(test) {
|
||||
casper.thenClick('label[for=static-page]');
|
||||
|
||||
casper.waitForResource(/\/posts\/\d+\/\?include=tags/, function waitForSuccess(resource) {
|
||||
test.assert(400 > resource.status);
|
||||
test.assert(resource.status < 400);
|
||||
|
||||
test.assertExists('.post-setting-static-page:checked', 'can turn on static page');
|
||||
});
|
||||
@ -212,7 +210,7 @@ CasperTest.begin('Post can be changed to static page', 6, function suite(test) {
|
||||
casper.thenClick('label[for=static-page]');
|
||||
|
||||
casper.waitForResource(/\/posts\/\d+\/\?include=tags/, function waitForSuccess(resource) {
|
||||
test.assert(400 > resource.status);
|
||||
test.assert(resource.status < 400);
|
||||
|
||||
test.assertDoesntExist('.post-setting-static-page:checked', 'can turn off static page');
|
||||
});
|
||||
@ -251,10 +249,10 @@ CasperTest.begin('Post url input is reset from all whitespace back to original v
|
||||
});
|
||||
|
||||
casper.then(function checkValueMatches() {
|
||||
//using assertField(name) checks the htmls initial "value" attribute, so have to hack around it.
|
||||
// using assertField(name) checks the htmls initial "value" attribute, so have to hack around it.
|
||||
var slugVal = this.evaluate(function () {
|
||||
return __utils__.getFieldValue('post-setting-slug');
|
||||
});
|
||||
test.assertEqual(slugVal, originalSlug);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -107,7 +107,7 @@ CasperTest.begin('General settings pane is correct', 8, function suite(test) {
|
||||
}, casper.failOnTimeout(test, 'No success notification :('));
|
||||
});
|
||||
|
||||
//// ## General settings validations tests
|
||||
// ## General settings validations tests
|
||||
CasperTest.begin('General settings validation is correct', 6, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('settings.general', function testTitleAndUrl() {
|
||||
test.assertTitle('Ghost Admin', 'Ghost admin has no title');
|
||||
@ -136,7 +136,7 @@ CasperTest.begin('General settings validation is correct', 6, function suite(tes
|
||||
|
||||
casper.thenClick('.js-bb-notification .close');
|
||||
|
||||
// Check postsPerPage autocorrect
|
||||
// Check postsPerPage autocorrect
|
||||
casper.fillAndSave('form#settings-general', {
|
||||
'general[postsPerPage]': 'notaninteger'
|
||||
});
|
||||
@ -181,7 +181,7 @@ CasperTest.begin('Users screen is correct', 9, function suite(test) {
|
||||
return true;
|
||||
}, '"Owner" is not a role option for new users');
|
||||
});
|
||||
//role options get loaded asynchronously; give them a chance to come in
|
||||
// role options get loaded asynchronously; give them a chance to come in
|
||||
casper.waitForSelector('.invite-new-user select#new-user-role option', function then() {
|
||||
test.assertEval(function authorIsSelectedByDefault() {
|
||||
var options = document.querySelectorAll('.invite-new-user select#new-user-role option'),
|
||||
@ -312,7 +312,7 @@ CasperTest.begin('User settings screen change slug handles duplicate slug', 4, f
|
||||
casper.thenClick('body');
|
||||
|
||||
casper.waitForResource(/\/slugs\/user\//, function testGoodResponse(resource) {
|
||||
test.assert(400 > resource.status);
|
||||
test.assert(resource.status < 400);
|
||||
});
|
||||
|
||||
casper.then(function checkSlugInputValue() {
|
||||
|
@ -112,7 +112,6 @@ CasperTest.begin('Authenticated user is redirected', 8, function suite(test) {
|
||||
});
|
||||
}, true);
|
||||
|
||||
|
||||
CasperTest.begin('Ensure email field form validation', 3, function suite(test) {
|
||||
CasperTest.Routines.signout.run(test);
|
||||
|
||||
@ -124,7 +123,7 @@ CasperTest.begin('Ensure email field form validation', 3, function suite(test) {
|
||||
casper.waitForOpaque('.js-login-box',
|
||||
function then() {
|
||||
this.fillAndSave('form.login-form', {
|
||||
'identification': 'notanemail'
|
||||
identification: 'notanemail'
|
||||
});
|
||||
},
|
||||
function onTimeout() {
|
||||
@ -136,4 +135,4 @@ CasperTest.begin('Ensure email field form validation', 3, function suite(test) {
|
||||
}, function onTimeout() {
|
||||
test.fail('Email validation error did not appear');
|
||||
}, 2000);
|
||||
}, true);
|
||||
}, true);
|
||||
|
@ -29,5 +29,4 @@ CasperTest.begin('Ghost signout works correctly', 3, function suite(test) {
|
||||
});
|
||||
|
||||
casper.captureScreenshot('user-menu-logout-clicked.png');
|
||||
|
||||
}, true);
|
||||
|
@ -5,14 +5,14 @@
|
||||
CasperTest.begin('Check post not found (404)', 2, function suite(test) {
|
||||
casper.thenOpen(url + 'asdf/', function (response) {
|
||||
test.assertEqual(response.status, 404, 'Response status should be 404.');
|
||||
test.assertSelectorHasText('.error-code', '404');
|
||||
test.assertSelectorHasText('.error-code', '404');
|
||||
});
|
||||
}, true);
|
||||
|
||||
CasperTest.begin('Check frontend route not found (404)', 2, function suite(test) {
|
||||
casper.thenOpen(url + 'asdf/asdf/', function (response) {
|
||||
test.assertEqual(response.status, 404, 'Response status should be 404.');
|
||||
test.assertSelectorHasText('.error-code', '404');
|
||||
test.assertSelectorHasText('.error-code', '404');
|
||||
});
|
||||
}, true);
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user