Skip to content

Commit d07e9d8

Browse files
committed
Reverted "Deprecated models.init pattern for initializing models"
ref https://linear.app/ghost/issue/ENG-2071/remove-modelsinit-pattern - this reverts commit da101af
1 parent 1cff0c1 commit d07e9d8

File tree

67 files changed

+279
-87
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+279
-87
lines changed

ghost/core/core/boot.js

+6
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ async function initCore({ghostServer, config, frontend}) {
9191
require('./shared/url-utils');
9292
debug('End: Load urlUtils');
9393

94+
// Models are the heart of Ghost - this is a syncronous operation
95+
debug('Begin: models');
96+
const models = require('./server/models');
97+
models.init();
98+
debug('End: models');
99+
94100
// Settings are a core concept we use settings to store key-value pairs used in critical pathways as well as public data like the site title
95101
debug('Begin: settings');
96102
const settings = require('./server/services/settings/settings-service');

ghost/core/core/cli/generate-data.js

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ module.exports = class DataGeneratorCommand extends Command {
2121
const models = require('../server/models');
2222
const knex = require('../server/data/db/connection');
2323

24+
models.init();
25+
2426
context.models = models;
2527
context.m = models;
2628
context.knex = knex;

ghost/core/core/cli/repl.js

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ module.exports = class REPL extends Command {
1212
const models = require('../server/models');
1313
const knex = require('../server/data/db/connection');
1414

15+
models.init();
16+
1517
context.models = models;
1618
context.m = models;
1719
context.knex = knex;
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
const models = require('../../../../models');
2+
13
module.exports = function before() {
4+
models.init();
25
return Promise.resolve();
36
};

ghost/core/core/server/models/base/listeners.js

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
const moment = require('moment-timezone');
22
const _ = require('lodash');
3+
const models = require('../../models');
34
const logging = require('@tryghost/logging');
45
const errors = require('@tryghost/errors');
56
const {sequence} = require('@tryghost/promise');
67

7-
const {Post: PostModel} = require('../post');
8-
const {Settings: SettingsModel} = require('../settings');
9-
108
// Listen to settings.timezone.edited and settings.notifications.edited to bind extra logic to settings, similar to the bridge and member service
119
const events = require('../../lib/common/events');
1210

@@ -38,13 +36,12 @@ events.on('settings.timezone.edited', function (settingModel, options) {
3836
* We lock the target row on fetch by using the `forUpdate` option.
3937
* Read more in models/post.js - `onFetching`
4038
*/
41-
42-
return PostModel.transaction(async function (transacting) {
39+
return models.Base.transaction(async function (transacting) {
4340
options.transacting = transacting;
4441
options.forUpdate = true;
4542

4643
try {
47-
const results = await PostModel.findAll(_.merge({filter: 'status:scheduled'}, options));
44+
const results = await models.Post.findAll(_.merge({filter: 'status:scheduled'}, options));
4845
if (!results.length) {
4946
return;
5047
}
@@ -70,7 +67,7 @@ events.on('settings.timezone.edited', function (settingModel, options) {
7067
}
7168

7269
try {
73-
await PostModel.edit(post.toJSON(), _.merge({id: post.id}, options));
70+
await models.Post.edit(post.toJSON(), _.merge({id: post.id}, options));
7471
} catch (err) {
7572
logging.error(new errors.InternalServerError({
7673
err
@@ -114,7 +111,7 @@ events.on('settings.notifications.edited', function (settingModel) {
114111
return;
115112
}
116113

117-
return SettingsModel.edit({
114+
return models.Settings.edit({
118115
key: 'notifications',
119116
value: JSON.stringify(allNotifications)
120117
}, options).catch(function (err) {
+24-76
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,35 @@
1-
/* eslint-disable max-lines */
1+
/**
2+
* Dependencies
3+
*/
4+
5+
const _ = require('lodash');
6+
const debug = require('@tryghost/debug')('models');
7+
const glob = require('glob');
28

39
// enable event listeners
410
require('./base/listeners');
511

612
/**
713
* Expose all models
814
*/
9-
module.exports = {
10-
// `base` file does not export a Base model
11-
Base: require('./base'),
15+
exports = module.exports;
1216

13-
...require('./action'),
14-
...require('./author'),
15-
...require('./api-key'),
16-
...require('./benefit'),
17-
...require('./collection-post'),
18-
...require('./collection'),
19-
...require('./comment-like'),
20-
...require('./comment-report'),
21-
...require('./comment'),
22-
...require('./custom-theme-setting'),
23-
...require('./donation-payment-event'),
24-
...require('./email-batch'),
25-
...require('./email-recipient-failure'),
26-
...require('./email-recipient'),
27-
...require('./email-spam-complaint-event'),
28-
...require('./email'),
29-
...require('./integration'),
30-
...require('./invite'),
31-
...require('./job'),
32-
...require('./label'),
33-
...require('./mail-event'),
34-
...require('./member-cancel-event'),
35-
...require('./member-click-event'),
36-
...require('./member-created-event'),
37-
...require('./member-email-change-event'),
38-
...require('./member-feedback'),
39-
...require('./member-login-event'),
40-
...require('./member-newsletter'),
41-
...require('./member-paid-subscription-event'),
42-
...require('./member-payment-event'),
43-
...require('./member-product-event'),
44-
...require('./member-status-event'),
45-
...require('./member-stripe-customer'),
46-
...require('./member-subscribe-event'),
47-
...require('./member'),
48-
...require('./mention'),
49-
...require('./milestone'),
50-
...require('./mobiledoc-revision'),
51-
...require('./newsletter'),
52-
...require('./offer-redemption'),
53-
...require('./offer'),
54-
...require('./permission'),
55-
...require('./post-revision'),
56-
...require('./post'),
57-
...require('./posts-meta'),
58-
...require('./product'),
59-
...require('./recommendation-click-event'),
60-
...require('./recommendation-subscribe-event'),
61-
...require('./recommendation'),
62-
...require('./redirect'),
63-
...require('./role'),
64-
...require('./session'),
65-
...require('./settings'),
66-
...require('./single-use-token'),
67-
...require('./snippet'),
68-
...require('./stripe-customer-subscription'),
69-
...require('./stripe-price'),
70-
...require('./stripe-product'),
71-
...require('./subscription-created-event'),
72-
...require('./suppression'),
73-
...require('./tag-public'),
74-
...require('./tag'),
75-
...require('./user'),
76-
...require('./webhook')
77-
};
17+
function init() {
18+
const baseNow = Date.now();
19+
exports.Base = require('./base');
20+
debug(`${Date.now() - baseNow}ms - Base.js require`);
21+
22+
let modelsFiles = glob.sync('!(index).js', {cwd: __dirname});
23+
modelsFiles.forEach((model) => {
24+
const name = model.replace(/.js$/, '');
25+
const modelNow = Date.now();
26+
_.extend(exports, require('./' + name));
27+
debug(`${Date.now() - modelNow}ms - ${model} require`);
28+
});
29+
}
7830

7931
/**
80-
* @deprecated: remove this once we've removed it from everywhere
32+
* Expose `init`
8133
*/
82-
module.exports.init = function init() {
83-
if (process.env.NODE_ENV !== 'production') {
84-
// eslint-disable-next-line no-console
85-
console.warn('@deprecated: models.init() is deprecated. Models are now automatically required.');
86-
}
87-
};
34+
35+
exports.init = init;

ghost/core/core/server/models/user.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const errors = require('@tryghost/errors');
99
const security = require('@tryghost/security');
1010
const {pipeline} = require('@tryghost/promise');
1111
const validatePassword = require('../lib/validate-password');
12+
const permissions = require('../services/permissions');
1213
const urlUtils = require('../../shared/url-utils');
1314
const activeStates = ['active', 'warn-1', 'warn-2', 'warn-3', 'warn-4'];
1415
const ASSIGNABLE_ROLES = ['Administrator', 'Editor', 'Author', 'Contributor'];
@@ -904,7 +905,6 @@ User = ghostBookshelf.Model.extend({
904905
// @NOTE: your role is not the same than the role you try to change (!)
905906
// e.g. admin can assign admin role to a user, but not owner
906907

907-
const permissions = require('../services/permissions');
908908
return permissions.canThis(context).assign.role(role)
909909
.then(() => {
910910
if (hasUserPermission && hasApiKeyPermission) {

ghost/core/core/server/services/update-check/run-update-check.js

+4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ if (parentPort) {
3131
(async () => {
3232
const updateCheck = require('./');
3333

34+
// INIT required services
35+
const models = require('../../models');
36+
models.init();
37+
3438
const permissions = require('../permissions');
3539
await permissions.init();
3640

ghost/core/core/server/web/api/testmode/jobs/graceful-job.js

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ const internalContext = {context: {internal: true}};
2525
(async () => {
2626
const models = require('../../../../models');
2727

28+
await models.init();
29+
2830
postParentPortMessage(`Fetching tags`);
2931
const tags = await models.Tag.findPage(internalContext);
3032

ghost/core/test/integration/url_service.test.js

+5
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@ const should = require('should');
22
const sinon = require('sinon');
33
const testUtils = require('../utils');
44
const configUtils = require('../utils/configUtils');
5+
const models = require('../../core/server/models');
56
const UrlService = require('../../core/server/services/url/UrlService');
67

78
describe('Integration: services/url/UrlService', function () {
89
let urlService;
910

11+
before(function () {
12+
models.init();
13+
});
14+
1015
before(testUtils.teardownDb);
1116
before(testUtils.setup('users:roles', 'posts'));
1217
after(testUtils.teardownDb);

ghost/core/test/regression/api/admin/schedules.test.js

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ describe('Schedules API', function () {
1515
let request;
1616

1717
before(function () {
18+
models.init();
19+
1820
// @NOTE: mock the post scheduler, otherwise it will auto publish the post
1921
sinon.stub(SchedulingDefault.prototype, '_pingUrl').resolves();
2022
});

ghost/core/test/regression/models/model_settings.test.js

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const models = require('../../../core/server/models');
88
const SETTINGS_LENGTH = 94;
99

1010
describe('Settings Model', function () {
11+
before(models.init);
1112
afterEach(testUtils.teardownDb);
1213

1314
describe('defaults', function () {

ghost/core/test/unit/api/cache-invalidation.test.js

+7
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,15 @@ const path = require('path');
33

44
const glob = require('glob');
55

6+
const models = require('../../../core/server/models');
7+
68
describe('API', function () {
79
describe('Cache Invalidation', function () {
10+
before(async function () {
11+
// Initialise models - Utilised by various endpoints to reference static fields (i.e models.Post.allowedFormats) when required in
12+
models.init();
13+
});
14+
815
it('Controller actions explicitly declare cacheInvalidate header', async function () {
916
const controllersRootPath = path.join(__dirname, '../../../core/server/api/endpoints');
1017
const controllerPaths = glob.sync('*.js', {

ghost/core/test/unit/api/canary/session.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ const sessionController = require('../../../../core/server/api/endpoints/session
88
const sessionServiceMiddleware = require('../../../../core/server/services/auth/session');
99

1010
describe('Session controller', function () {
11+
before(function () {
12+
models.init();
13+
});
14+
1115
afterEach(function () {
1216
sinon.restore();
1317
});

ghost/core/test/unit/api/canary/utils/validators/input/pages.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ const validators = require('../../../../../../../core/server/api/endpoints/utils
55
const models = require('../../../../../../../core/server/models');
66

77
describe('Unit: endpoints/utils/validators/input/pages', function () {
8+
before(function () {
9+
return models.init();
10+
});
11+
812
beforeEach(function () {
913
const memberFindPageStub = sinon.stub(models.Member, 'findPage').returns(Promise.reject());
1014
memberFindPageStub.withArgs({filter: 'label:vip', limit: 1}).returns(Promise.resolve());

ghost/core/test/unit/api/canary/utils/validators/input/posts.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ const validators = require('../../../../../../../core/server/api/endpoints/utils
55
const models = require('../../../../../../../core/server/models');
66

77
describe('Unit: endpoints/utils/validators/input/posts', function () {
8+
before(function () {
9+
models.init();
10+
});
11+
812
beforeEach(function () {
913
const memberFindPageStub = sinon.stub(models.Member, 'findPage').returns(Promise.reject());
1014
memberFindPageStub.withArgs({filter: 'label:vip', limit: 1}).returns(Promise.resolve());

ghost/core/test/unit/frontend/helpers/authors.test.js

+5
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@ const should = require('should');
22
const sinon = require('sinon');
33
const urlService = require('../../../../core/server/services/url');
44
const authorsHelper = require('../../../../core/frontend/helpers/authors');
5+
const models = require('../../../../core/server/models');
56
const testUtils = require('../../../utils');
67

78
describe('{{authors}} helper', function () {
9+
before(function () {
10+
models.init();
11+
});
12+
813
beforeEach(function () {
914
sinon.stub(urlService, 'getUrlByResourceId');
1015
});

ghost/core/test/unit/frontend/helpers/get.test.js

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const loggingLib = require('@tryghost/logging');
77

88
// Stuff we are testing
99
const get = require('../../../../core/frontend/helpers/get');
10+
const models = require('../../../../core/server/models');
1011
const proxy = require('../../../../core/frontend/services/proxy');
1112
const api = require('../../../../core/server/api').endpoints;
1213

@@ -16,6 +17,10 @@ describe('{{#get}} helper', function () {
1617
let locals = {};
1718
let logging;
1819

20+
before(function () {
21+
models.init();
22+
});
23+
1924
beforeEach(function () {
2025
fn = sinon.spy();
2126
inverse = sinon.spy();

ghost/core/test/unit/frontend/helpers/ghost_head.test.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const _ = require('lodash');
66
const moment = require('moment');
77
const testUtils = require('../../../utils');
88
const configUtils = require('../../../utils/configUtils');
9+
const models = require('../../../../core/server/models');
910
const imageLib = require('../../../../core/server/lib/image');
1011
const routing = require('../../../../core/frontend/services/routing');
1112
const urlService = require('../../../../core/server/services/url');
@@ -357,6 +358,9 @@ describe('{{ghost_head}} helper', function () {
357358
};
358359

359360
before(function () {
361+
// @TODO: remove when visibility is refactored out of models
362+
models.init();
363+
360364
keyStub = sinon.stub().resolves('xyz');
361365
const dataService = {
362366
getFrontendKey: keyStub
@@ -1543,7 +1547,7 @@ describe('{{ghost_head}} helper', function () {
15431547
}));
15441548

15451549
rendered.should.match(/data-datasource="analytics_events_json_v1"/);
1546-
});
1550+
});
15471551
});
15481552
describe('respects values from excludes: ', function () {
15491553
it('when excludes is empty', async function () {

ghost/core/test/unit/frontend/helpers/recommendations.test.js

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const should = require('should');
22
const sinon = require('sinon');
3+
const models = require('../../../../core/server/models');
34
const api = require('../../../../core/server/api').endpoints;
45
const hbs = require('../../../../core/frontend/services/theme-engine/engine');
56
const configUtils = require('../../../utils/configUtils');
@@ -20,6 +21,8 @@ describe('{{#recommendations}} helper', function () {
2021
let logging;
2122

2223
before(function () {
24+
models.init();
25+
2326
hbs.express4({
2427
partialsDir: [configUtils.config.get('paths').helperTemplates]
2528
});

0 commit comments

Comments
 (0)