2
1
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2023-12-13 21:00:40 +01:00

Refactor common pattern in service files

- Use array destructuring
- Use @tryghost/errors
- Part of the big move towards decoupling, this gives visibility on what's being used where
- Biting off manageable chunks / fixing bits of code I'm refactoring for other reasons
This commit is contained in:
Hannah Wolfe 2020-04-30 20:26:12 +01:00
parent c70c49258e
commit baa8118893
32 changed files with 224 additions and 208 deletions

View file

@ -1,7 +1,7 @@
// ## Server Loader // ## Server Loader
// Passes options through the boot process to get a server instance back // Passes options through the boot process to get a server instance back
const server = require('./server'); const server = require('./server');
const common = require('./server/lib/common'); const errors = require('@tryghost/errors');
const GhostServer = require('./server/ghost-server'); const GhostServer = require('./server/ghost-server');
// Set the default environment to be `development` // Set the default environment to be `development`
@ -12,8 +12,8 @@ function makeGhost(options) {
return server(options) return server(options)
.catch((err) => { .catch((err) => {
if (!common.errors.utils.isIgnitionError(err)) { if (!errors.utils.isIgnitionError(err)) {
err = new common.errors.GhostError({message: err.message, err: err}); err = new errors.GhostError({message: err.message, err: err});
} }
return GhostServer.announceServerStopped(err) return GhostServer.announceServerStopped(err)

View file

@ -1,16 +1,14 @@
const _ = require('lodash'); const _ = require('lodash');
const Analytics = require('analytics-node'); const Analytics = require('analytics-node');
const config = require('./config'); const config = require('./config');
const common = require('./lib/common'); const {events} = require('./lib/common');
let analytics;
module.exports.init = function () { module.exports.init = function () {
analytics = new Analytics(config.get('segment:key')); const analytics = new Analytics(config.get('segment:key'));
let toTrack;
const trackDefaults = config.get('segment:trackDefaults') || {}; const trackDefaults = config.get('segment:trackDefaults') || {};
const prefix = config.get('segment:prefix') || ''; const prefix = config.get('segment:prefix') || '';
toTrack = [ const toTrack = [
{ {
event: 'post.published', event: 'post.published',
name: 'Post Published' name: 'Post Published'
@ -30,7 +28,7 @@ module.exports.init = function () {
]; ];
_.each(toTrack, function (track) { _.each(toTrack, function (track) {
common.events.on(track.event, function () { events.on(track.event, function () {
analytics.track(_.extend(trackDefaults, {event: prefix + track.name})); analytics.track(_.extend(trackDefaults, {event: prefix + track.name}));
}); });
}); });

View file

@ -8,7 +8,8 @@ const path = require('path');
const _ = require('lodash'); const _ = require('lodash');
const config = require('./config'); const config = require('./config');
const urlUtils = require('./lib/url-utils'); const urlUtils = require('./lib/url-utils');
const common = require('./lib/common'); const errors = require('@tryghost/errors');
const {events, i18n, logging} = require('./lib/common');
const moment = require('moment'); const moment = require('moment');
/** /**
@ -86,16 +87,16 @@ GhostServer.prototype.start = function (externalApp) {
let ghostError; let ghostError;
if (error.errno === 'EADDRINUSE') { if (error.errno === 'EADDRINUSE') {
ghostError = new common.errors.GhostError({ ghostError = new errors.GhostError({
message: common.i18n.t('errors.httpServer.addressInUse.error'), message: i18n.t('errors.httpServer.addressInUse.error'),
context: common.i18n.t('errors.httpServer.addressInUse.context', {port: config.get('server').port}), context: i18n.t('errors.httpServer.addressInUse.context', {port: config.get('server').port}),
help: common.i18n.t('errors.httpServer.addressInUse.help') help: i18n.t('errors.httpServer.addressInUse.help')
}); });
} else { } else {
ghostError = new common.errors.GhostError({ ghostError = new errors.GhostError({
message: common.i18n.t('errors.httpServer.otherError.error', {errorNumber: error.errno}), message: i18n.t('errors.httpServer.otherError.error', {errorNumber: error.errno}),
context: common.i18n.t('errors.httpServer.otherError.context'), context: i18n.t('errors.httpServer.otherError.context'),
help: common.i18n.t('errors.httpServer.otherError.help') help: i18n.t('errors.httpServer.otherError.help')
}); });
} }
@ -128,7 +129,7 @@ GhostServer.prototype.stop = function () {
resolve(self); resolve(self);
} else { } else {
self.httpServer.close(function () { self.httpServer.close(function () {
common.events.emit('server.stop'); events.emit('server.stop');
self.httpServer = null; self.httpServer = null;
self.logShutdownMessages(); self.logShutdownMessages();
resolve(self); resolve(self);
@ -155,7 +156,7 @@ GhostServer.prototype.restart = function () {
* To be called after `stop` * To be called after `stop`
*/ */
GhostServer.prototype.hammertime = function () { GhostServer.prototype.hammertime = function () {
common.logging.info(common.i18n.t('notices.httpServer.cantTouchThis')); logging.info(i18n.t('notices.httpServer.cantTouchThis'));
return Promise.resolve(this); return Promise.resolve(this);
}; };
@ -202,27 +203,27 @@ GhostServer.prototype.closeConnections = function () {
GhostServer.prototype.logStartMessages = function () { GhostServer.prototype.logStartMessages = function () {
// Startup & Shutdown messages // Startup & Shutdown messages
if (config.get('env') === 'production') { if (config.get('env') === 'production') {
common.logging.info(common.i18n.t('notices.httpServer.ghostIsRunningIn', {env: config.get('env')})); logging.info(i18n.t('notices.httpServer.ghostIsRunningIn', {env: config.get('env')}));
common.logging.info(common.i18n.t('notices.httpServer.yourBlogIsAvailableOn', {url: urlUtils.urlFor('home', true)})); logging.info(i18n.t('notices.httpServer.yourBlogIsAvailableOn', {url: urlUtils.urlFor('home', true)}));
common.logging.info(common.i18n.t('notices.httpServer.ctrlCToShutDown')); logging.info(i18n.t('notices.httpServer.ctrlCToShutDown'));
} else { } else {
common.logging.info(common.i18n.t('notices.httpServer.ghostIsRunningIn', {env: config.get('env')})); logging.info(i18n.t('notices.httpServer.ghostIsRunningIn', {env: config.get('env')}));
common.logging.info(common.i18n.t('notices.httpServer.listeningOn', { logging.info(i18n.t('notices.httpServer.listeningOn', {
host: config.get('server').socket || config.get('server').host, host: config.get('server').socket || config.get('server').host,
port: config.get('server').port port: config.get('server').port
})); }));
common.logging.info(common.i18n.t('notices.httpServer.urlConfiguredAs', {url: urlUtils.urlFor('home', true)})); logging.info(i18n.t('notices.httpServer.urlConfiguredAs', {url: urlUtils.urlFor('home', true)}));
common.logging.info(common.i18n.t('notices.httpServer.ctrlCToShutDown')); logging.info(i18n.t('notices.httpServer.ctrlCToShutDown'));
} }
function shutdown() { function shutdown() {
common.logging.warn(common.i18n.t('notices.httpServer.ghostHasShutdown')); logging.warn(i18n.t('notices.httpServer.ghostHasShutdown'));
if (config.get('env') === 'production') { if (config.get('env') === 'production') {
common.logging.warn(common.i18n.t('notices.httpServer.yourBlogIsNowOffline')); logging.warn(i18n.t('notices.httpServer.yourBlogIsNowOffline'));
} else { } else {
common.logging.warn( logging.warn(
common.i18n.t('notices.httpServer.ghostWasRunningFor'), i18n.t('notices.httpServer.ghostWasRunningFor'),
moment.duration(process.uptime(), 'seconds').humanize() moment.duration(process.uptime(), 'seconds').humanize()
); );
} }
@ -238,7 +239,7 @@ GhostServer.prototype.logStartMessages = function () {
* ### Log Shutdown Messages * ### Log Shutdown Messages
*/ */
GhostServer.prototype.logShutdownMessages = function () { GhostServer.prototype.logShutdownMessages = function () {
common.logging.warn(common.i18n.t('notices.httpServer.ghostIsClosingConnections')); logging.warn(i18n.t('notices.httpServer.ghostIsClosingConnections'));
}; };
module.exports = GhostServer; module.exports = GhostServer;
@ -253,7 +254,7 @@ const connectToBootstrapSocket = (message) => {
let wasResolved = false; let wasResolved = false;
const waitTimeout = setTimeout(() => { const waitTimeout = setTimeout(() => {
common.logging.info('Bootstrap socket timed out.'); logging.info('Bootstrap socket timed out.');
if (!client.destroyed) { if (!client.destroyed) {
client.destroy(); client.destroy();
@ -283,7 +284,7 @@ const connectToBootstrapSocket = (message) => {
}); });
client.on('close', () => { client.on('close', () => {
common.logging.info('Bootstrap client was closed.'); logging.info('Bootstrap client was closed.');
if (waitTimeout) { if (waitTimeout) {
clearTimeout(waitTimeout); clearTimeout(waitTimeout);
@ -291,7 +292,7 @@ const connectToBootstrapSocket = (message) => {
}); });
client.on('error', (err) => { client.on('error', (err) => {
common.logging.warn(`Can't connect to the bootstrap socket (${socketAddress.host} ${socketAddress.port}) ${err.code}`); logging.warn(`Can't connect to the bootstrap socket (${socketAddress.host} ${socketAddress.port}) ${err.code}`);
client.removeAllListeners(); client.removeAllListeners();
@ -300,10 +301,10 @@ const connectToBootstrapSocket = (message) => {
} }
if (options.tries < 3) { if (options.tries < 3) {
common.logging.warn(`Tries: ${options.tries}`); logging.warn(`Tries: ${options.tries}`);
// retry // retry
common.logging.warn('Retrying...'); logging.warn('Retrying...');
options.tries = options.tries + 1; options.tries = options.tries + 1;
const retryTimeout = setTimeout(() => { const retryTimeout = setTimeout(() => {
@ -338,7 +339,7 @@ module.exports.announceServerStart = function announceServerStart() {
} }
announceServerStartCalled = true; announceServerStartCalled = true;
common.events.emit('server.start'); events.emit('server.start');
// CASE: IPC communication to the CLI via child process. // CASE: IPC communication to the CLI via child process.
if (process.send) { if (process.send) {

View file

@ -12,7 +12,7 @@ require('./overrides');
const debug = require('ghost-ignition').debug('boot:init'); const debug = require('ghost-ignition').debug('boot:init');
const Promise = require('bluebird'); const Promise = require('bluebird');
const config = require('./config'); const config = require('./config');
const common = require('./lib/common'); const {events, i18n, logging} = require('./lib/common');
const migrator = require('./data/db/migrator'); const migrator = require('./data/db/migrator');
const urlUtils = require('./lib/url-utils'); const urlUtils = require('./lib/url-utils');
let parentApp; let parentApp;
@ -84,7 +84,7 @@ const minimalRequiredSetupToStartGhost = (dbState) => {
let ghostServer; let ghostServer;
// Initialize Ghost core internationalization // Initialize Ghost core internationalization
common.i18n.init(); i18n.init();
debug('Default i18n done for core'); debug('Default i18n done for core');
models.init(); models.init();
@ -113,7 +113,7 @@ const minimalRequiredSetupToStartGhost = (dbState) => {
// CASE: all good or db was just initialised // CASE: all good or db was just initialised
if (dbState === 1 || dbState === 2) { if (dbState === 1 || dbState === 2) {
common.events.emit('db.ready'); events.emit('db.ready');
return initialiseServices() return initialiseServices()
.then(() => { .then(() => {
@ -123,24 +123,24 @@ const minimalRequiredSetupToStartGhost = (dbState) => {
// CASE: migrations required, put blog into maintenance mode // CASE: migrations required, put blog into maintenance mode
if (dbState === 4) { if (dbState === 4) {
common.logging.info('Blog is in maintenance mode.'); logging.info('Blog is in maintenance mode.');
config.set('maintenance:enabled', true); config.set('maintenance:enabled', true);
migrator.migrate() migrator.migrate()
.then(() => { .then(() => {
common.events.emit('db.ready'); events.emit('db.ready');
return initialiseServices(); return initialiseServices();
}) })
.then(() => { .then(() => {
config.set('maintenance:enabled', false); config.set('maintenance:enabled', false);
common.logging.info('Blog is out of maintenance mode.'); logging.info('Blog is out of maintenance mode.');
return GhostServer.announceServerStart(); return GhostServer.announceServerStart();
}) })
.catch((err) => { .catch((err) => {
return GhostServer.announceServerStopped(err) return GhostServer.announceServerStopped(err)
.finally(() => { .finally(() => {
common.logging.error(err); logging.error(err);
setTimeout(() => { setTimeout(() => {
process.exit(-1); process.exit(-1);
}, 100); }, 100);

View file

@ -5,7 +5,7 @@
const Promise = require('bluebird'); const Promise = require('bluebird');
const fs = require('fs-extra'); const fs = require('fs-extra');
const common = require('../../common'); const {i18n} = require('../../common');
/** /**
* Parse package.json and validate it has * Parse package.json and validate it has
@ -15,7 +15,7 @@ const common = require('../../common');
function parsePackageJson(path) { function parsePackageJson(path) {
return fs.readFile(path) return fs.readFile(path)
.catch(function () { .catch(function () {
const err = new Error(common.i18n.t('errors.utils.parsepackagejson.couldNotReadPackage')); const err = new Error(i18n.t('errors.utils.parsepackagejson.couldNotReadPackage'));
err.context = path; err.context = path;
return Promise.reject(err); return Promise.reject(err);
@ -31,18 +31,18 @@ function parsePackageJson(path) {
hasRequiredKeys = json.name && json.version; hasRequiredKeys = json.name && json.version;
if (!hasRequiredKeys) { if (!hasRequiredKeys) {
err = new Error(common.i18n.t('errors.utils.parsepackagejson.nameOrVersionMissing')); err = new Error(i18n.t('errors.utils.parsepackagejson.nameOrVersionMissing'));
err.context = path; err.context = path;
err.help = common.i18n.t('errors.utils.parsepackagejson.willBeRequired', {url: 'https://ghost.org/docs/api/handlebars-themes/'}); err.help = i18n.t('errors.utils.parsepackagejson.willBeRequired', {url: 'https://ghost.org/docs/api/handlebars-themes/'});
return Promise.reject(err); return Promise.reject(err);
} }
return json; return json;
} catch (parseError) { } catch (parseError) {
err = new Error(common.i18n.t('errors.utils.parsepackagejson.themeFileIsMalformed')); err = new Error(i18n.t('errors.utils.parsepackagejson.themeFileIsMalformed'));
err.context = path; err.context = path;
err.help = common.i18n.t('errors.utils.parsepackagejson.willBeRequired', {url: 'https://ghost.org/docs/api/handlebars-themes/'}); err.help = i18n.t('errors.utils.parsepackagejson.willBeRequired', {url: 'https://ghost.org/docs/api/handlebars-themes/'});
return Promise.reject(err); return Promise.reject(err);
} }

View file

@ -7,7 +7,7 @@ const _ = require('lodash');
const join = require('path').join; const join = require('path').join;
const fs = require('fs-extra'); const fs = require('fs-extra');
const parsePackageJson = require('./parse'); const parsePackageJson = require('./parse');
const common = require('../../common'); const errors = require('@tryghost/errors');
const notAPackageRegex = /^\.|_messages|README.md|node_modules|bower_components/i; const notAPackageRegex = /^\.|_messages|README.md|node_modules|bower_components/i;
const packageJSONPath = 'package.json'; const packageJSONPath = 'package.json';
let readPackage; let readPackage;
@ -53,7 +53,7 @@ readPackage = function readPackage(packagePath, packageName) {
}); });
}) })
.catch(function (err) { .catch(function (err) {
return Promise.reject(new common.errors.NotFoundError({ return Promise.reject(new errors.NotFoundError({
message: 'Package not found', message: 'Package not found',
err: err, err: err,
help: 'path: ' + packagePath, help: 'path: ' + packagePath,

View file

@ -1,4 +1,5 @@
const common = require('./common'); const errors = require('@tryghost/errors');
const {logging} = require('./common');
const config = require('../config'); const config = require('../config');
let cardFactory; let cardFactory;
@ -49,7 +50,7 @@ module.exports = {
cards: this.cards, cards: this.cards,
atoms: this.atoms, atoms: this.atoms,
unknownCardHandler(args) { unknownCardHandler(args) {
common.logging.error(new common.errors.InternalServerError({ logging.error(new errors.InternalServerError({
message: 'Mobiledoc card \'' + args.env.name + '\' not found.' message: 'Mobiledoc card \'' + args.env.name + '\' not found.'
})); }));
} }
@ -64,7 +65,7 @@ module.exports = {
return require('@tryghost/html-to-mobiledoc').toMobiledoc; return require('@tryghost/html-to-mobiledoc').toMobiledoc;
} catch (err) { } catch (err) {
return () => { return () => {
throw new common.errors.InternalServerError({ throw new errors.InternalServerError({
message: 'Unable to convert from source HTML to Mobiledoc', message: 'Unable to convert from source HTML to Mobiledoc',
context: 'The html-to-mobiledoc package was not installed', context: 'The html-to-mobiledoc package was not installed',
help: 'Please review any errors from the install process by checking the Ghost logs', help: 'Please review any errors from the install process by checking the Ghost logs',

View file

@ -1,7 +1,8 @@
const jwt = require('jsonwebtoken'); const jwt = require('jsonwebtoken');
const url = require('url'); const url = require('url');
const models = require('../../../models'); const models = require('../../../models');
const common = require('../../../lib/common'); const errors = require('@tryghost/errors');
const {i18n} = require('../../../lib/common');
const _ = require('lodash'); const _ = require('lodash');
let JWT_OPTIONS = { let JWT_OPTIONS = {
@ -42,8 +43,8 @@ const authenticate = (req, res, next) => {
const token = _extractTokenFromHeader(req.headers.authorization); const token = _extractTokenFromHeader(req.headers.authorization);
if (!token) { if (!token) {
return next(new common.errors.UnauthorizedError({ return next(new errors.UnauthorizedError({
message: common.i18n.t('errors.middleware.auth.incorrectAuthHeaderFormat'), message: i18n.t('errors.middleware.auth.incorrectAuthHeaderFormat'),
code: 'INVALID_AUTH_HEADER' code: 'INVALID_AUTH_HEADER'
})); }));
} }
@ -54,8 +55,8 @@ const authenticate = (req, res, next) => {
const authenticateWithUrl = (req, res, next) => { const authenticateWithUrl = (req, res, next) => {
const token = _extractTokenFromUrl(req.originalUrl); const token = _extractTokenFromUrl(req.originalUrl);
if (!token) { if (!token) {
return next(new common.errors.UnauthorizedError({ return next(new errors.UnauthorizedError({
message: common.i18n.t('errors.middleware.auth.invalidTokenWithMessage', {message: 'No token found in URL'}), message: i18n.t('errors.middleware.auth.invalidTokenWithMessage', {message: 'No token found in URL'}),
code: 'INVALID_JWT' code: 'INVALID_JWT'
})); }));
} }
@ -81,8 +82,8 @@ const authenticateWithToken = (req, res, next, {token, JWT_OPTIONS}) => {
const decoded = jwt.decode(token, {complete: true}); const decoded = jwt.decode(token, {complete: true});
if (!decoded || !decoded.header) { if (!decoded || !decoded.header) {
return next(new common.errors.BadRequestError({ return next(new errors.BadRequestError({
message: common.i18n.t('errors.middleware.auth.invalidToken'), message: i18n.t('errors.middleware.auth.invalidToken'),
code: 'INVALID_JWT' code: 'INVALID_JWT'
})); }));
} }
@ -90,23 +91,23 @@ const authenticateWithToken = (req, res, next, {token, JWT_OPTIONS}) => {
const apiKeyId = decoded.header.kid; const apiKeyId = decoded.header.kid;
if (!apiKeyId) { if (!apiKeyId) {
return next(new common.errors.BadRequestError({ return next(new errors.BadRequestError({
message: common.i18n.t('errors.middleware.auth.adminApiKidMissing'), message: i18n.t('errors.middleware.auth.adminApiKidMissing'),
code: 'MISSING_ADMIN_API_KID' code: 'MISSING_ADMIN_API_KID'
})); }));
} }
models.ApiKey.findOne({id: apiKeyId}).then((apiKey) => { models.ApiKey.findOne({id: apiKeyId}).then((apiKey) => {
if (!apiKey) { if (!apiKey) {
return next(new common.errors.UnauthorizedError({ return next(new errors.UnauthorizedError({
message: common.i18n.t('errors.middleware.auth.unknownAdminApiKey'), message: i18n.t('errors.middleware.auth.unknownAdminApiKey'),
code: 'UNKNOWN_ADMIN_API_KEY' code: 'UNKNOWN_ADMIN_API_KEY'
})); }));
} }
if (apiKey.get('type') !== 'admin') { if (apiKey.get('type') !== 'admin') {
return next(new common.errors.UnauthorizedError({ return next(new errors.UnauthorizedError({
message: common.i18n.t('errors.middleware.auth.invalidApiKeyType'), message: i18n.t('errors.middleware.auth.invalidApiKeyType'),
code: 'INVALID_API_KEY_TYPE' code: 'INVALID_API_KEY_TYPE'
})); }));
} }
@ -129,22 +130,22 @@ const authenticateWithToken = (req, res, next, {token, JWT_OPTIONS}) => {
jwt.verify(token, secret, options); jwt.verify(token, secret, options);
} catch (err) { } catch (err) {
if (err.name === 'TokenExpiredError' || err.name === 'JsonWebTokenError') { if (err.name === 'TokenExpiredError' || err.name === 'JsonWebTokenError') {
return next(new common.errors.UnauthorizedError({ return next(new errors.UnauthorizedError({
message: common.i18n.t('errors.middleware.auth.invalidTokenWithMessage', {message: err.message}), message: i18n.t('errors.middleware.auth.invalidTokenWithMessage', {message: err.message}),
code: 'INVALID_JWT', code: 'INVALID_JWT',
err err
})); }));
} }
// unknown error // unknown error
return next(new common.errors.InternalServerError({err})); return next(new errors.InternalServerError({err}));
} }
// authenticated OK, store the api key on the request for later checks and logging // authenticated OK, store the api key on the request for later checks and logging
req.api_key = apiKey; req.api_key = apiKey;
next(); next();
}).catch((err) => { }).catch((err) => {
next(new common.errors.InternalServerError({err})); next(new errors.InternalServerError({err}));
}); });
}; };

View file

@ -1,5 +1,6 @@
const models = require('../../../models'); const models = require('../../../models');
const common = require('../../../lib/common'); const errors = require('@tryghost/errors');
const {i18n} = require('../../../lib/common');
const authenticateContentApiKey = function authenticateContentApiKey(req, res, next) { const authenticateContentApiKey = function authenticateContentApiKey(req, res, next) {
// allow fallthrough to other auth methods or final ensureAuthenticated check // allow fallthrough to other auth methods or final ensureAuthenticated check
@ -8,8 +9,8 @@ const authenticateContentApiKey = function authenticateContentApiKey(req, res, n
} }
if (req.query.key.constructor === Array) { if (req.query.key.constructor === Array) {
return next(new common.errors.BadRequestError({ return next(new errors.BadRequestError({
message: common.i18n.t('errors.middleware.auth.invalidRequest'), message: i18n.t('errors.middleware.auth.invalidRequest'),
code: 'INVALID_REQUEST' code: 'INVALID_REQUEST'
})); }));
} }
@ -18,15 +19,15 @@ const authenticateContentApiKey = function authenticateContentApiKey(req, res, n
models.ApiKey.findOne({secret: key}).then((apiKey) => { models.ApiKey.findOne({secret: key}).then((apiKey) => {
if (!apiKey) { if (!apiKey) {
return next(new common.errors.UnauthorizedError({ return next(new errors.UnauthorizedError({
message: common.i18n.t('errors.middleware.auth.unknownContentApiKey'), message: i18n.t('errors.middleware.auth.unknownContentApiKey'),
code: 'UNKNOWN_CONTENT_API_KEY' code: 'UNKNOWN_CONTENT_API_KEY'
})); }));
} }
if (apiKey.get('type') !== 'content') { if (apiKey.get('type') !== 'content') {
return next(new common.errors.UnauthorizedError({ return next(new errors.UnauthorizedError({
message: common.i18n.t('errors.middleware.auth.invalidApiKeyType'), message: i18n.t('errors.middleware.auth.invalidApiKeyType'),
code: 'INVALID_API_KEY_TYPE' code: 'INVALID_API_KEY_TYPE'
})); }));
} }
@ -35,7 +36,7 @@ const authenticateContentApiKey = function authenticateContentApiKey(req, res, n
req.api_key = apiKey; req.api_key = apiKey;
next(); next();
}).catch((err) => { }).catch((err) => {
next(new common.errors.InternalServerError({err})); next(new errors.InternalServerError({err}));
}); });
}; };

View file

@ -1,5 +1,6 @@
const labs = require('../labs'); const labs = require('../labs');
const common = require('../../lib/common'); const errors = require('@tryghost/errors');
const {i18n} = require('../../lib/common');
const authorize = { const authorize = {
authorizeContentApi(req, res, next) { authorizeContentApi(req, res, next) {
@ -11,9 +12,9 @@ const authorize = {
if (labs.isSet('members') && hasMember) { if (labs.isSet('members') && hasMember) {
return next(); return next();
} }
return next(new common.errors.NoPermissionError({ return next(new errors.NoPermissionError({
message: common.i18n.t('errors.middleware.auth.authorizationFailed'), message: i18n.t('errors.middleware.auth.authorizationFailed'),
context: common.i18n.t('errors.middleware.auth.missingContentMemberOrIntegration') context: i18n.t('errors.middleware.auth.missingContentMemberOrIntegration')
})); }));
}, },
@ -24,9 +25,9 @@ const authorize = {
if (hasUser || hasApiKey) { if (hasUser || hasApiKey) {
return next(); return next();
} else { } else {
return next(new common.errors.NoPermissionError({ return next(new errors.NoPermissionError({
message: common.i18n.t('errors.middleware.auth.authorizationFailed'), message: i18n.t('errors.middleware.auth.authorizationFailed'),
context: common.i18n.t('errors.middleware.auth.missingAdminUserOrIntegration') context: i18n.t('errors.middleware.auth.missingAdminUserOrIntegration')
})); }));
} }
} }

View file

@ -1,7 +1,8 @@
const _ = require('lodash'); const _ = require('lodash');
const security = require('../../lib/security'); const security = require('../../lib/security');
const constants = require('../../lib/constants'); const constants = require('../../lib/constants');
const common = require('../../lib/common'); const errors = require('@tryghost/errors');
const {i18n} = require('../../lib/common');
const models = require('../../models'); const models = require('../../models');
const urlUtils = require('../../lib/url-utils'); const urlUtils = require('../../lib/url-utils');
const mail = require('../mail'); const mail = require('../mail');
@ -21,7 +22,7 @@ function generateToken(email, settingsAPI) {
}) })
.then((user) => { .then((user) => {
if (!user) { if (!user) {
throw new common.errors.NotFoundError({message: common.i18n.t('errors.api.users.userNotFound')}); throw new errors.NotFoundError({message: i18n.t('errors.api.users.userNotFound')});
} }
token = security.tokens.resetToken.generateHash({ token = security.tokens.resetToken.generateHash({
@ -46,8 +47,8 @@ function extractTokenParts(options) {
}); });
if (!tokenParts) { if (!tokenParts) {
return Promise.reject(new common.errors.UnauthorizedError({ return Promise.reject(new errors.UnauthorizedError({
message: common.i18n.t('errors.api.common.invalidTokenStructure') message: i18n.t('errors.api.common.invalidTokenStructure')
})); }));
} }
@ -58,8 +59,8 @@ function extractTokenParts(options) {
function protectBruteForce({options, tokenParts}) { function protectBruteForce({options, tokenParts}) {
if (tokenSecurity[`${tokenParts.email}+${tokenParts.expires}`] && if (tokenSecurity[`${tokenParts.email}+${tokenParts.expires}`] &&
tokenSecurity[`${tokenParts.email}+${tokenParts.expires}`].count >= 10) { tokenSecurity[`${tokenParts.email}+${tokenParts.expires}`].count >= 10) {
return Promise.reject(new common.errors.NoPermissionError({ return Promise.reject(new errors.NoPermissionError({
message: common.i18n.t('errors.models.user.tokenLocked') message: i18n.t('errors.models.user.tokenLocked')
})); }));
} }
@ -82,7 +83,7 @@ function doReset(options, tokenParts, settingsAPI) {
}) })
.then((user) => { .then((user) => {
if (!user) { if (!user) {
throw new common.errors.NotFoundError({message: common.i18n.t('errors.api.users.userNotFound')}); throw new errors.NotFoundError({message: i18n.t('errors.api.users.userNotFound')});
} }
let tokenIsCorrect = security.tokens.resetToken.compare({ let tokenIsCorrect = security.tokens.resetToken.compare({
@ -92,8 +93,8 @@ function doReset(options, tokenParts, settingsAPI) {
}); });
if (!tokenIsCorrect) { if (!tokenIsCorrect) {
return Promise.reject(new common.errors.BadRequestError({ return Promise.reject(new errors.BadRequestError({
message: common.i18n.t('errors.api.common.invalidTokenStructure') message: i18n.t('errors.api.common.invalidTokenStructure')
})); }));
} }
@ -107,14 +108,14 @@ function doReset(options, tokenParts, settingsAPI) {
updatedUser.set('status', 'active'); updatedUser.set('status', 'active');
return updatedUser.save(options); return updatedUser.save(options);
}) })
.catch(common.errors.ValidationError, (err) => { .catch(errors.ValidationError, (err) => {
return Promise.reject(err); return Promise.reject(err);
}) })
.catch((err) => { .catch((err) => {
if (common.errors.utils.isIgnitionError(err)) { if (errors.utils.isIgnitionError(err)) {
return Promise.reject(err); return Promise.reject(err);
} }
return Promise.reject(new common.errors.UnauthorizedError({err: err})); return Promise.reject(new errors.UnauthorizedError({err: err}));
}); });
} }
@ -133,7 +134,7 @@ async function sendResetNotification(data, mailAPI) {
mail: [{ mail: [{
message: { message: {
to: data.email, to: data.email,
subject: common.i18n.t('common.api.authentication.mail.resetPassword'), subject: i18n.t('common.api.authentication.mail.resetPassword'),
html: content.html, html: content.html,
text: content.text text: content.text
}, },

View file

@ -1,6 +1,7 @@
const _ = require('lodash'); const _ = require('lodash');
const config = require('../../config'); const config = require('../../config');
const common = require('../../lib/common'); const errors = require('@tryghost/errors');
const {i18n, logging} = require('../../lib/common');
const models = require('../../models'); const models = require('../../models');
const mail = require('../mail'); const mail = require('../mail');
@ -27,11 +28,11 @@ function assertSetupCompleted(status) {
return __; return __;
} }
const completed = common.i18n.t('errors.api.authentication.setupAlreadyCompleted'); const completed = i18n.t('errors.api.authentication.setupAlreadyCompleted');
const notCompleted = common.i18n.t('errors.api.authentication.setupMustBeCompleted'); const notCompleted = i18n.t('errors.api.authentication.setupMustBeCompleted');
function throwReason(reason) { function throwReason(reason) {
throw new common.errors.NoPermissionError({message: reason}); throw new errors.NoPermissionError({message: reason});
} }
if (isSetup) { if (isSetup) {
@ -48,8 +49,8 @@ async function setupUser(userData) {
const owner = await models.User.findOne({role: 'Owner', status: 'all'}); const owner = await models.User.findOne({role: 'Owner', status: 'all'});
if (!owner) { if (!owner) {
throw new common.errors.GhostError({ throw new errors.GhostError({
message: common.i18n.t('errors.api.authentication.setupUnableToRun') message: i18n.t('errors.api.authentication.setupUnableToRun')
}); });
} }
@ -74,7 +75,7 @@ async function doSettings(data, settingsAPI) {
userSettings = [ userSettings = [
{key: 'title', value: blogTitle.trim()}, {key: 'title', value: blogTitle.trim()},
{key: 'description', value: common.i18n.t('common.api.authentication.sampleBlogDescription')} {key: 'description', value: i18n.t('common.api.authentication.sampleBlogDescription')}
]; ];
await settingsAPI.edit({settings: userSettings}, context); await settingsAPI.edit({settings: userSettings}, context);
@ -92,7 +93,7 @@ function sendWelcomeEmail(email, mailAPI) {
.then((content) => { .then((content) => {
const message = { const message = {
to: email, to: email,
subject: common.i18n.t('common.api.authentication.mail.yourNewGhostBlog'), subject: i18n.t('common.api.authentication.mail.yourNewGhostBlog'),
html: content.html, html: content.html,
text: content.text text: content.text
}; };
@ -106,8 +107,8 @@ function sendWelcomeEmail(email, mailAPI) {
mailAPI.send(payload, {context: {internal: true}}) mailAPI.send(payload, {context: {internal: true}})
.catch((err) => { .catch((err) => {
err.context = common.i18n.t('errors.api.authentication.unableToSendWelcomeEmail'); err.context = i18n.t('errors.api.authentication.unableToSendWelcomeEmail');
common.logging.error(err); logging.error(err);
}); });
}); });
} }

View file

@ -1,5 +1,6 @@
const _ = require('lodash'); const _ = require('lodash');
const common = require('../../lib/common'); const errors = require('@tryghost/errors');
const {i18n, logging} = require('../../lib/common');
const mailgunProvider = require('./mailgun'); const mailgunProvider = require('./mailgun');
const configService = require('../../config'); const configService = require('../../config');
const settingsCache = require('../settings/cache'); const settingsCache = require('../settings/cache');
@ -64,7 +65,7 @@ module.exports = {
let fromAddress = message.from; let fromAddress = message.from;
if (/@localhost$/.test(message.from) || /@ghost.local$/.test(message.from)) { if (/@localhost$/.test(message.from) || /@ghost.local$/.test(message.from)) {
fromAddress = 'localhost@example.com'; fromAddress = 'localhost@example.com';
common.logging.warn(`Rewriting bulk email from address ${message.from} to ${fromAddress}`); logging.warn(`Rewriting bulk email from address ${message.from} to ${fromAddress}`);
BATCH_SIZE = 2; BATCH_SIZE = 2;
} }
@ -101,13 +102,13 @@ module.exports = {
if (error) { if (error) {
// NOTE: logging an error here only but actual handling should happen in more sophisticated batch retry handler // NOTE: logging an error here only but actual handling should happen in more sophisticated batch retry handler
// REF: possible mailgun errors https://documentation.mailgun.com/en/latest/api-intro.html#errors // REF: possible mailgun errors https://documentation.mailgun.com/en/latest/api-intro.html#errors
let ghostError = new common.errors.EmailError({ let ghostError = new errors.EmailError({
err: error, err: error,
context: common.i18n.t('errors.services.mega.requestFailed.error') context: i18n.t('errors.services.mega.requestFailed.error')
}); });
sentry.captureException(ghostError); sentry.captureException(ghostError);
common.logging.warn(ghostError); logging.warn(ghostError);
// NOTE: these are generated variables, so can be regenerated when retry is done // NOTE: these are generated variables, so can be regenerated when retry is done
const data = _.omit(batchData, ['recipient-variables']); const data = _.omit(batchData, ['recipient-variables']);

View file

@ -1,6 +1,6 @@
const {URL} = require('url'); const {URL} = require('url');
const mailgun = require('mailgun-js'); const mailgun = require('mailgun-js');
const common = require('../../lib/common'); const {logging} = require('../../lib/common');
const configService = require('../../config'); const configService = require('../../config');
const settingsCache = require('../settings/cache'); const settingsCache = require('../settings/cache');
@ -24,13 +24,13 @@ function getInstance() {
const hasMailgunConfig = !!(bulkEmailConfig && bulkEmailConfig.mailgun); const hasMailgunConfig = !!(bulkEmailConfig && bulkEmailConfig.mailgun);
const hasMailgunSetting = !!(bulkEmailSetting && bulkEmailSetting.apiKey && bulkEmailSetting.baseUrl && bulkEmailSetting.domain); const hasMailgunSetting = !!(bulkEmailSetting && bulkEmailSetting.apiKey && bulkEmailSetting.baseUrl && bulkEmailSetting.domain);
if (!hasMailgunConfig && !hasMailgunSetting) { if (!hasMailgunConfig && !hasMailgunSetting) {
common.logging.warn(`Bulk email service is not configured`); logging.warn(`Bulk email service is not configured`);
} else { } else {
try { try {
let mailgunConfig = hasMailgunConfig ? bulkEmailConfig.mailgun : bulkEmailSetting; let mailgunConfig = hasMailgunConfig ? bulkEmailConfig.mailgun : bulkEmailSetting;
return createMailgun(mailgunConfig); return createMailgun(mailgunConfig);
} catch (err) { } catch (err) {
common.logging.warn(`Bulk email service is not configured`); logging.warn(`Bulk email service is not configured`);
} }
} }
return null; return null;

View file

@ -1,4 +1,5 @@
const common = require('../../lib/common'); const errors = require('@tryghost/errors');
const {i18n} = require('../../lib/common');
const models = require('../../models'); const models = require('../../models');
const security = require('../../lib/security'); const security = require('../../lib/security');
@ -10,11 +11,11 @@ async function accept(invitation) {
let invite = await models.Invite.findOne({token: inviteToken, status: 'sent'}, options); let invite = await models.Invite.findOne({token: inviteToken, status: 'sent'}, options);
if (!invite) { if (!invite) {
throw new common.errors.NotFoundError({message: common.i18n.t('errors.api.invites.inviteNotFound')}); throw new errors.NotFoundError({message: i18n.t('errors.api.invites.inviteNotFound')});
} }
if (invite.get('expires') < Date.now()) { if (invite.get('expires') < Date.now()) {
throw new common.errors.NotFoundError({message: common.i18n.t('errors.api.invites.inviteExpired')}); throw new errors.NotFoundError({message: i18n.t('errors.api.invites.inviteExpired')});
} }
await models.User.add({ await models.User.add({

View file

@ -2,7 +2,8 @@ const settingsCache = require('./settings/cache');
const _ = require('lodash'); const _ = require('lodash');
const Promise = require('bluebird'); const Promise = require('bluebird');
const SafeString = require('../../frontend/services/themes/engine').SafeString; const SafeString = require('../../frontend/services/themes/engine').SafeString;
const common = require('../lib/common'); const errors = require('@tryghost/errors');
const {i18n, logging} = require('../lib/common');
const deprecatedFeatures = ['subscribers', 'publicAPI']; const deprecatedFeatures = ['subscribers', 'publicAPI'];
module.exports.getAll = () => { module.exports.getAll = () => {
@ -31,14 +32,14 @@ module.exports.enabledHelper = function enabledHelper(options, callback) {
} }
// Else, the helper is not active and we need to handle this as an error // Else, the helper is not active and we need to handle this as an error
errDetails.message = common.i18n.t(options.errMessagePath || 'warnings.helpers.helperNotAvailable', {helperName: options.helperName}), errDetails.message = i18n.t(options.errMessagePath || 'warnings.helpers.helperNotAvailable', {helperName: options.helperName}),
errDetails.context = common.i18n.t(options.errContextPath || 'warnings.helpers.flagMustBeEnabled', { errDetails.context = i18n.t(options.errContextPath || 'warnings.helpers.flagMustBeEnabled', {
helperName: options.helperName, helperName: options.helperName,
flagName: options.flagName flagName: options.flagName
}); });
errDetails.help = common.i18n.t(options.errHelpPath || 'warnings.helpers.seeLink', {url: options.helpUrl}); errDetails.help = i18n.t(options.errHelpPath || 'warnings.helpers.seeLink', {url: options.helpUrl});
common.logging.error(new common.errors.DisabledFeatureError(errDetails)); logging.error(new errors.DisabledFeatureError(errDetails));
errString = new SafeString(`<script>console.error("${_.values(errDetails).join(' ')}");</script>`); errString = new SafeString(`<script>console.error("${_.values(errDetails).join(' ')}");</script>`);

View file

@ -4,12 +4,13 @@ const _ = require('lodash');
const Promise = require('bluebird'); const Promise = require('bluebird');
const validator = require('validator'); const validator = require('validator');
const config = require('../../config'); const config = require('../../config');
const common = require('../../lib/common'); const errors = require('@tryghost/errors');
const {i18n} = require('../../lib/common');
const settingsCache = require('../settings/cache'); const settingsCache = require('../settings/cache');
const urlUtils = require('../../lib/url-utils'); const urlUtils = require('../../lib/url-utils');
const helpMessage = common.i18n.t('errors.api.authentication.checkEmailConfigInstructions', {url: 'https://ghost.org/docs/concepts/config/#mail'}); const helpMessage = i18n.t('errors.api.authentication.checkEmailConfigInstructions', {url: 'https://ghost.org/docs/concepts/config/#mail'});
const defaultErrorMessage = common.i18n.t('errors.mail.failedSendingEmail.error'); const defaultErrorMessage = i18n.t('errors.mail.failedSendingEmail.error');
function getDomain() { function getDomain() {
const domain = urlUtils.urlFor('home', true).match(new RegExp('^https?://([^/:?#]+)(?:[/:?#]|$)', 'i')); const domain = urlUtils.urlFor('home', true).match(new RegExp('^https?://([^/:?#]+)(?:[/:?#]|$)', 'i'));
@ -28,7 +29,7 @@ function getFromAddress(requestedFromAddress) {
// If we do have a from address, and it's just an email // If we do have a from address, and it's just an email
if (validator.isEmail(address, {require_tld: false})) { if (validator.isEmail(address, {require_tld: false})) {
const defaultBlogTitle = settingsCache.get('title') ? settingsCache.get('title').replace(/"/g, '\\"') : common.i18n.t('common.mail.title', {domain: getDomain()}); const defaultBlogTitle = settingsCache.get('title') ? settingsCache.get('title').replace(/"/g, '\\"') : i18n.t('common.mail.title', {domain: getDomain()});
return `"${defaultBlogTitle}" <${address}>`; return `"${defaultBlogTitle}" <${address}>`;
} }
@ -47,7 +48,7 @@ function createMessage(message) {
function createMailError({message, err, ignoreDefaultMessage} = {message: ''}) { function createMailError({message, err, ignoreDefaultMessage} = {message: ''}) {
const fullErrorMessage = defaultErrorMessage + message; const fullErrorMessage = defaultErrorMessage + message;
return new common.errors.EmailError({ return new errors.EmailError({
message: ignoreDefaultMessage ? message : fullErrorMessage, message: ignoreDefaultMessage ? message : fullErrorMessage,
err: err, err: err,
help: helpMessage help: helpMessage
@ -70,7 +71,7 @@ module.exports = class GhostMailer {
send(message) { send(message) {
if (!(message && message.subject && message.html && message.to)) { if (!(message && message.subject && message.html && message.to)) {
return Promise.reject(createMailError({ return Promise.reject(createMailError({
message: common.i18n.t('errors.mail.incompleteMessageData.error'), message: i18n.t('errors.mail.incompleteMessageData.error'),
ignoreDefaultMessage: true ignoreDefaultMessage: true
})); }));
} }
@ -90,7 +91,7 @@ module.exports = class GhostMailer {
this.transport.sendMail(message, (err, response) => { this.transport.sendMail(message, (err, response) => {
if (err) { if (err) {
reject(createMailError({ reject(createMailError({
message: common.i18n.t('errors.mail.reason', {reason: err.message || err}), message: i18n.t('errors.mail.reason', {reason: err.message || err}),
err err
})); }));
} }
@ -104,7 +105,7 @@ module.exports = class GhostMailer {
response.statusHandler.once('failed', function (data) { response.statusHandler.once('failed', function (data) {
if (data.error && data.error.errno === 'ENOTFOUND') { if (data.error && data.error.errno === 'ENOTFOUND') {
reject(createMailError({ reject(createMailError({
message: common.i18n.t('errors.mail.noMailServerAtAddress.error', {domain: data.domain}) message: i18n.t('errors.mail.noMailServerAtAddress.error', {domain: data.domain})
})); }));
} }
@ -114,7 +115,7 @@ module.exports = class GhostMailer {
response.statusHandler.once('requeue', function (data) { response.statusHandler.once('requeue', function (data) {
if (data.error && data.error.message) { if (data.error && data.error.message) {
reject(createMailError({ reject(createMailError({
message: common.i18n.t('errors.mail.reason', {reason: data.error.message}) message: i18n.t('errors.mail.reason', {reason: data.error.message})
})); }));
} }
@ -122,7 +123,7 @@ module.exports = class GhostMailer {
}); });
response.statusHandler.once('sent', function () { response.statusHandler.once('sent', function () {
resolve(common.i18n.t('notices.mail.messageSent')); resolve(i18n.t('notices.mail.messageSent'));
}); });
}); });
} }

View file

@ -1,7 +1,8 @@
const _ = require('lodash'); const _ = require('lodash');
const url = require('url'); const url = require('url');
const moment = require('moment'); const moment = require('moment');
const common = require('../../lib/common'); const errors = require('@tryghost/errors');
const {events, i18n, logging} = require('../../lib/common');
const membersService = require('../members'); const membersService = require('../members');
const bulkEmailService = require('../bulk-email'); const bulkEmailService = require('../bulk-email');
const models = require('../../models'); const models = require('../../models');
@ -147,14 +148,14 @@ const retryFailedEmail = async (model) => {
*/ */
async function handleUnsubscribeRequest(req) { async function handleUnsubscribeRequest(req) {
if (!req.url) { if (!req.url) {
throw new common.errors.BadRequestError({ throw new errors.BadRequestError({
message: 'Unsubscribe failed! Could not find member' message: 'Unsubscribe failed! Could not find member'
}); });
} }
const {query} = url.parse(req.url, true); const {query} = url.parse(req.url, true);
if (!query || !query.uuid) { if (!query || !query.uuid) {
throw new common.errors.BadRequestError({ throw new errors.BadRequestError({
message: (query.preview ? 'Unsubscribe preview' : 'Unsubscribe failed! Could not find member') message: (query.preview ? 'Unsubscribe preview' : 'Unsubscribe failed! Could not find member')
}); });
} }
@ -164,7 +165,7 @@ async function handleUnsubscribeRequest(req) {
}); });
if (!member) { if (!member) {
throw new common.errors.BadRequestError({ throw new errors.BadRequestError({
message: 'Unsubscribe failed! Could not find member' message: 'Unsubscribe failed! Could not find member'
}); });
} }
@ -172,7 +173,7 @@ async function handleUnsubscribeRequest(req) {
try { try {
return await membersService.api.members.update({subscribed: false}, {id: member.id}); return await membersService.api.members.update({subscribed: false}, {id: member.id});
} catch (err) { } catch (err) {
throw new common.errors.InternalServerError({ throw new errors.InternalServerError({
message: 'Failed to unsubscribe member' message: 'Failed to unsubscribe member'
}); });
} }
@ -184,7 +185,7 @@ function checkHostLimitForMembers(members = []) {
const allowedMembersLimit = membersHostLimit.max; const allowedMembersLimit = membersHostLimit.max;
const hostUpgradeLink = config.get('host_settings:limits').upgrade_url; const hostUpgradeLink = config.get('host_settings:limits').upgrade_url;
if (members.length > allowedMembersLimit) { if (members.length > allowedMembersLimit) {
throw new common.errors.HostLimitError({ throw new errors.HostLimitError({
message: `Your current plan allows you to send email to up to ${allowedMembersLimit} members, but you currently have ${members.length} members`, message: `Your current plan allows you to send email to up to ${allowedMembersLimit} members, but you currently have ${members.length} members`,
help: hostUpgradeLink, help: hostUpgradeLink,
errorDetails: { errorDetails: {
@ -230,9 +231,9 @@ async function pendingEmailHandler(emailModel, options) {
// needs filtering and saving objects of {error, batchData} form to separate property // needs filtering and saving objects of {error, batchData} form to separate property
meta = await sendEmail(postModel, members); meta = await sendEmail(postModel, members);
} catch (err) { } catch (err) {
common.logging.error(new common.errors.GhostError({ logging.error(new errors.GhostError({
err: err, err: err,
context: common.i18n.t('errors.services.mega.requestFailed.error') context: i18n.t('errors.services.mega.requestFailed.error')
})); }));
error = err.message; error = err.message;
} }
@ -260,7 +261,7 @@ async function pendingEmailHandler(emailModel, options) {
id: emailModel.id id: emailModel.id
}); });
} catch (err) { } catch (err) {
common.logging.error(err); logging.error(err);
} }
} }
@ -275,8 +276,8 @@ const statusChangedHandler = (emailModel, options) => {
}; };
function listen() { function listen() {
common.events.on('email.added', pendingEmailHandler); events.on('email.added', pendingEmailHandler);
common.events.on('email.edited', statusChangedHandler); events.on('email.edited', statusChangedHandler);
} }
// Public API // Public API

View file

@ -1,6 +1,6 @@
const settingsCache = require('../settings/cache'); const settingsCache = require('../settings/cache');
const MembersApi = require('@tryghost/members-api'); const MembersApi = require('@tryghost/members-api');
const common = require('../../lib/common'); const {logging} = require('../../lib/common');
const mail = require('../mail'); const mail = require('../mail');
const models = require('../../models'); const models = require('../../models');
const signinEmail = require('./emails/signin'); const signinEmail = require('./emails/signin');
@ -24,7 +24,7 @@ function createApiInstance() {
transporter: { transporter: {
sendMail(message) { sendMail(message) {
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
common.logging.warn(message.text); logging.warn(message.text);
} }
let msg = Object.assign({ let msg = Object.assign({
from: config.getEmailFromAddress(), from: config.getEmailFromAddress(),
@ -126,7 +126,7 @@ function createApiInstance() {
memberStripeCustomerModel: models.MemberStripeCustomer, memberStripeCustomerModel: models.MemberStripeCustomer,
stripeCustomerSubscriptionModel: models.StripeCustomerSubscription, stripeCustomerSubscriptionModel: models.StripeCustomerSubscription,
memberModel: models.Member, memberModel: models.Member,
logger: common.logging logger: logging
}); });
return membersApiInstance; return membersApiInstance;

View file

@ -3,7 +3,7 @@ const settingsCache = require('../settings/cache');
const ghostVersion = require('../../lib/ghost-version'); const ghostVersion = require('../../lib/ghost-version');
const crypto = require('crypto'); const crypto = require('crypto');
const path = require('path'); const path = require('path');
const common = require('../../lib/common'); const {logging} = require('../../lib/common');
const urlUtils = require('../../lib/url-utils'); const urlUtils = require('../../lib/url-utils');
const COMPLIMENTARY_PLAN = { const COMPLIMENTARY_PLAN = {
@ -130,12 +130,12 @@ function getStripePaymentConfig() {
function getAuthSecret() { function getAuthSecret() {
const hexSecret = settingsCache.get('members_email_auth_secret'); const hexSecret = settingsCache.get('members_email_auth_secret');
if (!hexSecret) { if (!hexSecret) {
common.logging.warn('Could not find members_email_auth_secret, using dynamically generated secret'); logging.warn('Could not find members_email_auth_secret, using dynamically generated secret');
return crypto.randomBytes(64); return crypto.randomBytes(64);
} }
const secret = Buffer.from(hexSecret, 'hex'); const secret = Buffer.from(hexSecret, 'hex');
if (secret.length < 64) { if (secret.length < 64) {
common.logging.warn('members_email_auth_secret not large enough (64 bytes), using dynamically generated secret'); logging.warn('members_email_auth_secret not large enough (64 bytes), using dynamically generated secret');
return crypto.randomBytes(64); return crypto.randomBytes(64);
} }
return secret; return secret;

View file

@ -1,14 +1,14 @@
const MembersSSR = require('@tryghost/members-ssr'); const MembersSSR = require('@tryghost/members-ssr');
const createMembersApiInstance = require('./api'); const createMembersApiInstance = require('./api');
const common = require('../../lib/common'); const {events, logging} = require('../../lib/common');
const urlUtils = require('../../lib/url-utils'); const urlUtils = require('../../lib/url-utils');
const settingsCache = require('../settings/cache'); const settingsCache = require('../settings/cache');
let membersApi; let membersApi;
// Bind to events to automatically keep subscription info up-to-date from settings // Bind to events to automatically keep subscription info up-to-date from settings
common.events.on('settings.edited', function updateSettingFromModel(settingModel) { events.on('settings.edited', function updateSettingFromModel(settingModel) {
if (!['members_subscription_settings'].includes(settingModel.get('key'))) { if (!['members_subscription_settings'].includes(settingModel.get('key'))) {
return; return;
} }
@ -18,7 +18,7 @@ common.events.on('settings.edited', function updateSettingFromModel(settingModel
membersApi = reconfiguredMembersAPI; membersApi = reconfiguredMembersAPI;
}); });
reconfiguredMembersAPI.bus.on('error', function (err) { reconfiguredMembersAPI.bus.on('error', function (err) {
common.logging.error(err); logging.error(err);
}); });
}); });
@ -32,7 +32,7 @@ const membersService = {
membersApi = createMembersApiInstance(); membersApi = createMembersApiInstance();
membersApi.bus.on('error', function (err) { membersApi.bus.on('error', function (err) {
common.logging.error(err); logging.error(err);
}); });
} }
return membersApi; return membersApi;

View file

@ -1,4 +1,4 @@
const common = require('../../lib/common'); const {logging} = require('../../lib/common');
const config = require('../../config'); const config = require('../../config');
const labsService = require('../labs'); const labsService = require('../labs');
const membersService = require('./index'); const membersService = require('./index');
@ -19,7 +19,7 @@ const loadMemberSession = async function (req, res, next) {
res.locals.member = req.member; res.locals.member = req.member;
next(); next();
} catch (err) { } catch (err) {
common.logging.warn(err.message); logging.warn(err.message);
Object.assign(req, {member: null}); Object.assign(req, {member: null});
next(); next();
} }
@ -31,7 +31,7 @@ const getIdentityToken = async function (req, res) {
res.writeHead(200); res.writeHead(200);
res.end(token); res.end(token);
} catch (err) { } catch (err) {
common.logging.warn(err.message); logging.warn(err.message);
res.writeHead(err.statusCode); res.writeHead(err.statusCode);
res.end(err.message); res.end(err.message);
} }
@ -43,7 +43,7 @@ const deleteSession = async function (req, res) {
res.writeHead(204); res.writeHead(204);
res.end(); res.end();
} catch (err) { } catch (err) {
common.logging.warn(err.message); logging.warn(err.message);
res.writeHead(err.statusCode); res.writeHead(err.statusCode);
res.end(err.message); res.end(err.message);
} }
@ -66,7 +66,7 @@ const getMemberData = async function (req, res) {
res.json(null); res.json(null);
} }
} catch (err) { } catch (err) {
common.logging.warn(err.message); logging.warn(err.message);
res.writeHead(err.statusCode); res.writeHead(err.statusCode);
res.end(err.message); res.end(err.message);
} }
@ -114,7 +114,7 @@ const createSessionFromMagicLink = async function (req, res, next) {
// Do a standard 302 redirect // Do a standard 302 redirect
res.redirect(redirectPath); res.redirect(redirectPath);
} catch (err) { } catch (err) {
common.logging.warn(err.message); logging.warn(err.message);
return next(); return next();
} }
}; };

View file

@ -1,7 +1,8 @@
const _ = require('lodash'); const _ = require('lodash');
const Promise = require('bluebird'); const Promise = require('bluebird');
const models = require('../../models'); const models = require('../../models');
const common = require('../../lib/common'); const errors = require('@tryghost/errors');
const {i18n} = require('../../lib/common');
const providers = require('./providers'); const providers = require('./providers');
const parseContext = require('./parse-context'); const parseContext = require('./parse-context');
const actionsMap = require('./actions-map-cache'); const actionsMap = require('./actions-map-cache');
@ -102,7 +103,7 @@ CanThisResult.prototype.buildObjectTypeHandlers = function (objTypes, actType, c
return; return;
} }
return Promise.reject(new common.errors.NoPermissionError({message: common.i18n.t('errors.permissions.noPermissionToAction')})); return Promise.reject(new errors.NoPermissionError({message: i18n.t('errors.permissions.noPermissionToAction')}));
}); });
}; };
@ -120,7 +121,7 @@ CanThisResult.prototype.beginCheck = function (context) {
context = parseContext(context); context = parseContext(context);
if (actionsMap.empty()) { if (actionsMap.empty()) {
throw new Error(common.i18n.t('errors.permissions.noActionsMapFound.error')); throw new Error(i18n.t('errors.permissions.noActionsMapFound.error'));
} }
// Kick off loading of user permissions if necessary // Kick off loading of user permissions if necessary

View file

@ -1,7 +1,8 @@
const _ = require('lodash'); const _ = require('lodash');
const Promise = require('bluebird'); const Promise = require('bluebird');
const models = require('../../models'); const models = require('../../models');
const common = require('../../lib/common'); const errors = require('@tryghost/errors');
const {i18n} = require('../../lib/common');
module.exports = { module.exports = {
user: function (id) { user: function (id) {
@ -9,8 +10,8 @@ module.exports = {
.then(function (foundUser) { .then(function (foundUser) {
// CASE: {context: {user: id}} where the id is not in our database // CASE: {context: {user: id}} where the id is not in our database
if (!foundUser) { if (!foundUser) {
return Promise.reject(new common.errors.NotFoundError({ return Promise.reject(new errors.NotFoundError({
message: common.i18n.t('errors.models.user.userNotFound') message: i18n.t('errors.models.user.userNotFound')
})); }));
} }
@ -50,8 +51,8 @@ module.exports = {
return models.ApiKey.findOne({id}, {withRelated: ['role', 'role.permissions']}) return models.ApiKey.findOne({id}, {withRelated: ['role', 'role.permissions']})
.then((foundApiKey) => { .then((foundApiKey) => {
if (!foundApiKey) { if (!foundApiKey) {
throw new common.errors.NotFoundError({ throw new errors.NotFoundError({
message: common.i18n.t('errors.models.api_key.apiKeyNotFound') message: i18n.t('errors.models.api_key.apiKeyNotFound')
}); });
} }

View file

@ -1,6 +1,7 @@
const _ = require('lodash'); const _ = require('lodash');
const Promise = require('bluebird'); const Promise = require('bluebird');
const common = require('../../lib/common'); const errors = require('@tryghost/errors');
const {i18n} = require('../../lib/common');
const parseContext = require('./parse-context'); const parseContext = require('./parse-context');
const _private = {}; const _private = {};
@ -16,7 +17,7 @@ const _private = {};
* - public context cannot fetch draft/scheduled posts * - public context cannot fetch draft/scheduled posts
*/ */
_private.applyStatusRules = function applyStatusRules(docName, method, opts) { _private.applyStatusRules = function applyStatusRules(docName, method, opts) {
const err = new common.errors.NoPermissionError({message: common.i18n.t('errors.permissions.applyStatusRules.error', {docName: docName})}); const err = new errors.NoPermissionError({message: i18n.t('errors.permissions.applyStatusRules.error', {docName: docName})});
// Enforce status 'active' for users // Enforce status 'active' for users
if (docName === 'users') { if (docName === 'users') {

View file

@ -3,7 +3,7 @@
// circular dependency bugs. // circular dependency bugs.
const debug = require('ghost-ignition').debug('settings:cache'); const debug = require('ghost-ignition').debug('settings:cache');
const _ = require('lodash'); const _ = require('lodash');
const common = require('../../lib/common'); const {events} = require('../../lib/common');
const publicSettings = require('./public'); const publicSettings = require('./public');
// Local function, only ever used for initialising // Local function, only ever used for initialising
@ -123,17 +123,17 @@ module.exports = {
} }
// Bind to events to automatically keep up-to-date // Bind to events to automatically keep up-to-date
common.events.on('settings.edited', updateSettingFromModel); events.on('settings.edited', updateSettingFromModel);
common.events.on('settings.added', updateSettingFromModel); events.on('settings.added', updateSettingFromModel);
common.events.on('settings.deleted', updateSettingFromModel); events.on('settings.deleted', updateSettingFromModel);
return settingsCache; return settingsCache;
}, },
shutdown() { shutdown() {
common.events.removeListener('settings.edited', updateSettingFromModel); events.removeListener('settings.edited', updateSettingFromModel);
common.events.removeListener('settings.added', updateSettingFromModel); events.removeListener('settings.added', updateSettingFromModel);
common.events.removeListener('settings.deleted', updateSettingFromModel); events.removeListener('settings.deleted', updateSettingFromModel);
}, },
reset() { reset() {

View file

@ -1,4 +1,5 @@
const common = require('../lib/common'); const errors = require('@tryghost/errors');
const {events, i18n, logging} = require('../lib/common');
const request = require('../lib/request'); const request = require('../lib/request');
const imageLib = require('../lib/image'); const imageLib = require('../lib/image');
const urlUtils = require('../lib/url-utils'); const urlUtils = require('../lib/url-utils');
@ -123,10 +124,10 @@ function ping(post) {
'Content-type': 'application/json' 'Content-type': 'application/json'
} }
}).catch(function (err) { }).catch(function (err) {
common.logging.error(new common.errors.GhostError({ logging.error(new errors.GhostError({
err: err, err: err,
context: common.i18n.t('errors.services.ping.requestFailed.error', {service: 'slack'}), context: i18n.t('errors.services.ping.requestFailed.error', {service: 'slack'}),
help: common.i18n.t('errors.services.ping.requestFailed.help', {url: 'https://ghost.org/docs/'}) help: i18n.t('errors.services.ping.requestFailed.help', {url: 'https://ghost.org/docs/'})
})); }));
}); });
} }
@ -149,8 +150,8 @@ function testPing() {
} }
function listen() { function listen() {
common.events.on('post.published', listener); events.on('post.published', listener);
common.events.on('slack.test', testPing); events.on('slack.test', testPing);
} }
// Public API // Public API

View file

@ -1,5 +1,5 @@
const _ = require('lodash'); const _ = require('lodash');
const common = require('../../lib/common'); const {events} = require('../../lib/common');
const trigger = require('./trigger'); const trigger = require('./trigger');
const WEBHOOKS = [ const WEBHOOKS = [
@ -41,7 +41,7 @@ const WEBHOOKS = [
const listen = () => { const listen = () => {
_.each(WEBHOOKS, (event) => { _.each(WEBHOOKS, (event) => {
common.events.on(event, (model, options) => { events.on(event, (model, options) => {
// CASE: avoid triggering webhooks when importing // CASE: avoid triggering webhooks when importing
if (options && options.importing) { if (options && options.importing) {
return; return;

View file

@ -1,6 +1,6 @@
const _ = require('lodash'); const _ = require('lodash');
const debug = require('ghost-ignition').debug('services:webhooks:trigger'); const debug = require('ghost-ignition').debug('services:webhooks:trigger');
const common = require('../../lib/common'); const {logging} = require('../../lib/common');
const request = require('../../../server/lib/request'); const request = require('../../../server/lib/request');
const models = require('../../models'); const models = require('../../models');
const payload = require('./payload'); const payload = require('./payload');
@ -21,7 +21,7 @@ const webhooks = {
last_triggered_error: data.error || null last_triggered_error: data.error || null
}, {id: webhook.id}) }, {id: webhook.id})
.catch(() => { .catch(() => {
common.logging.warn(`Unable to update "last_triggered" for webhook: ${webhook.id}`); logging.warn(`Unable to update "last_triggered" for webhook: ${webhook.id}`);
}); });
}, },
@ -30,7 +30,7 @@ const webhooks = {
.Webhook .Webhook
.destroy({id: webhook.id}, {context: {internal: true}}) .destroy({id: webhook.id}, {context: {internal: true}})
.catch(() => { .catch(() => {
common.logging.warn(`Unable to destroy webhook ${webhook.id}.`); logging.warn(`Unable to destroy webhook ${webhook.id}.`);
}); });
} }
}; };
@ -47,7 +47,7 @@ const response = {
onError(webhook) { onError(webhook) {
return (err) => { return (err) => {
if (err.statusCode === 410) { if (err.statusCode === 410) {
common.logging.info(`Webhook destroyed (410 response) for "${webhook.get('event')}" with url "${webhook.get('target_url')}".`); logging.info(`Webhook destroyed (410 response) for "${webhook.get('event')}" with url "${webhook.get('target_url')}".`);
return webhooks.destroy(webhook); return webhooks.destroy(webhook);
} }
@ -57,7 +57,7 @@ const response = {
error: `Request failed: ${err.code || 'unknown'}` error: `Request failed: ${err.code || 'unknown'}`
}); });
common.logging.warn(`Request to ${webhook.get('target_url') || null} failed because of: ${err.code || ''}.`); logging.warn(`Request to ${webhook.get('target_url') || null} failed because of: ${err.code || ''}.`);
}; };
} }
}; };
@ -82,7 +82,7 @@ module.exports = (event, model) => {
retry: 5 retry: 5
}; };
common.logging.info(`Trigger Webhook for "${webhook.get('event')}" with url "${url}".`); logging.info(`Trigger Webhook for "${webhook.get('event')}" with url "${url}".`);
request(url, opts) request(url, opts)
.then(response.onSuccess(webhook)) .then(response.onSuccess(webhook))

View file

@ -2,7 +2,8 @@ const _ = require('lodash');
const xml = require('xml'); const xml = require('xml');
const config = require('../config'); const config = require('../config');
const urlService = require('../../frontend/services/url'); const urlService = require('../../frontend/services/url');
const common = require('../lib/common'); const errors = require('@tryghost/errors');
const {events, i18n, logging} = require('../lib/common');
const request = require('../lib/request'); const request = require('../lib/request');
const settingsCache = require('./settings/cache'); const settingsCache = require('./settings/cache');
@ -80,11 +81,11 @@ function ping(post) {
} }
}) })
.catch(function (err) { .catch(function (err) {
common.logging.error(new common.errors.GhostError({ logging.error(new errors.GhostError({
err: err, err: err,
message: err.message, message: err.message,
context: common.i18n.t('errors.services.ping.requestFailed.error', {service: 'xmlrpc'}), context: i18n.t('errors.services.ping.requestFailed.error', {service: 'xmlrpc'}),
help: common.i18n.t('errors.services.ping.requestFailed.help', {url: 'https://ghost.org/docs/'}) help: i18n.t('errors.services.ping.requestFailed.help', {url: 'https://ghost.org/docs/'})
})); }));
}); });
}); });
@ -101,7 +102,7 @@ function listener(model, options) {
} }
function listen() { function listen() {
common.events.on('post.published', listener); events.on('post.published', listener);
} }
module.exports = { module.exports = {

View file

@ -18,7 +18,8 @@ const debug = require('ghost-ignition').debug('update-check');
const api = require('./api').v2; const api = require('./api').v2;
const config = require('./config'); const config = require('./config');
const urlUtils = require('./lib/url-utils'); const urlUtils = require('./lib/url-utils');
const common = require('./lib/common'); const errors = require('@tryghost/errors');
const {i18n, logging} = require('./lib/common');
const request = require('./lib/request'); const request = require('./lib/request');
const ghostVersion = require('./lib/ghost-version'); const ghostVersion = require('./lib/ghost-version');
const internal = {context: {internal: true}}; const internal = {context: {internal: true}};
@ -49,9 +50,9 @@ function updateCheckError(err) {
}] }]
}, internal); }, internal);
err.context = common.i18n.t('errors.updateCheck.checkingForUpdatesFailed.error'); err.context = i18n.t('errors.updateCheck.checkingForUpdatesFailed.error');
err.help = common.i18n.t('errors.updateCheck.checkingForUpdatesFailed.help', {url: 'https://ghost.org/docs/'}); err.help = i18n.t('errors.updateCheck.checkingForUpdatesFailed.help', {url: 'https://ghost.org/docs/'});
common.logging.error(err); logging.error(err);
} }
/** /**
@ -178,7 +179,7 @@ function updateCheckRequest() {
// CASE: service returns JSON error, deserialize into JS error // CASE: service returns JSON error, deserialize into JS error
if (err.response && err.response.body && typeof err.response.body === 'object') { if (err.response && err.response.body && typeof err.response.body === 'object') {
err = common.errors.utils.deserialize(err.response.body); err = errors.utils.deserialize(err.response.body);
} }
throw err; throw err;

View file

@ -13,7 +13,7 @@ const ghost = require('./core');
debug('Required ghost'); debug('Required ghost');
const express = require('./core/shared/express'); const express = require('./core/shared/express');
const common = require('./core/server/lib/common'); const {logging} = require('./core/server/lib/common');
const urlService = require('./core/frontend/services/url'); const urlService = require('./core/frontend/services/url');
const ghostApp = express(); const ghostApp = express();
@ -31,10 +31,10 @@ ghost().then(function (ghostServer) {
// Let Ghost handle starting our server instance. // Let Ghost handle starting our server instance.
return ghostServer.start(ghostApp) return ghostServer.start(ghostApp)
.then(function afterStart() { .then(function afterStart() {
common.logging.info('Ghost boot', (Date.now() - startTime) / 1000 + 's'); logging.info('Ghost boot', (Date.now() - startTime) / 1000 + 's');
}); });
}).catch(function (err) { }).catch(function (err) {
common.logging.error(err); logging.error(err);
setTimeout(() => { setTimeout(() => {
process.exit(-1); process.exit(-1);
}, 100); }, 100);