ghost 4.36.3 → 4.38.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.c8rc.json +10 -0
- package/content/themes/casper/LICENSE +1 -1
- package/content/themes/casper/README.md +1 -1
- package/content/themes/casper/assets/built/global.css +1 -1
- package/content/themes/casper/assets/built/global.css.map +1 -1
- package/content/themes/casper/assets/built/screen.css +1 -1
- package/content/themes/casper/assets/built/screen.css.map +1 -1
- package/content/themes/casper/assets/css/global.css +14 -6
- package/content/themes/casper/assets/css/screen.css +9 -1
- package/content/themes/casper/package.json +2 -2
- package/content/themes/casper/partials/post-card.hbs +1 -1
- package/content/themes/casper/post.hbs +18 -19
- package/content/themes/casper/yarn.lock +186 -217
- package/core/built/assets/ghost-dark-9f760f16230b8bc52e188d6ce28516b0.css +1 -0
- package/core/built/assets/{ghost.min-801697772dc605c0dae0abfec54ec591.js → ghost.min-6386b02480494a69c3bfe66206754836.js} +375 -312
- package/core/built/assets/ghost.min-f4c59dd57a2136df8b0a34f87c099034.css +1 -0
- package/core/built/assets/icons/eye.svg +4 -1
- package/core/built/assets/icons/member-add.svg +3 -0
- package/core/built/assets/icons/pin.svg +4 -1
- package/core/built/assets/{vendor.min-2313642ee897688be83924a38d5e62f1.js → vendor.min-c814d3c4b3f543c4cd5ef3aacd0fc645.js} +40 -36
- package/core/frontend/helpers/excerpt.js +7 -4
- package/core/frontend/helpers/get.js +4 -0
- package/core/frontend/helpers/match.js +12 -0
- package/core/frontend/helpers/prev_post.js +11 -1
- package/core/frontend/helpers/tiers.js +59 -0
- package/core/frontend/helpers/tpl/content-cta.hbs +1 -1
- package/core/frontend/services/routing/router-manager.js +1 -1
- package/core/frontend/web/site.js +10 -0
- package/core/server/api/canary/authentication.js +2 -0
- package/core/server/api/canary/index.js +8 -0
- package/core/server/api/canary/members.js +2 -1
- package/core/server/api/canary/products.js +3 -6
- package/core/server/api/canary/tiers-public.js +34 -0
- package/core/server/api/canary/tiers.js +120 -0
- package/core/server/api/canary/utils/serializers/input/index.js +4 -0
- package/core/server/api/canary/utils/serializers/input/tiers.js +36 -0
- package/core/server/api/canary/utils/serializers/output/email-posts.js +7 -1
- package/core/server/api/canary/utils/serializers/output/index.js +4 -0
- package/core/server/api/canary/utils/serializers/output/members.js +5 -0
- package/core/server/api/canary/utils/serializers/output/pages.js +9 -2
- package/core/server/api/canary/utils/serializers/output/posts.js +8 -2
- package/core/server/api/canary/utils/serializers/output/preview.js +7 -1
- package/core/server/api/canary/utils/serializers/output/products.js +3 -1
- package/core/server/api/canary/utils/serializers/output/tiers.js +212 -0
- package/core/server/api/canary/utils/serializers/output/utils/mapper.js +17 -7
- package/core/server/api/canary/utils/validators/input/index.js +4 -0
- package/core/server/api/canary/utils/validators/input/tiers.js +6 -0
- package/core/server/api/v2/settings.js +2 -1
- package/core/server/data/db/connection.js +3 -2
- package/core/server/data/migrations/init/1-create-tables.js +4 -1
- package/core/server/data/migrations/versions/3.29/01-remove-duplicate-subscriptions.js +2 -1
- package/core/server/data/migrations/versions/3.29/02-remove-duplicate-customers.js +2 -1
- package/core/server/data/migrations/versions/3.29/03-remove-orphaned-customers.js +2 -1
- package/core/server/data/migrations/versions/3.29/04-remove-orphaned-subscriptions.js +2 -1
- package/core/server/data/migrations/versions/3.29/05-add-member-constraints.js +3 -2
- package/core/server/data/migrations/versions/3.39/06-add-email-recipient-index.js +4 -3
- package/core/server/data/migrations/versions/4.0/14-remove-orphaned-stripe-records.js +2 -1
- package/core/server/data/migrations/versions/4.0/26-add-cascade-on-delete.js +2 -1
- package/core/server/data/migrations/versions/4.0/29-fix-foreign-key-for-members-stripe-customers-subscriptions.js +2 -1
- package/core/server/data/migrations/versions/4.1/02-add-unique-constraint-for-member-stripe-tables.js +2 -1
- package/core/server/data/migrations/versions/4.20/05-remove-not-null-constraint-from-portal-title.js +3 -2
- package/core/server/data/migrations/versions/4.33/2022-01-18-09-07-remove-duplicate-offer-redemptions.js +2 -2
- package/core/server/data/migrations/versions/4.35/2022-02-01-11-48-update-email-recipient-filter-column-type.js +2 -1
- package/core/server/data/migrations/versions/4.35/2022-02-01-12-03-update-recipient-filter-column-type.js +2 -1
- package/core/server/data/migrations/versions/4.37/2022-02-21-09-53-backfill-members-last-seen-at-column.js +32 -0
- package/core/server/data/migrations/versions/4.38/2022-03-01-08-46-add-visibility-to-tiers.js +11 -0
- package/core/server/data/migrations/versions/4.38/2022-03-03-16-12-add-visibility-to-tiers.js +8 -0
- package/core/server/data/migrations/versions/4.38/2022-03-03-16-17-drop-tiers-visible-column.js +7 -0
- package/core/server/data/schema/clients/index.js +1 -1
- package/core/server/data/schema/clients/mysql.js +4 -4
- package/core/server/data/schema/commands.js +61 -70
- package/core/server/data/schema/{default-settings.json → default-settings/default-settings.json} +0 -0
- package/core/server/data/schema/default-settings/index.js +6 -0
- package/core/server/data/schema/fixtures/fixtures.json +4 -2
- package/core/server/data/schema/schema.js +7 -0
- package/core/server/models/product.js +2 -1
- package/core/server/services/auth/api-key/admin.js +15 -6
- package/core/server/services/auth/setup.js +13 -1
- package/core/server/services/email-analytics/lib/event-processor.js +18 -1
- package/core/server/services/members/middleware.js +4 -1
- package/core/server/services/members/service.js +21 -8
- package/core/server/services/route-settings/index.js +1 -1
- package/core/server/web/admin/views/default-prod.html +4 -4
- package/core/server/web/admin/views/default.html +4 -4
- package/core/server/web/api/app.js +3 -0
- package/core/server/web/api/canary/admin/middleware.js +2 -0
- package/core/server/web/api/canary/admin/routes.js +7 -0
- package/core/server/web/api/canary/content/routes.js +1 -0
- package/core/server/web/members/app.js +1 -1
- package/core/server/web/shared/middleware/uncapitalise.js +2 -2
- package/core/shared/config/defaults.json +3 -2
- package/core/shared/config/overrides.json +1 -1
- package/core/shared/config/utils.js +5 -1
- package/core/shared/labs.js +4 -1
- package/package.json +62 -61
- package/yarn.lock +729 -614
- package/core/built/assets/ghost-dark-25e568b14d76f6754fa8279cceb265ba.css +0 -1
- package/core/built/assets/ghost.min-75ed7451ca633bae1b345eb57e2c28e0.css +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const logging = require('@tryghost/logging');
|
|
2
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
2
3
|
|
|
3
4
|
module.exports = {
|
|
4
5
|
config: {
|
|
@@ -6,7 +7,7 @@ module.exports = {
|
|
|
6
7
|
},
|
|
7
8
|
|
|
8
9
|
async up({transacting: knex}) {
|
|
9
|
-
if (knex
|
|
10
|
+
if (!DatabaseInfo.isMySQL(knex)) {
|
|
10
11
|
logging.warn('Skipping cleanup of duplicate subscriptions - database is not MySQL');
|
|
11
12
|
return;
|
|
12
13
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const logging = require('@tryghost/logging');
|
|
2
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
2
3
|
|
|
3
4
|
module.exports = {
|
|
4
5
|
config: {
|
|
@@ -6,7 +7,7 @@ module.exports = {
|
|
|
6
7
|
},
|
|
7
8
|
|
|
8
9
|
async up({transacting: knex}) {
|
|
9
|
-
if (knex
|
|
10
|
+
if (!DatabaseInfo.isMySQL(knex)) {
|
|
10
11
|
logging.warn('Skipping cleanup of duplicate customers - database is not MySQL');
|
|
11
12
|
return;
|
|
12
13
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const logging = require('@tryghost/logging');
|
|
2
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
2
3
|
|
|
3
4
|
module.exports = {
|
|
4
5
|
config: {
|
|
@@ -6,7 +7,7 @@ module.exports = {
|
|
|
6
7
|
},
|
|
7
8
|
|
|
8
9
|
async up({transacting: knex}) {
|
|
9
|
-
if (knex
|
|
10
|
+
if (!DatabaseInfo.isMySQL(knex)) {
|
|
10
11
|
logging.warn('Skipping cleanup of orphaned customers - database is not MySQL');
|
|
11
12
|
return;
|
|
12
13
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const logging = require('@tryghost/logging');
|
|
2
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
2
3
|
|
|
3
4
|
module.exports = {
|
|
4
5
|
config: {
|
|
@@ -6,7 +7,7 @@ module.exports = {
|
|
|
6
7
|
},
|
|
7
8
|
|
|
8
9
|
async up({transacting: knex}) {
|
|
9
|
-
if (knex
|
|
10
|
+
if (!DatabaseInfo.isMySQL(knex)) {
|
|
10
11
|
logging.warn('Skipping cleanup of orphaned subscriptions - database is not MySQL');
|
|
11
12
|
return;
|
|
12
13
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const logging = require('@tryghost/logging');
|
|
2
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
2
3
|
|
|
3
4
|
module.exports = {
|
|
4
5
|
config: {
|
|
@@ -6,7 +7,7 @@ module.exports = {
|
|
|
6
7
|
},
|
|
7
8
|
|
|
8
9
|
async up({transacting: knex}) {
|
|
9
|
-
if (knex
|
|
10
|
+
if (!DatabaseInfo.isMySQL(knex)) {
|
|
10
11
|
return logging.warn('Skipping member tables index creation - database is not MySQL');
|
|
11
12
|
}
|
|
12
13
|
|
|
@@ -91,7 +92,7 @@ module.exports = {
|
|
|
91
92
|
},
|
|
92
93
|
|
|
93
94
|
async down({transacting: knex}) {
|
|
94
|
-
if (knex
|
|
95
|
+
if (!DatabaseInfo.isMySQL(knex)) {
|
|
95
96
|
return logging.warn('Skipping member tables index removal - database is not MySQL');
|
|
96
97
|
}
|
|
97
98
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
const logging = require('@tryghost/logging');
|
|
2
2
|
const {createNonTransactionalMigration} = require('../../utils');
|
|
3
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
3
4
|
|
|
4
5
|
module.exports = createNonTransactionalMigration(
|
|
5
6
|
async function up(knex) {
|
|
6
7
|
let hasIndex = false;
|
|
7
8
|
|
|
8
|
-
if (knex
|
|
9
|
+
if (DatabaseInfo.isSQLite(knex)) {
|
|
9
10
|
const result = await knex.raw(`select * from sqlite_master where type = 'index' and tbl_name = 'email_recipients' and name = 'email_recipients_email_id_member_email_index'`);
|
|
10
11
|
hasIndex = result.length !== 0;
|
|
11
12
|
} else {
|
|
@@ -27,7 +28,7 @@ module.exports = createNonTransactionalMigration(
|
|
|
27
28
|
async function down(knex) {
|
|
28
29
|
let missingIndex = false;
|
|
29
30
|
|
|
30
|
-
if (knex
|
|
31
|
+
if (DatabaseInfo.isSQLite(knex)) {
|
|
31
32
|
const result = await knex.raw(`select * from sqlite_master where type = 'index' and tbl_name = 'email_recipients' and name = 'email_recipients_email_id_member_email_index'`);
|
|
32
33
|
missingIndex = result.length === 0;
|
|
33
34
|
} else {
|
|
@@ -42,7 +43,7 @@ module.exports = createNonTransactionalMigration(
|
|
|
42
43
|
|
|
43
44
|
logging.info('Dropping composite index on email_recipients for [email_id, member_email]');
|
|
44
45
|
|
|
45
|
-
if (knex
|
|
46
|
+
if (DatabaseInfo.isMySQL(knex)) {
|
|
46
47
|
await knex.schema.table('email_recipients', (table) => {
|
|
47
48
|
table.dropForeign('email_id');
|
|
48
49
|
table.dropIndex(['email_id', 'member_email']);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
const {createIrreversibleMigration} = require('../../utils');
|
|
2
2
|
const logging = require('@tryghost/logging');
|
|
3
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
3
4
|
|
|
4
5
|
module.exports = createIrreversibleMigration(async function up(connection) {
|
|
5
|
-
if (connection
|
|
6
|
+
if (DatabaseInfo.isMySQL(connection)) {
|
|
6
7
|
logging.info('Skipping removal of orphaned stripe records for MySQL');
|
|
7
8
|
return;
|
|
8
9
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
const logging = require('@tryghost/logging');
|
|
2
2
|
const {createIrreversibleMigration} = require('../../utils');
|
|
3
3
|
const {addForeign, dropForeign} = require('../../../schema/commands');
|
|
4
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
4
5
|
|
|
5
6
|
module.exports = createIrreversibleMigration(async (knex) => {
|
|
6
|
-
if (knex
|
|
7
|
+
if (!DatabaseInfo.isSQLite(knex)) {
|
|
7
8
|
return logging.warn('Skipping adding "on delete cascade" - database is not SQLite3');
|
|
8
9
|
}
|
|
9
10
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
const logging = require('@tryghost/logging');
|
|
2
2
|
const {createIrreversibleMigration} = require('../../utils');
|
|
3
3
|
const {addForeign, dropForeign} = require('../../../schema/commands');
|
|
4
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
4
5
|
|
|
5
6
|
module.exports = createIrreversibleMigration(async (knex) => {
|
|
6
|
-
if (knex
|
|
7
|
+
if (!DatabaseInfo.isSQLite(knex)) {
|
|
7
8
|
return logging.warn('Skipping fixing foreign key for members_stripe_customers_subscriptions - database is not SQLite3');
|
|
8
9
|
}
|
|
9
10
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const logging = require('@tryghost/logging');
|
|
2
2
|
const {createTransactionalMigration} = require('../../utils');
|
|
3
3
|
const {addUnique} = require('../../../schema/commands');
|
|
4
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
4
5
|
|
|
5
6
|
module.exports = createTransactionalMigration(
|
|
6
7
|
async function up(connection) {
|
|
7
|
-
if (connection
|
|
8
|
+
if (!DatabaseInfo.isSQLite(connection)) {
|
|
8
9
|
return logging.warn('Skipping adding unique constraint for members_stripe_customers_subscriptions and members_stripe_customers - database is not SQLite3');
|
|
9
10
|
}
|
|
10
11
|
|
package/core/server/data/migrations/versions/4.20/05-remove-not-null-constraint-from-portal-title.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const logging = require('@tryghost/logging');
|
|
2
2
|
const {createNonTransactionalMigration} = require('../../utils');
|
|
3
3
|
const {addUnique} = require('../../../schema/commands');
|
|
4
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
4
5
|
|
|
5
6
|
module.exports = createNonTransactionalMigration(
|
|
6
7
|
async function up(knex) {
|
|
@@ -14,7 +15,7 @@ module.exports = createNonTransactionalMigration(
|
|
|
14
15
|
table.string('portal_title', 191).nullable();
|
|
15
16
|
});
|
|
16
17
|
|
|
17
|
-
if (knex
|
|
18
|
+
if (DatabaseInfo.isSQLite(knex)) {
|
|
18
19
|
// eslint-disable-next-line no-restricted-syntax
|
|
19
20
|
for (const column of ['name', 'code', 'stripe_coupon_id']) {
|
|
20
21
|
await addUnique('offers', column, knex);
|
|
@@ -32,7 +33,7 @@ module.exports = createNonTransactionalMigration(
|
|
|
32
33
|
table.string('portal_title', 191).notNullable();
|
|
33
34
|
});
|
|
34
35
|
|
|
35
|
-
if (knex
|
|
36
|
+
if (DatabaseInfo.isSQLite(knex)) {
|
|
36
37
|
// eslint-disable-next-line no-restricted-syntax
|
|
37
38
|
for (const column of ['name', 'code', 'stripe_coupon_id']) {
|
|
38
39
|
await addUnique('offers', column, knex);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const logging = require('@tryghost/logging');
|
|
2
|
-
|
|
3
2
|
const {createTransactionalMigration} = require('../../utils');
|
|
3
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
4
4
|
|
|
5
5
|
module.exports = createTransactionalMigration(
|
|
6
6
|
async function up(knex) {
|
|
7
|
-
if (knex
|
|
7
|
+
if (!DatabaseInfo.isMySQL(knex)) {
|
|
8
8
|
logging.warn('Skipping cleanup of duplicate offer redemptions - database is not MySQL');
|
|
9
9
|
return;
|
|
10
10
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
const logging = require('@tryghost/logging');
|
|
2
2
|
const {createNonTransactionalMigration} = require('../../utils');
|
|
3
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
3
4
|
|
|
4
5
|
module.exports = createNonTransactionalMigration(
|
|
5
6
|
async function up(knex) {
|
|
6
|
-
if (knex
|
|
7
|
+
if (DatabaseInfo.isSQLite(knex)) {
|
|
7
8
|
logging.warn('Skipping migration for SQLite3');
|
|
8
9
|
return;
|
|
9
10
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
const logging = require('@tryghost/logging');
|
|
2
2
|
const {createNonTransactionalMigration} = require('../../utils');
|
|
3
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
3
4
|
|
|
4
5
|
module.exports = createNonTransactionalMigration(
|
|
5
6
|
async function up(knex) {
|
|
6
|
-
if (knex
|
|
7
|
+
if (DatabaseInfo.isSQLite(knex)) {
|
|
7
8
|
logging.warn('Skipping migration for SQLite3');
|
|
8
9
|
return;
|
|
9
10
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const logging = require('@tryghost/logging');
|
|
2
|
+
const {createTransactionalMigration} = require('../../utils');
|
|
3
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
4
|
+
|
|
5
|
+
module.exports = createTransactionalMigration(
|
|
6
|
+
async function up(knex) {
|
|
7
|
+
if (DatabaseInfo.isSQLite(knex)) {
|
|
8
|
+
logging.warn('Skipping migration for SQLite3');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
logging.info('Backfilling the members.last_seen_at column from members_login_events.');
|
|
12
|
+
await knex.raw(`
|
|
13
|
+
UPDATE members
|
|
14
|
+
INNER JOIN (SELECT member_id as id, MAX(created_at) as last_seen_at
|
|
15
|
+
FROM members_login_events
|
|
16
|
+
GROUP BY member_id) as logins ON logins.id = members.id
|
|
17
|
+
SET
|
|
18
|
+
members.last_seen_at = logins.last_seen_at
|
|
19
|
+
WHERE
|
|
20
|
+
members.last_seen_at IS NULL
|
|
21
|
+
OR members.last_seen_at < logins.last_seen_at
|
|
22
|
+
`);
|
|
23
|
+
},
|
|
24
|
+
async function down(knex) {
|
|
25
|
+
if (DatabaseInfo.isSQLite(knex)) {
|
|
26
|
+
logging.warn('Skipping migration for SQLite3');
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
logging.info('Rolling back the backfilling of the members.last_seen_at column from members_login_events.');
|
|
30
|
+
await knex('members').update({last_seen_at: null});
|
|
31
|
+
}
|
|
32
|
+
);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const {createAddColumnMigration} = require('../../utils');
|
|
2
|
+
|
|
3
|
+
module.exports = createAddColumnMigration('products', 'visible', {
|
|
4
|
+
type: 'boolean',
|
|
5
|
+
nullable: false,
|
|
6
|
+
defaultTo: false
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
module.exports.up = async () => {
|
|
10
|
+
// noop - column will be replaced with `visibility` instead
|
|
11
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
2
|
const db = require('../../../data/db');
|
|
3
3
|
|
|
4
|
-
const doRawAndFlatten = function doRaw(query, transaction, flattenFn) {
|
|
5
|
-
return
|
|
4
|
+
const doRawAndFlatten = function doRaw(query, transaction = db.knex, flattenFn) {
|
|
5
|
+
return transaction.raw(query).then(function (response) {
|
|
6
6
|
return _.flatten(flattenFn(response));
|
|
7
7
|
});
|
|
8
8
|
};
|
|
@@ -31,8 +31,8 @@ const getColumns = function getColumns(table, transaction) {
|
|
|
31
31
|
// a wrong datatype in schema.js some installations using mysql could have been created using the
|
|
32
32
|
// data type text instead of mediumtext.
|
|
33
33
|
// For details see: https://github.com/TryGhost/Ghost/issues/1947
|
|
34
|
-
const checkPostTable = function checkPostTable(transaction) {
|
|
35
|
-
return
|
|
34
|
+
const checkPostTable = function checkPostTable(transaction = db.knex) {
|
|
35
|
+
return transaction.raw('SHOW FIELDS FROM posts where Field ="html" OR Field = "markdown"').then(function (response) {
|
|
36
36
|
return _.flatten(_.map(response[0], function (entry) {
|
|
37
37
|
if (entry.Type.toLowerCase() !== 'mediumtext') {
|
|
38
38
|
return (transaction || db.knex).raw('ALTER TABLE posts MODIFY ' + entry.Field + ' MEDIUMTEXT');
|
|
@@ -4,6 +4,7 @@ const logging = require('@tryghost/logging');
|
|
|
4
4
|
const errors = require('@tryghost/errors');
|
|
5
5
|
const tpl = require('@tryghost/tpl');
|
|
6
6
|
const db = require('../db');
|
|
7
|
+
const DatabaseInfo = require('@tryghost/database-info');
|
|
7
8
|
const schema = require('./schema');
|
|
8
9
|
const clients = require('./clients');
|
|
9
10
|
|
|
@@ -58,14 +59,14 @@ function addTableColumn(tableName, table, columnName, columnSpec = schema[tableN
|
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
function addColumn(tableName, column, transaction, columnSpec) {
|
|
62
|
-
return
|
|
62
|
+
function addColumn(tableName, column, transaction = db.knex, columnSpec) {
|
|
63
|
+
return transaction.schema.table(tableName, function (table) {
|
|
63
64
|
addTableColumn(tableName, table, column, columnSpec);
|
|
64
65
|
});
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
function dropColumn(tableName, column, transaction) {
|
|
68
|
-
return
|
|
68
|
+
function dropColumn(tableName, column, transaction = db.knex) {
|
|
69
|
+
return transaction.schema.table(tableName, function (table) {
|
|
69
70
|
table.dropColumn(column);
|
|
70
71
|
});
|
|
71
72
|
}
|
|
@@ -77,11 +78,11 @@ function dropColumn(tableName, column, transaction) {
|
|
|
77
78
|
* @param {string|[string]} columns - column(s) to form unique constraint with
|
|
78
79
|
* @param {import('knex')} transaction - connection object containing knex reference
|
|
79
80
|
*/
|
|
80
|
-
async function addUnique(tableName, columns, transaction) {
|
|
81
|
+
async function addUnique(tableName, columns, transaction = db.knex) {
|
|
81
82
|
try {
|
|
82
83
|
logging.info(`Adding unique constraint for: ${columns} in table ${tableName}`);
|
|
83
84
|
|
|
84
|
-
return await
|
|
85
|
+
return await transaction.schema.table(tableName, function (table) {
|
|
85
86
|
table.unique(columns);
|
|
86
87
|
});
|
|
87
88
|
} catch (err) {
|
|
@@ -104,11 +105,11 @@ async function addUnique(tableName, columns, transaction) {
|
|
|
104
105
|
* @param {string|[string]} columns - column(s) unique constraint was formed
|
|
105
106
|
* @param {import('knex')} transaction - connection object containing knex reference
|
|
106
107
|
*/
|
|
107
|
-
async function dropUnique(tableName, columns, transaction) {
|
|
108
|
+
async function dropUnique(tableName, columns, transaction = db.knex) {
|
|
108
109
|
try {
|
|
109
110
|
logging.info(`Dropping unique constraint for: ${columns} in table: ${tableName}`);
|
|
110
111
|
|
|
111
|
-
return await
|
|
112
|
+
return await transaction.schema.table(tableName, function (table) {
|
|
112
113
|
table.dropUnique(columns);
|
|
113
114
|
});
|
|
114
115
|
} catch (err) {
|
|
@@ -134,17 +135,14 @@ async function dropUnique(tableName, columns, transaction) {
|
|
|
134
135
|
* @param {string} configuration.toColumn - column of the table to point the foreign key to
|
|
135
136
|
* @param {import('knex')} configuration.transaction - connection object containing knex reference
|
|
136
137
|
*/
|
|
137
|
-
async function hasForeignSQLite({fromTable, fromColumn, toTable, toColumn, transaction}) {
|
|
138
|
-
|
|
139
|
-
const client = knex.client.config.client;
|
|
140
|
-
|
|
141
|
-
if (client !== 'sqlite3') {
|
|
138
|
+
async function hasForeignSQLite({fromTable, fromColumn, toTable, toColumn, transaction = db.knex}) {
|
|
139
|
+
if (!DatabaseInfo.isSQLite(transaction)) {
|
|
142
140
|
throw new errors.InternalServerError({
|
|
143
141
|
message: tpl(messages.hasForeignSQLite3)
|
|
144
142
|
});
|
|
145
143
|
}
|
|
146
144
|
|
|
147
|
-
const foreignKeys = await
|
|
145
|
+
const foreignKeys = await transaction.raw(`PRAGMA foreign_key_list('${fromTable}');`);
|
|
148
146
|
|
|
149
147
|
const hasForeignKey = foreignKeys.some(foreignKey => foreignKey.table === toTable && foreignKey.from === fromColumn && foreignKey.to === toColumn);
|
|
150
148
|
|
|
@@ -162,9 +160,8 @@ async function hasForeignSQLite({fromTable, fromColumn, toTable, toColumn, trans
|
|
|
162
160
|
* @param {Boolean} configuration.cascadeDelete - adds the "on delete cascade" option if true
|
|
163
161
|
* @param {import('knex')} configuration.transaction - connection object containing knex reference
|
|
164
162
|
*/
|
|
165
|
-
async function addForeign({fromTable, fromColumn, toTable, toColumn, cascadeDelete = false, transaction}) {
|
|
166
|
-
|
|
167
|
-
if (isSQLite) {
|
|
163
|
+
async function addForeign({fromTable, fromColumn, toTable, toColumn, cascadeDelete = false, transaction = db.knex}) {
|
|
164
|
+
if (DatabaseInfo.isSQLite(transaction)) {
|
|
168
165
|
const foreignKeyExists = await hasForeignSQLite({fromTable, fromColumn, toTable, toColumn, transaction});
|
|
169
166
|
if (foreignKeyExists) {
|
|
170
167
|
logging.warn(`Skipped adding foreign key from ${fromTable}.${fromColumn} to ${toTable}.${toColumn} - foreign key already exists`);
|
|
@@ -176,14 +173,14 @@ async function addForeign({fromTable, fromColumn, toTable, toColumn, cascadeDele
|
|
|
176
173
|
|
|
177
174
|
//disable and re-enable foreign key checks on sqlite because of https://github.com/knex/knex/issues/4155
|
|
178
175
|
let foreignKeysEnabled;
|
|
179
|
-
if (isSQLite) {
|
|
176
|
+
if (DatabaseInfo.isSQLite(transaction)) {
|
|
180
177
|
foreignKeysEnabled = await db.knex.raw('PRAGMA foreign_keys;');
|
|
181
178
|
if (foreignKeysEnabled[0].foreign_keys) {
|
|
182
179
|
await db.knex.raw('PRAGMA foreign_keys = OFF;');
|
|
183
180
|
}
|
|
184
181
|
}
|
|
185
182
|
|
|
186
|
-
await
|
|
183
|
+
await transaction.schema.table(fromTable, function (table) {
|
|
187
184
|
if (cascadeDelete) {
|
|
188
185
|
table.foreign(fromColumn).references(`${toTable}.${toColumn}`).onDelete('CASCADE');
|
|
189
186
|
} else {
|
|
@@ -191,13 +188,13 @@ async function addForeign({fromTable, fromColumn, toTable, toColumn, cascadeDele
|
|
|
191
188
|
}
|
|
192
189
|
});
|
|
193
190
|
|
|
194
|
-
if (isSQLite) {
|
|
191
|
+
if (DatabaseInfo.isSQLite(transaction)) {
|
|
195
192
|
if (foreignKeysEnabled[0].foreign_keys) {
|
|
196
193
|
await db.knex.raw('PRAGMA foreign_keys = ON;');
|
|
197
194
|
}
|
|
198
195
|
}
|
|
199
196
|
} catch (err) {
|
|
200
|
-
if (err.code === 'ER_DUP_KEY') {
|
|
197
|
+
if (err.code === 'ER_DUP_KEY' || err.code === 'ER_FK_DUP_KEY' || err.code === 'ER_FK_DUP_NAME') {
|
|
201
198
|
logging.warn(`Skipped adding foreign key from ${fromTable}.${fromColumn} to ${toTable}.${toColumn} - foreign key already exists`);
|
|
202
199
|
return;
|
|
203
200
|
}
|
|
@@ -215,9 +212,8 @@ async function addForeign({fromTable, fromColumn, toTable, toColumn, cascadeDele
|
|
|
215
212
|
* @param {string} configuration.toColumn - column of the table to point the foreign key to
|
|
216
213
|
* @param {import('knex')} configuration.transaction - connection object containing knex reference
|
|
217
214
|
*/
|
|
218
|
-
async function dropForeign({fromTable, fromColumn, toTable, toColumn, transaction}) {
|
|
219
|
-
|
|
220
|
-
if (isSQLite) {
|
|
215
|
+
async function dropForeign({fromTable, fromColumn, toTable, toColumn, transaction = db.knex}) {
|
|
216
|
+
if (DatabaseInfo.isSQLite(transaction)) {
|
|
221
217
|
const foreignKeyExists = await hasForeignSQLite({fromTable, fromColumn, toTable, toColumn, transaction});
|
|
222
218
|
if (!foreignKeyExists) {
|
|
223
219
|
logging.warn(`Skipped dropping foreign key from ${fromTable}.${fromColumn} to ${toTable}.${toColumn} - foreign key does not exist`);
|
|
@@ -229,18 +225,18 @@ async function dropForeign({fromTable, fromColumn, toTable, toColumn, transactio
|
|
|
229
225
|
|
|
230
226
|
//disable and re-enable foreign key checks on sqlite because of https://github.com/knex/knex/issues/4155
|
|
231
227
|
let foreignKeysEnabled;
|
|
232
|
-
if (isSQLite) {
|
|
228
|
+
if (DatabaseInfo.isSQLite(transaction)) {
|
|
233
229
|
foreignKeysEnabled = await db.knex.raw('PRAGMA foreign_keys;');
|
|
234
230
|
if (foreignKeysEnabled[0].foreign_keys) {
|
|
235
231
|
await db.knex.raw('PRAGMA foreign_keys = OFF;');
|
|
236
232
|
}
|
|
237
233
|
}
|
|
238
234
|
|
|
239
|
-
await
|
|
235
|
+
await transaction.schema.table(fromTable, function (table) {
|
|
240
236
|
table.dropForeign(fromColumn);
|
|
241
237
|
});
|
|
242
238
|
|
|
243
|
-
if (isSQLite) {
|
|
239
|
+
if (DatabaseInfo.isSQLite(transaction)) {
|
|
244
240
|
if (foreignKeysEnabled[0].foreign_keys) {
|
|
245
241
|
await db.knex.raw('PRAGMA foreign_keys = ON;');
|
|
246
242
|
}
|
|
@@ -260,17 +256,14 @@ async function dropForeign({fromTable, fromColumn, toTable, toColumn, transactio
|
|
|
260
256
|
* @param {string} tableName - name of the table to check primary key constraint on
|
|
261
257
|
* @param {import('knex')} transaction - connection object containing knex reference
|
|
262
258
|
*/
|
|
263
|
-
async function hasPrimaryKeySQLite(tableName, transaction) {
|
|
264
|
-
|
|
265
|
-
const client = knex.client.config.client;
|
|
266
|
-
|
|
267
|
-
if (client !== 'sqlite3') {
|
|
259
|
+
async function hasPrimaryKeySQLite(tableName, transaction = db.knex) {
|
|
260
|
+
if (!DatabaseInfo.isSQLite(transaction)){
|
|
268
261
|
throw new errors.InternalServerError({
|
|
269
262
|
message: tpl(messages.hasPrimaryKeySQLiteError)
|
|
270
263
|
});
|
|
271
264
|
}
|
|
272
265
|
|
|
273
|
-
const rawConstraints = await
|
|
266
|
+
const rawConstraints = await transaction.raw(`PRAGMA index_list('${tableName}');`);
|
|
274
267
|
const tablePrimaryKey = rawConstraints.find(c => c.origin === 'pk');
|
|
275
268
|
|
|
276
269
|
return tablePrimaryKey;
|
|
@@ -283,9 +276,8 @@ async function hasPrimaryKeySQLite(tableName, transaction) {
|
|
|
283
276
|
* @param {string|[string]} columns - column(s) to form primary key constraint with
|
|
284
277
|
* @param {import('knex')} transaction - connection object containing knex reference
|
|
285
278
|
*/
|
|
286
|
-
async function addPrimaryKey(tableName, columns, transaction) {
|
|
287
|
-
|
|
288
|
-
if (isSQLite) {
|
|
279
|
+
async function addPrimaryKey(tableName, columns, transaction = db.knex) {
|
|
280
|
+
if (DatabaseInfo.isSQLite(transaction)) {
|
|
289
281
|
const primaryKeyExists = await hasPrimaryKeySQLite(tableName, transaction);
|
|
290
282
|
if (primaryKeyExists) {
|
|
291
283
|
logging.warn(`Primary key constraint for: ${columns} already exists for table: ${tableName}`);
|
|
@@ -294,7 +286,7 @@ async function addPrimaryKey(tableName, columns, transaction) {
|
|
|
294
286
|
}
|
|
295
287
|
try {
|
|
296
288
|
logging.info(`Adding primary key constraint for: ${columns} in table ${tableName}`);
|
|
297
|
-
return await
|
|
289
|
+
return await transaction.schema.table(tableName, function (table) {
|
|
298
290
|
table.primary(columns);
|
|
299
291
|
});
|
|
300
292
|
} catch (err) {
|
|
@@ -307,37 +299,36 @@ async function addPrimaryKey(tableName, columns, transaction) {
|
|
|
307
299
|
}
|
|
308
300
|
|
|
309
301
|
/**
|
|
310
|
-
*
|
|
311
|
-
*
|
|
302
|
+
* Adds a table according to the provided spec, or falls back to the current schema
|
|
303
|
+
*
|
|
304
|
+
* NOTE: this function does NOT check if the table already exists - use the migration
|
|
305
|
+
* utils if you want that
|
|
306
|
+
*
|
|
307
|
+
* @param {String} table - name of the table to create
|
|
308
|
+
* @param {import('knex').Transaction} transaction - connection to the DB
|
|
309
|
+
* @param {Object} [tableSpec] - table schema to generate table with
|
|
312
310
|
*/
|
|
313
|
-
function createTable(table, transaction, tableSpec = schema[table]) {
|
|
314
|
-
return
|
|
315
|
-
.
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
tableSpec['@@INDEXES@@'].forEach(index => t.index(index));
|
|
327
|
-
}
|
|
328
|
-
if (tableSpec['@@UNIQUE_CONSTRAINTS@@']) {
|
|
329
|
-
tableSpec['@@UNIQUE_CONSTRAINTS@@'].forEach(unique => t.unique(unique));
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
});
|
|
311
|
+
function createTable(table, transaction = db.knex, tableSpec = schema[table]) {
|
|
312
|
+
return transaction.schema.createTable(table, function (t) {
|
|
313
|
+
Object.keys(tableSpec)
|
|
314
|
+
.filter(column => !(column.startsWith('@@')))
|
|
315
|
+
.forEach(column => addTableColumn(table, t, column, tableSpec[column]));
|
|
316
|
+
|
|
317
|
+
if (tableSpec['@@INDEXES@@']) {
|
|
318
|
+
tableSpec['@@INDEXES@@'].forEach(index => t.index(index));
|
|
319
|
+
}
|
|
320
|
+
if (tableSpec['@@UNIQUE_CONSTRAINTS@@']) {
|
|
321
|
+
tableSpec['@@UNIQUE_CONSTRAINTS@@'].forEach(unique => t.unique(unique));
|
|
322
|
+
}
|
|
323
|
+
});
|
|
333
324
|
}
|
|
334
325
|
|
|
335
|
-
function deleteTable(table, transaction) {
|
|
336
|
-
return
|
|
326
|
+
function deleteTable(table, transaction = db.knex) {
|
|
327
|
+
return transaction.schema.dropTableIfExists(table);
|
|
337
328
|
}
|
|
338
329
|
|
|
339
|
-
function getTables(transaction) {
|
|
340
|
-
const client =
|
|
330
|
+
function getTables(transaction = db.knex) {
|
|
331
|
+
const client = transaction.client.config.client;
|
|
341
332
|
|
|
342
333
|
if (_.includes(_.keys(clients), client)) {
|
|
343
334
|
return clients[client].getTables(transaction);
|
|
@@ -346,8 +337,8 @@ function getTables(transaction) {
|
|
|
346
337
|
return Promise.reject(tpl(messages.noSupportForDatabase, {client: client}));
|
|
347
338
|
}
|
|
348
339
|
|
|
349
|
-
function getIndexes(table, transaction) {
|
|
350
|
-
const client =
|
|
340
|
+
function getIndexes(table, transaction = db.knex) {
|
|
341
|
+
const client = transaction.client.config.client;
|
|
351
342
|
|
|
352
343
|
if (_.includes(_.keys(clients), client)) {
|
|
353
344
|
return clients[client].getIndexes(table, transaction);
|
|
@@ -356,8 +347,8 @@ function getIndexes(table, transaction) {
|
|
|
356
347
|
return Promise.reject(tpl(messages.noSupportForDatabase, {client: client}));
|
|
357
348
|
}
|
|
358
349
|
|
|
359
|
-
function getColumns(table, transaction) {
|
|
360
|
-
const client =
|
|
350
|
+
function getColumns(table, transaction = db.knex) {
|
|
351
|
+
const client = transaction.client.config.client;
|
|
361
352
|
|
|
362
353
|
if (_.includes(_.keys(clients), client)) {
|
|
363
354
|
return clients[client].getColumns(table);
|
|
@@ -366,10 +357,10 @@ function getColumns(table, transaction) {
|
|
|
366
357
|
return Promise.reject(tpl(messages.noSupportForDatabase, {client: client}));
|
|
367
358
|
}
|
|
368
359
|
|
|
369
|
-
function checkTables(transaction) {
|
|
370
|
-
const client =
|
|
360
|
+
function checkTables(transaction = db.knex) {
|
|
361
|
+
const client = transaction.client.config.client;
|
|
371
362
|
|
|
372
|
-
if (
|
|
363
|
+
if (DatabaseInfo.isMySQL(transaction)) {
|
|
373
364
|
return clients[client].checkPostTable();
|
|
374
365
|
}
|
|
375
366
|
}
|
package/core/server/data/schema/{default-settings.json → default-settings/default-settings.json}
RENAMED
|
File without changes
|