ghost 5.19.3 → 5.21.0
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/components/tryghost-adapter-manager-5.21.0.tgz +0 -0
- package/components/{tryghost-api-framework-5.19.3.tgz → tryghost-api-framework-5.21.0.tgz} +0 -0
- package/components/tryghost-api-version-compatibility-service-5.21.0.tgz +0 -0
- package/components/tryghost-audience-feedback-5.21.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.21.0.tgz +0 -0
- package/components/tryghost-constants-5.21.0.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-5.21.0.tgz +0 -0
- package/components/tryghost-data-generator-5.21.0.tgz +0 -0
- package/components/tryghost-domain-events-5.21.0.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.21.0.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.21.0.tgz +0 -0
- package/components/tryghost-email-content-generator-5.21.0.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.21.0.tgz +0 -0
- package/components/tryghost-extract-api-key-5.21.0.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.21.0.tgz +0 -0
- package/components/{tryghost-job-manager-5.19.3.tgz → tryghost-job-manager-5.21.0.tgz} +0 -0
- package/components/tryghost-link-redirects-5.21.0.tgz +0 -0
- package/components/tryghost-link-replacer-5.21.0.tgz +0 -0
- package/components/tryghost-link-tracking-5.21.0.tgz +0 -0
- package/components/tryghost-magic-link-5.21.0.tgz +0 -0
- package/components/tryghost-mailgun-client-5.21.0.tgz +0 -0
- package/components/tryghost-member-analytics-service-5.21.0.tgz +0 -0
- package/components/tryghost-member-attribution-5.21.0.tgz +0 -0
- package/components/tryghost-member-events-5.21.0.tgz +0 -0
- package/components/tryghost-members-analytics-ingress-5.21.0.tgz +0 -0
- package/components/tryghost-members-api-5.21.0.tgz +0 -0
- package/components/tryghost-members-csv-5.21.0.tgz +0 -0
- package/components/tryghost-members-events-service-5.21.0.tgz +0 -0
- package/components/tryghost-members-importer-5.21.0.tgz +0 -0
- package/components/tryghost-members-offers-5.21.0.tgz +0 -0
- package/components/tryghost-members-payments-5.21.0.tgz +0 -0
- package/components/{tryghost-members-ssr-5.19.3.tgz → tryghost-members-ssr-5.21.0.tgz} +0 -0
- package/components/tryghost-members-stripe-service-5.21.0.tgz +0 -0
- package/components/tryghost-minifier-5.21.0.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.21.0.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.21.0.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.21.0.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.21.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.21.0.tgz +0 -0
- package/components/tryghost-mw-vhost-5.21.0.tgz +0 -0
- package/components/tryghost-oembed-service-5.21.0.tgz +0 -0
- package/components/{tryghost-package-json-5.19.3.tgz → tryghost-package-json-5.21.0.tgz} +0 -0
- package/components/tryghost-referrers-5.21.0.tgz +0 -0
- package/components/tryghost-security-5.21.0.tgz +0 -0
- package/components/tryghost-session-service-5.21.0.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.21.0.tgz +0 -0
- package/components/tryghost-staff-service-5.21.0.tgz +0 -0
- package/components/tryghost-stats-service-5.21.0.tgz +0 -0
- package/components/tryghost-tiers-5.21.0.tgz +0 -0
- package/components/{tryghost-update-check-service-5.19.3.tgz → tryghost-update-check-service-5.21.0.tgz} +0 -0
- package/components/tryghost-verification-trigger-5.21.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.21.0.tgz +0 -0
- package/core/boot.js +2 -0
- package/core/built/admin/assets/{chunk.143.c035c61595ed02eee886.js → chunk.143.9cddfa7bd1a8b9cf3d4b.js} +7 -7
- package/core/built/admin/assets/{chunk.178.998dfbcebcec635146b1.js → chunk.178.6de14cfdb28df721b66e.js} +4 -4
- package/core/built/admin/assets/{chunk.613.f1d519ad47e7f9024263.js → chunk.613.695f31829550fb00d43c.js} +352 -421
- package/core/built/admin/assets/{chunk.613.f1d519ad47e7f9024263.js.LICENSE.txt → chunk.613.695f31829550fb00d43c.js.LICENSE.txt} +0 -0
- package/core/built/admin/assets/{ghost-5ce6f5a730c83c91fc258b12c537ea35.js → ghost-192fee3b46a193df1e65c49a67a7d694.js} +2866 -2707
- package/core/built/admin/assets/ghost-9873519a8ad69b5b23284f0a9e050bc6.css +1 -0
- package/core/built/admin/assets/ghost-dark-190bdce42b125c3d4be930bd7599b442.css +1 -0
- package/core/built/admin/assets/{vendor-5c7d7063620bec13668c4370145cd4b4.js → vendor-26cca1d4d56660dc6e915a12ccc3b330.js} +1079 -1032
- package/core/built/admin/index.html +7 -7
- package/core/cli/generate-data.js +51 -0
- package/core/frontend/helpers/ghost_head.js +1 -1
- package/core/server/api/endpoints/links.js +34 -1
- package/core/server/api/endpoints/members.js +1 -4
- package/core/server/api/endpoints/posts-public.js +1 -1
- package/core/server/api/endpoints/posts.js +2 -1
- package/core/server/api/endpoints/tiers-public.js +2 -14
- package/core/server/api/endpoints/tiers.js +5 -51
- package/core/server/api/endpoints/utils/serializers/input/posts.js +21 -1
- package/core/server/api/endpoints/utils/serializers/input/settings.js +1 -0
- package/core/server/api/endpoints/utils/serializers/input/tiers.js +18 -27
- package/core/server/api/endpoints/utils/serializers/output/index.js +4 -0
- package/core/server/api/endpoints/utils/serializers/output/links.js +5 -0
- package/core/server/api/endpoints/utils/serializers/output/mappers/activity-feed-events.js +89 -15
- package/core/server/api/endpoints/utils/serializers/output/mappers/posts.js +20 -6
- package/core/server/api/endpoints/utils/serializers/output/mappers/snippets.js +2 -2
- package/core/server/api/endpoints/utils/serializers/output/members.js +6 -5
- package/core/server/api/endpoints/utils/serializers/output/tiers.js +15 -55
- package/core/server/data/db/backup.js +17 -10
- package/core/server/data/importer/importers/data/custom-theme-settings.js +81 -0
- package/core/server/data/importer/importers/data/data-importer.js +2 -0
- package/core/server/data/migrations/utils/permissions.js +35 -24
- package/core/server/data/migrations/versions/5.20/2022-10-18-05-39-drop-nullable-tier-id.js +3 -0
- package/core/server/data/migrations/versions/5.20/2022-10-18-10-13-add-ghost-subscription-id-column-to-mscs.js +10 -0
- package/core/server/data/migrations/versions/5.20/2022-10-19-11-17-add-link-browse-permissions.js +10 -0
- package/core/server/data/migrations/versions/5.20/2022-10-20-02-52-add-link-edit-permissions.js +10 -0
- package/core/server/data/migrations/versions/5.21/2022-10-24-07-23-disable-feedback-enabled.js +20 -0
- package/core/server/data/migrations/versions/5.21/2022-10-25-12-05-backfill-missed-products-columns.js +35 -0
- package/core/server/data/migrations/versions/5.21/2022-10-26-04-49-add-batch-id-members-created-events.js +7 -0
- package/core/server/data/migrations/versions/5.21/2022-10-26-04-49-add-batch-id-subscription-created-events.js +7 -0
- package/core/server/data/migrations/versions/5.21/2022-10-26-04-50-member-subscription-created-batch-id.js +72 -0
- package/core/server/data/migrations/versions/5.21/2022-10-26-09-32-add-feedback-enabled-column-to-emails.js +7 -0
- package/core/server/data/migrations/versions/5.21/2022-10-27-09-50-add-member-track-source-setting.js +8 -0
- package/core/server/data/schema/commands.js +107 -48
- package/core/server/data/schema/default-settings/default-settings.json +8 -0
- package/core/server/data/schema/fixtures/fixture-manager.js +16 -14
- package/core/server/data/schema/fixtures/fixtures.json +14 -2
- package/core/server/data/schema/schema.js +7 -3
- package/core/server/models/base/plugins/actions.js +1 -1
- package/core/server/models/base/plugins/crud.js +12 -0
- package/core/server/models/email-recipient.js +14 -0
- package/core/server/models/email.js +2 -5
- package/core/server/models/member-click-event.js +37 -0
- package/core/server/models/member-created-event.js +23 -0
- package/core/server/models/member-paid-subscription-event.js +19 -0
- package/core/server/models/member.js +6 -0
- package/core/server/models/post.js +33 -2
- package/core/server/models/redirect.js +1 -0
- package/core/server/models/subscription-created-event.js +7 -0
- package/core/server/services/audience-feedback/index.js +2 -0
- package/core/server/services/link-redirection/LinkRedirectRepository.js +16 -5
- package/core/server/services/link-tracking/PostLinkRepository.js +26 -2
- package/core/server/services/link-tracking/index.js +3 -1
- package/core/server/services/mega/feedback-buttons.js +87 -16
- package/core/server/services/mega/mega.js +1 -0
- package/core/server/services/mega/template.js +3 -0
- package/core/server/services/member-attribution/index.js +3 -1
- package/core/server/services/members/api.js +4 -1
- package/core/server/services/members/service.js +8 -1
- package/core/server/services/newsletters/index.js +3 -1
- package/core/server/services/newsletters/service.js +11 -1
- package/core/server/services/tiers/TierRepository.js +116 -0
- package/core/server/services/tiers/index.js +1 -0
- package/core/server/services/tiers/service.js +32 -0
- package/core/server/services/url/UrlGenerator.js +4 -2
- package/core/server/web/api/endpoints/admin/routes.js +1 -0
- package/core/shared/config/defaults.json +1 -1
- package/core/shared/labs.js +7 -8
- package/ghost.js +1 -0
- package/package.json +117 -113
- package/yarn.lock +1187 -1129
- package/components/tryghost-adapter-manager-5.19.3.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-5.19.3.tgz +0 -0
- package/components/tryghost-audience-feedback-5.19.3.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.19.3.tgz +0 -0
- package/components/tryghost-constants-5.19.3.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-5.19.3.tgz +0 -0
- package/components/tryghost-domain-events-5.19.3.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.19.3.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.19.3.tgz +0 -0
- package/components/tryghost-email-content-generator-5.19.3.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.19.3.tgz +0 -0
- package/components/tryghost-extract-api-key-5.19.3.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.19.3.tgz +0 -0
- package/components/tryghost-link-redirects-5.19.3.tgz +0 -0
- package/components/tryghost-link-replacer-5.19.3.tgz +0 -0
- package/components/tryghost-link-tracking-5.19.3.tgz +0 -0
- package/components/tryghost-magic-link-5.19.3.tgz +0 -0
- package/components/tryghost-mailgun-client-5.19.3.tgz +0 -0
- package/components/tryghost-member-analytics-service-5.19.3.tgz +0 -0
- package/components/tryghost-member-attribution-5.19.3.tgz +0 -0
- package/components/tryghost-member-events-5.19.3.tgz +0 -0
- package/components/tryghost-members-analytics-ingress-5.19.3.tgz +0 -0
- package/components/tryghost-members-api-5.19.3.tgz +0 -0
- package/components/tryghost-members-csv-5.19.3.tgz +0 -0
- package/components/tryghost-members-events-service-5.19.3.tgz +0 -0
- package/components/tryghost-members-importer-5.19.3.tgz +0 -0
- package/components/tryghost-members-offers-5.19.3.tgz +0 -0
- package/components/tryghost-members-payments-5.19.3.tgz +0 -0
- package/components/tryghost-members-stripe-service-5.19.3.tgz +0 -0
- package/components/tryghost-minifier-5.19.3.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.19.3.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.19.3.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.19.3.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.19.3.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.19.3.tgz +0 -0
- package/components/tryghost-mw-vhost-5.19.3.tgz +0 -0
- package/components/tryghost-oembed-service-5.19.3.tgz +0 -0
- package/components/tryghost-referrers-5.19.3.tgz +0 -0
- package/components/tryghost-security-5.19.3.tgz +0 -0
- package/components/tryghost-session-service-5.19.3.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.19.3.tgz +0 -0
- package/components/tryghost-staff-service-5.19.3.tgz +0 -0
- package/components/tryghost-stats-service-5.19.3.tgz +0 -0
- package/components/tryghost-verification-trigger-5.19.3.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.19.3.tgz +0 -0
- package/core/built/admin/assets/ghost-982146a4ada3a5af1981d1919ae01d08.css +0 -1
- package/core/built/admin/assets/ghost-dark-41929e4857de411a23597a9de49a4e4f.css +0 -1
|
@@ -14,20 +14,26 @@ const messages = {
|
|
|
14
14
|
noSupportForDatabase: 'No support for database client {client}'
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} tableName
|
|
19
|
+
* @param {import('knex').knex.TableBuilder} tableBuilder
|
|
20
|
+
* @param {string} columnName
|
|
21
|
+
* @param {object} [columnSpec]
|
|
22
|
+
*/
|
|
23
|
+
function addTableColumn(tableName, tableBuilder, columnName, columnSpec = schema[tableName][columnName]) {
|
|
18
24
|
let column;
|
|
19
25
|
|
|
20
26
|
// creation distinguishes between text with fieldtype, string with maxlength and all others
|
|
21
27
|
if (columnSpec.type === 'text' && Object.prototype.hasOwnProperty.call(columnSpec, 'fieldtype')) {
|
|
22
|
-
column =
|
|
28
|
+
column = tableBuilder[columnSpec.type](columnName, columnSpec.fieldtype);
|
|
23
29
|
} else if (columnSpec.type === 'string') {
|
|
24
30
|
if (Object.prototype.hasOwnProperty.call(columnSpec, 'maxlength')) {
|
|
25
|
-
column =
|
|
31
|
+
column = tableBuilder[columnSpec.type](columnName, columnSpec.maxlength);
|
|
26
32
|
} else {
|
|
27
|
-
column =
|
|
33
|
+
column = tableBuilder[columnSpec.type](columnName, 191);
|
|
28
34
|
}
|
|
29
35
|
} else {
|
|
30
|
-
column =
|
|
36
|
+
column = tableBuilder[columnSpec.type](columnName);
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
if (Object.prototype.hasOwnProperty.call(columnSpec, 'nullable') && columnSpec.nullable === true) {
|
|
@@ -48,6 +54,10 @@ function addTableColumn(tableName, table, columnName, columnSpec = schema[tableN
|
|
|
48
54
|
// check if table exists?
|
|
49
55
|
column.references(columnSpec.references);
|
|
50
56
|
}
|
|
57
|
+
if (Object.prototype.hasOwnProperty.call(columnSpec, 'constraintName')) {
|
|
58
|
+
column.withKeyName(columnSpec.constraintName);
|
|
59
|
+
}
|
|
60
|
+
|
|
51
61
|
if (Object.prototype.hasOwnProperty.call(columnSpec, 'cascadeDelete') && columnSpec.cascadeDelete === true) {
|
|
52
62
|
column.onDelete('CASCADE');
|
|
53
63
|
} else if (Object.prototype.hasOwnProperty.call(columnSpec, 'setNullDelete') && columnSpec.setNullDelete === true) {
|
|
@@ -61,18 +71,34 @@ function addTableColumn(tableName, table, columnName, columnSpec = schema[tableN
|
|
|
61
71
|
}
|
|
62
72
|
}
|
|
63
73
|
|
|
74
|
+
/**
|
|
75
|
+
* @param {string} tableName
|
|
76
|
+
* @param {string} column
|
|
77
|
+
* @param {import('knex').Knex} [transaction]
|
|
78
|
+
*/
|
|
64
79
|
function setNullable(tableName, column, transaction = db.knex) {
|
|
65
80
|
return transaction.schema.table(tableName, function (table) {
|
|
66
81
|
table.setNullable(column);
|
|
67
82
|
});
|
|
68
83
|
}
|
|
69
84
|
|
|
85
|
+
/**
|
|
86
|
+
* @param {string} tableName
|
|
87
|
+
* @param {string} column
|
|
88
|
+
* @param {import('knex').Knex} [transaction]
|
|
89
|
+
*/
|
|
70
90
|
function dropNullable(tableName, column, transaction = db.knex) {
|
|
71
91
|
return transaction.schema.table(tableName, function (table) {
|
|
72
92
|
table.dropNullable(column);
|
|
73
93
|
});
|
|
74
94
|
}
|
|
75
95
|
|
|
96
|
+
/**
|
|
97
|
+
* @param {string} tableName
|
|
98
|
+
* @param {string} column
|
|
99
|
+
* @param {import('knex').Knex.Transaction} [transaction]
|
|
100
|
+
* @param {object} columnSpec
|
|
101
|
+
*/
|
|
76
102
|
async function addColumn(tableName, column, transaction = db.knex, columnSpec) {
|
|
77
103
|
const addColumnBuilder = transaction.schema.table(tableName, function (table) {
|
|
78
104
|
addTableColumn(tableName, table, column, columnSpec);
|
|
@@ -85,41 +111,51 @@ async function addColumn(tableName, column, transaction = db.knex, columnSpec) {
|
|
|
85
111
|
return;
|
|
86
112
|
}
|
|
87
113
|
|
|
88
|
-
|
|
114
|
+
for (const sqlQuery of addColumnBuilder.toSQL()) {
|
|
115
|
+
let sql = sqlQuery.sql;
|
|
89
116
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
117
|
+
if (DatabaseInfo.isMySQL(transaction)) {
|
|
118
|
+
// Guard against an ending semicolon
|
|
119
|
+
sql = sql.replace(/;\s*$/, '') + ', algorithm=copy';
|
|
120
|
+
}
|
|
94
121
|
|
|
95
|
-
|
|
122
|
+
await transaction.raw(sql);
|
|
123
|
+
}
|
|
96
124
|
}
|
|
97
125
|
|
|
126
|
+
/**
|
|
127
|
+
* @param {string} tableName
|
|
128
|
+
* @param {string} column
|
|
129
|
+
* @param {import('knex').Knex} [transaction]
|
|
130
|
+
* @param {object} [columnSpec]
|
|
131
|
+
*/
|
|
98
132
|
async function dropColumn(tableName, column, transaction = db.knex, columnSpec = {}) {
|
|
99
133
|
if (Object.prototype.hasOwnProperty.call(columnSpec, 'references')) {
|
|
100
134
|
const [toTable, toColumn] = columnSpec.references.split('.');
|
|
101
|
-
await dropForeign({fromTable: tableName, fromColumn: column, toTable, toColumn, transaction});
|
|
135
|
+
await dropForeign({fromTable: tableName, fromColumn: column, toTable, toColumn, constraintName: columnSpec.constraintName, transaction});
|
|
102
136
|
}
|
|
103
137
|
|
|
104
|
-
const
|
|
138
|
+
const dropColumnBuilder = transaction.schema.table(tableName, function (table) {
|
|
105
139
|
table.dropColumn(column);
|
|
106
140
|
});
|
|
107
141
|
|
|
108
142
|
// Use the default flow for SQLite because .toSQL() is tricky with SQLite when
|
|
109
143
|
// it does the table dance
|
|
110
144
|
if (DatabaseInfo.isSQLite(transaction)) {
|
|
111
|
-
await
|
|
145
|
+
await dropColumnBuilder;
|
|
112
146
|
return;
|
|
113
147
|
}
|
|
114
148
|
|
|
115
|
-
|
|
149
|
+
for (const sqlQuery of dropColumnBuilder.toSQL()) {
|
|
150
|
+
let sql = sqlQuery.sql;
|
|
116
151
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
152
|
+
if (DatabaseInfo.isMySQL(transaction)) {
|
|
153
|
+
// Guard against an ending semicolon
|
|
154
|
+
sql = sql.replace(/;\s*$/, '') + ', algorithm=copy';
|
|
155
|
+
}
|
|
121
156
|
|
|
122
|
-
|
|
157
|
+
await transaction.raw(sql);
|
|
158
|
+
}
|
|
123
159
|
}
|
|
124
160
|
|
|
125
161
|
/**
|
|
@@ -127,7 +163,7 @@ async function dropColumn(tableName, column, transaction = db.knex, columnSpec =
|
|
|
127
163
|
*
|
|
128
164
|
* @param {string} tableName - name of the table to add unique constraint to
|
|
129
165
|
* @param {string|string[]} columns - column(s) to form unique constraint with
|
|
130
|
-
* @param {import('knex')} transaction - connection object containing knex reference
|
|
166
|
+
* @param {import('knex').Knex} [transaction] - connection object containing knex reference
|
|
131
167
|
*/
|
|
132
168
|
async function addUnique(tableName, columns, transaction = db.knex) {
|
|
133
169
|
try {
|
|
@@ -154,7 +190,7 @@ async function addUnique(tableName, columns, transaction = db.knex) {
|
|
|
154
190
|
*
|
|
155
191
|
* @param {string} tableName - name of the table to drop unique constraint from
|
|
156
192
|
* @param {string|string[]} columns - column(s) unique constraint was formed
|
|
157
|
-
* @param {import('knex')} transaction - connection object containing knex reference
|
|
193
|
+
* @param {import('knex').Knex} transaction - connection object containing knex reference
|
|
158
194
|
*/
|
|
159
195
|
async function dropUnique(tableName, columns, transaction = db.knex) {
|
|
160
196
|
try {
|
|
@@ -184,7 +220,7 @@ async function dropUnique(tableName, columns, transaction = db.knex) {
|
|
|
184
220
|
* @param {string} configuration.fromColumn - column of the table to add the foreign key to
|
|
185
221
|
* @param {string} configuration.toTable - name of the table to point the foreign key to
|
|
186
222
|
* @param {string} configuration.toColumn - column of the table to point the foreign key to
|
|
187
|
-
* @param {import('knex')} configuration.transaction - connection object containing knex reference
|
|
223
|
+
* @param {import('knex').Knex} [configuration.transaction] - connection object containing knex reference
|
|
188
224
|
*/
|
|
189
225
|
async function hasForeignSQLite({fromTable, fromColumn, toTable, toColumn, transaction = db.knex}) {
|
|
190
226
|
if (!DatabaseInfo.isSQLite(transaction)) {
|
|
@@ -208,11 +244,12 @@ async function hasForeignSQLite({fromTable, fromColumn, toTable, toColumn, trans
|
|
|
208
244
|
* @param {string} configuration.fromColumn - column of the table to add the foreign key to
|
|
209
245
|
* @param {string} configuration.toTable - name of the table to point the foreign key to
|
|
210
246
|
* @param {string} configuration.toColumn - column of the table to point the foreign key to
|
|
247
|
+
* @param {string} [configuration.constraintName] - name of the FK to create
|
|
211
248
|
* @param {Boolean} [configuration.cascadeDelete] - adds the "on delete cascade" option if true
|
|
212
249
|
* @param {Boolean} [configuration.setNullDelete] - adds the "on delete SET NULL" option if true
|
|
213
|
-
* @param {import('knex')} configuration.transaction - connection object containing knex reference
|
|
250
|
+
* @param {import('knex').Knex} [configuration.transaction] - connection object containing knex reference
|
|
214
251
|
*/
|
|
215
|
-
async function addForeign({fromTable, fromColumn, toTable, toColumn, cascadeDelete = false, setNullDelete = false, transaction = db.knex}) {
|
|
252
|
+
async function addForeign({fromTable, fromColumn, toTable, toColumn, constraintName, cascadeDelete = false, setNullDelete = false, transaction = db.knex}) {
|
|
216
253
|
if (DatabaseInfo.isSQLite(transaction)) {
|
|
217
254
|
const foreignKeyExists = await hasForeignSQLite({fromTable, fromColumn, toTable, toColumn, transaction});
|
|
218
255
|
if (foreignKeyExists) {
|
|
@@ -233,12 +270,18 @@ async function addForeign({fromTable, fromColumn, toTable, toColumn, cascadeDele
|
|
|
233
270
|
}
|
|
234
271
|
|
|
235
272
|
await transaction.schema.table(fromTable, function (table) {
|
|
273
|
+
let fkBuilder;
|
|
274
|
+
|
|
236
275
|
if (cascadeDelete) {
|
|
237
|
-
table.foreign(fromColumn).references(`${toTable}.${toColumn}`).onDelete('CASCADE');
|
|
276
|
+
fkBuilder = table.foreign(fromColumn).references(`${toTable}.${toColumn}`).onDelete('CASCADE');
|
|
238
277
|
} else if (setNullDelete) {
|
|
239
|
-
table.foreign(fromColumn).references(`${toTable}.${toColumn}`).onDelete('SET NULL');
|
|
278
|
+
fkBuilder = table.foreign(fromColumn).references(`${toTable}.${toColumn}`).onDelete('SET NULL');
|
|
240
279
|
} else {
|
|
241
|
-
table.foreign(fromColumn).references(`${toTable}.${toColumn}`);
|
|
280
|
+
fkBuilder = table.foreign(fromColumn).references(`${toTable}.${toColumn}`);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (constraintName) {
|
|
284
|
+
fkBuilder.withKeyName(constraintName);
|
|
242
285
|
}
|
|
243
286
|
});
|
|
244
287
|
|
|
@@ -264,9 +307,10 @@ async function addForeign({fromTable, fromColumn, toTable, toColumn, cascadeDele
|
|
|
264
307
|
* @param {string} configuration.fromColumn - column of the table to add the foreign key to
|
|
265
308
|
* @param {string} configuration.toTable - name of the table to point the foreign key to
|
|
266
309
|
* @param {string} configuration.toColumn - column of the table to point the foreign key to
|
|
267
|
-
* @param {
|
|
310
|
+
* @param {string} [configuration.constraintName] - name of the FK to delete
|
|
311
|
+
* @param {import('knex').Knex} [configuration.transaction] - connection object containing knex reference
|
|
268
312
|
*/
|
|
269
|
-
async function dropForeign({fromTable, fromColumn, toTable, toColumn, transaction = db.knex}) {
|
|
313
|
+
async function dropForeign({fromTable, fromColumn, toTable, toColumn, constraintName, transaction = db.knex}) {
|
|
270
314
|
if (DatabaseInfo.isSQLite(transaction)) {
|
|
271
315
|
const foreignKeyExists = await hasForeignSQLite({fromTable, fromColumn, toTable, toColumn, transaction});
|
|
272
316
|
if (!foreignKeyExists) {
|
|
@@ -287,7 +331,7 @@ async function dropForeign({fromTable, fromColumn, toTable, toColumn, transactio
|
|
|
287
331
|
}
|
|
288
332
|
|
|
289
333
|
await transaction.schema.table(fromTable, function (table) {
|
|
290
|
-
table.dropForeign(fromColumn);
|
|
334
|
+
table.dropForeign(fromColumn, constraintName);
|
|
291
335
|
});
|
|
292
336
|
|
|
293
337
|
if (DatabaseInfo.isSQLite(transaction)) {
|
|
@@ -308,7 +352,7 @@ async function dropForeign({fromTable, fromColumn, toTable, toColumn, transactio
|
|
|
308
352
|
* Checks if primary key index exists in a table over the given columns.
|
|
309
353
|
*
|
|
310
354
|
* @param {string} tableName - name of the table to check primary key constraint on
|
|
311
|
-
* @param {import('knex')} transaction - connection object containing knex reference
|
|
355
|
+
* @param {import('knex').Knex} [transaction] - connection object containing knex reference
|
|
312
356
|
*/
|
|
313
357
|
async function hasPrimaryKeySQLite(tableName, transaction = db.knex) {
|
|
314
358
|
if (!DatabaseInfo.isSQLite(transaction)){
|
|
@@ -328,7 +372,7 @@ async function hasPrimaryKeySQLite(tableName, transaction = db.knex) {
|
|
|
328
372
|
*
|
|
329
373
|
* @param {string} tableName - name of the table to add primaykey constraint to
|
|
330
374
|
* @param {string|string[]} columns - column(s) to form primary key constraint with
|
|
331
|
-
* @param {import('knex')} transaction - connection object containing knex reference
|
|
375
|
+
* @param {import('knex').Knex} [transaction] - connection object containing knex reference
|
|
332
376
|
*/
|
|
333
377
|
async function addPrimaryKey(tableName, columns, transaction = db.knex) {
|
|
334
378
|
if (DatabaseInfo.isSQLite(transaction)) {
|
|
@@ -359,7 +403,7 @@ async function addPrimaryKey(tableName, columns, transaction = db.knex) {
|
|
|
359
403
|
* utils if you want that
|
|
360
404
|
*
|
|
361
405
|
* @param {String} table - name of the table to create
|
|
362
|
-
* @param {import('knex').
|
|
406
|
+
* @param {import('knex').Knex} [transaction] - connection to the DB
|
|
363
407
|
* @param {Object} [tableSpec] - table schema to generate table with
|
|
364
408
|
*/
|
|
365
409
|
function createTable(table, transaction = db.knex, tableSpec = schema[table]) {
|
|
@@ -377,10 +421,17 @@ function createTable(table, transaction = db.knex, tableSpec = schema[table]) {
|
|
|
377
421
|
});
|
|
378
422
|
}
|
|
379
423
|
|
|
424
|
+
/**
|
|
425
|
+
* @param {string} table
|
|
426
|
+
* @param {import('knex').Knex} [transaction] - connection to the DB
|
|
427
|
+
*/
|
|
380
428
|
function deleteTable(table, transaction = db.knex) {
|
|
381
429
|
return transaction.schema.dropTableIfExists(table);
|
|
382
430
|
}
|
|
383
431
|
|
|
432
|
+
/**
|
|
433
|
+
* @param {import('knex').Knex} [transaction] - connection to the DB
|
|
434
|
+
*/
|
|
384
435
|
function getTables(transaction = db.knex) {
|
|
385
436
|
const client = transaction.client.config.client;
|
|
386
437
|
|
|
@@ -391,6 +442,10 @@ function getTables(transaction = db.knex) {
|
|
|
391
442
|
return Promise.reject(tpl(messages.noSupportForDatabase, {client: client}));
|
|
392
443
|
}
|
|
393
444
|
|
|
445
|
+
/**
|
|
446
|
+
* @param {string} table
|
|
447
|
+
* @param {import('knex').Knex} [transaction] - connection to the DB
|
|
448
|
+
*/
|
|
394
449
|
function getIndexes(table, transaction = db.knex) {
|
|
395
450
|
const client = transaction.client.config.client;
|
|
396
451
|
|
|
@@ -401,6 +456,10 @@ function getIndexes(table, transaction = db.knex) {
|
|
|
401
456
|
return Promise.reject(tpl(messages.noSupportForDatabase, {client: client}));
|
|
402
457
|
}
|
|
403
458
|
|
|
459
|
+
/**
|
|
460
|
+
* @param {string} table
|
|
461
|
+
* @param {import('knex').Knex} [transaction] - connection to the DB
|
|
462
|
+
*/
|
|
404
463
|
function getColumns(table, transaction = db.knex) {
|
|
405
464
|
const client = transaction.client.config.client;
|
|
406
465
|
|
|
@@ -441,20 +500,20 @@ function createColumnMigration(...migrations) {
|
|
|
441
500
|
}
|
|
442
501
|
|
|
443
502
|
module.exports = {
|
|
444
|
-
createTable
|
|
445
|
-
deleteTable
|
|
446
|
-
getTables
|
|
447
|
-
getIndexes
|
|
448
|
-
addUnique
|
|
449
|
-
dropUnique
|
|
450
|
-
addPrimaryKey
|
|
451
|
-
addForeign
|
|
452
|
-
dropForeign
|
|
453
|
-
addColumn
|
|
454
|
-
dropColumn
|
|
455
|
-
setNullable
|
|
456
|
-
dropNullable
|
|
457
|
-
getColumns
|
|
503
|
+
createTable,
|
|
504
|
+
deleteTable,
|
|
505
|
+
getTables,
|
|
506
|
+
getIndexes,
|
|
507
|
+
addUnique,
|
|
508
|
+
dropUnique,
|
|
509
|
+
addPrimaryKey,
|
|
510
|
+
addForeign,
|
|
511
|
+
dropForeign,
|
|
512
|
+
addColumn,
|
|
513
|
+
dropColumn,
|
|
514
|
+
setNullable,
|
|
515
|
+
dropNullable,
|
|
516
|
+
getColumns,
|
|
458
517
|
createColumnMigration,
|
|
459
518
|
// NOTE: below are exposed for testing purposes only
|
|
460
519
|
_hasForeignSQLite: hasForeignSQLite,
|
|
@@ -295,6 +295,14 @@
|
|
|
295
295
|
"members_yearly_price_id": {
|
|
296
296
|
"defaultValue": null,
|
|
297
297
|
"type": "string"
|
|
298
|
+
},
|
|
299
|
+
"members_track_sources": {
|
|
300
|
+
"defaultValue": "true",
|
|
301
|
+
"validations": {
|
|
302
|
+
"isEmpty": false,
|
|
303
|
+
"isIn": [["true", "false"]]
|
|
304
|
+
},
|
|
305
|
+
"type": "boolean"
|
|
298
306
|
}
|
|
299
307
|
},
|
|
300
308
|
"portal": {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
|
-
const Promise = require('bluebird');
|
|
3
2
|
const logging = require('@tryghost/logging');
|
|
4
3
|
const {sequence} = require('@tryghost/promise');
|
|
5
4
|
|
|
@@ -83,16 +82,16 @@ class FixtureManager {
|
|
|
83
82
|
const userRolesRelation = this.fixtures.relations.find(r => r.from.relation === 'roles');
|
|
84
83
|
await this.addFixturesForRelation(userRolesRelation, localOptions);
|
|
85
84
|
|
|
86
|
-
await
|
|
85
|
+
await sequence(this.fixtures.models.filter(m => !['User', 'Role'].includes(m.name)).map(model => () => {
|
|
87
86
|
logging.info('Model: ' + model.name);
|
|
88
87
|
|
|
89
88
|
return this.addFixturesForModel(model, localOptions);
|
|
90
|
-
});
|
|
89
|
+
}));
|
|
91
90
|
|
|
92
|
-
await
|
|
91
|
+
await sequence(this.fixtures.relations.filter(r => r.from.relation !== 'roles').map(relation => () => {
|
|
93
92
|
logging.info('Relation: ' + relation.from.model + ' to ' + relation.to.model);
|
|
94
93
|
return this.addFixturesForRelation(relation, localOptions);
|
|
95
|
-
});
|
|
94
|
+
}));
|
|
96
95
|
}
|
|
97
96
|
|
|
98
97
|
/*
|
|
@@ -191,12 +190,15 @@ class FixtureManager {
|
|
|
191
190
|
fetchRelationData(relation, options) {
|
|
192
191
|
const fromOptions = _.extend({}, options, {withRelated: [relation.from.relation]});
|
|
193
192
|
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
to: models[relation.to.model].findAll(options)
|
|
197
|
-
};
|
|
193
|
+
const fromRelations = models[relation.from.model].findAll(fromOptions);
|
|
194
|
+
const toRelations = models[relation.to.model].findAll(options);
|
|
198
195
|
|
|
199
|
-
return Promise.
|
|
196
|
+
return Promise.all([fromRelations, toRelations]).then(([from, to]) => {
|
|
197
|
+
return {
|
|
198
|
+
from: from,
|
|
199
|
+
to: to
|
|
200
|
+
};
|
|
201
|
+
});
|
|
200
202
|
}
|
|
201
203
|
|
|
202
204
|
/**
|
|
@@ -223,7 +225,7 @@ class FixtureManager {
|
|
|
223
225
|
});
|
|
224
226
|
}
|
|
225
227
|
|
|
226
|
-
const results = await
|
|
228
|
+
const results = await sequence(modelFixture.entries.map(entry => async () => {
|
|
227
229
|
let data = {};
|
|
228
230
|
|
|
229
231
|
// CASE: if id is specified, only query by id
|
|
@@ -243,7 +245,7 @@ class FixtureManager {
|
|
|
243
245
|
if (!found) {
|
|
244
246
|
return models[modelFixture.name].add(entry, options);
|
|
245
247
|
}
|
|
246
|
-
});
|
|
248
|
+
}));
|
|
247
249
|
|
|
248
250
|
return {expected: modelFixture.entries.length, done: _.compact(results).length};
|
|
249
251
|
}
|
|
@@ -308,12 +310,12 @@ class FixtureManager {
|
|
|
308
310
|
}
|
|
309
311
|
|
|
310
312
|
async removeFixturesForModel(modelFixture, options) {
|
|
311
|
-
const results = await
|
|
313
|
+
const results = await sequence(modelFixture.entries.map(entry => async () => {
|
|
312
314
|
const found = models[modelFixture.name].findOne(entry.id ? {id: entry.id} : entry, options);
|
|
313
315
|
if (found) {
|
|
314
316
|
return models[modelFixture.name].destroy(_.extend(options, {id: found.id}));
|
|
315
317
|
}
|
|
316
|
-
});
|
|
318
|
+
}));
|
|
317
319
|
|
|
318
320
|
return {expected: modelFixture.entries.length, done: results.length};
|
|
319
321
|
}
|
|
@@ -618,6 +618,16 @@
|
|
|
618
618
|
"name": "Report comments",
|
|
619
619
|
"action_type": "report",
|
|
620
620
|
"object_type": "comment"
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
"name": "Browse links",
|
|
624
|
+
"action_type": "browse",
|
|
625
|
+
"object_type": "link"
|
|
626
|
+
},
|
|
627
|
+
{
|
|
628
|
+
"name": "Edit links",
|
|
629
|
+
"action_type": "edit",
|
|
630
|
+
"object_type": "link"
|
|
621
631
|
}
|
|
622
632
|
]
|
|
623
633
|
},
|
|
@@ -747,7 +757,8 @@
|
|
|
747
757
|
"members_stripe_connect": "auth",
|
|
748
758
|
"newsletter": "all",
|
|
749
759
|
"explore": "read",
|
|
750
|
-
"comment": "all"
|
|
760
|
+
"comment": "all",
|
|
761
|
+
"link": "all"
|
|
751
762
|
},
|
|
752
763
|
"DB Backup Integration": {
|
|
753
764
|
"db": "all"
|
|
@@ -781,7 +792,8 @@
|
|
|
781
792
|
"offer": ["browse", "read", "add", "edit"],
|
|
782
793
|
"newsletter": ["browse", "read", "add", "edit"],
|
|
783
794
|
"explore": "read",
|
|
784
|
-
"comment": "all"
|
|
795
|
+
"comment": "all",
|
|
796
|
+
"link": "all"
|
|
785
797
|
},
|
|
786
798
|
"Editor": {
|
|
787
799
|
"notification": "all",
|
|
@@ -517,7 +517,8 @@ module.exports = {
|
|
|
517
517
|
type: 'string', maxlength: 50, nullable: false, validations: {
|
|
518
518
|
isIn: [['member', 'import', 'system', 'api', 'admin']]
|
|
519
519
|
}
|
|
520
|
-
}
|
|
520
|
+
},
|
|
521
|
+
batch_id: {type: 'string', maxlength: 24, nullable: true}
|
|
521
522
|
},
|
|
522
523
|
members_cancel_events: {
|
|
523
524
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
@@ -630,7 +631,7 @@ module.exports = {
|
|
|
630
631
|
}
|
|
631
632
|
},
|
|
632
633
|
member_id: {type: 'string', maxlength: 24, nullable: false, unique: false, references: 'members.id', cascadeDelete: true},
|
|
633
|
-
tier_id: {type: 'string', maxlength: 24, nullable:
|
|
634
|
+
tier_id: {type: 'string', maxlength: 24, nullable: false, unique: false, references: 'products.id'},
|
|
634
635
|
|
|
635
636
|
// These are null if type !== 'paid'
|
|
636
637
|
cadence: {
|
|
@@ -657,6 +658,7 @@ module.exports = {
|
|
|
657
658
|
members_stripe_customers_subscriptions: {
|
|
658
659
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
659
660
|
customer_id: {type: 'string', maxlength: 255, nullable: false, unique: false, references: 'members_stripe_customers.customer_id', cascadeDelete: true},
|
|
661
|
+
ghost_subscription_id: {type: 'string', maxlength: 24, nullable: true, references: 'subscriptions.id', constraintName: 'mscs_ghost_subscription_id_foreign', cascadeDelete: true},
|
|
660
662
|
subscription_id: {type: 'string', maxlength: 255, nullable: false, unique: true},
|
|
661
663
|
stripe_price_id: {type: 'string', maxlength: 255, nullable: false, unique: false, index: true, defaultTo: ''},
|
|
662
664
|
status: {type: 'string', maxlength: 50, nullable: false},
|
|
@@ -696,7 +698,8 @@ module.exports = {
|
|
|
696
698
|
attribution_url: {type: 'string', maxlength: 2000, nullable: true},
|
|
697
699
|
referrer_source: {type: 'string', maxlength: 191, nullable: true},
|
|
698
700
|
referrer_medium: {type: 'string', maxlength: 191, nullable: true},
|
|
699
|
-
referrer_url: {type: 'string', maxlength: 2000, nullable: true}
|
|
701
|
+
referrer_url: {type: 'string', maxlength: 2000, nullable: true},
|
|
702
|
+
batch_id: {type: 'string', maxlength: 24, nullable: true}
|
|
700
703
|
},
|
|
701
704
|
offer_redemptions: {
|
|
702
705
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
@@ -782,6 +785,7 @@ module.exports = {
|
|
|
782
785
|
plaintext: {type: 'text', maxlength: 1000000000, fieldtype: 'long', nullable: true},
|
|
783
786
|
track_opens: {type: 'boolean', nullable: false, defaultTo: false},
|
|
784
787
|
track_clicks: {type: 'boolean', nullable: false, defaultTo: false},
|
|
788
|
+
feedback_enabled: {type: 'boolean', nullable: false, defaultTo: false},
|
|
785
789
|
submitted_at: {type: 'dateTime', nullable: false},
|
|
786
790
|
newsletter_id: {type: 'string', maxlength: 24, nullable: true, references: 'newsletters.id'},
|
|
787
791
|
created_at: {type: 'dateTime', nullable: false},
|
|
@@ -72,7 +72,7 @@ module.exports = function (Bookshelf) {
|
|
|
72
72
|
*
|
|
73
73
|
* We protect adding too many and uncontrolled events.
|
|
74
74
|
*
|
|
75
|
-
* We could
|
|
75
|
+
* We could embed adding actions more nicely in the future e.g. plugin.
|
|
76
76
|
*/
|
|
77
77
|
addAction: (model, event, options) => {
|
|
78
78
|
if (!model.wasChanged()) {
|
|
@@ -108,6 +108,18 @@ module.exports = function (Bookshelf) {
|
|
|
108
108
|
options.order = this.orderDefaultOptions();
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
if (options.selectRaw) {
|
|
112
|
+
itemCollection.query((qb) => {
|
|
113
|
+
qb.select(qb.client.raw(options.selectRaw));
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (options.whereRaw) {
|
|
118
|
+
itemCollection.query((qb) => {
|
|
119
|
+
qb.whereRaw(options.whereRaw);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
111
123
|
const response = await itemCollection.fetchPage(options);
|
|
112
124
|
// Attributes are being filtered here, so they are not leaked into calling layer
|
|
113
125
|
// where models are serialized to json and do not do more filtering.
|
|
@@ -3,6 +3,20 @@ const ghostBookshelf = require('./base');
|
|
|
3
3
|
const EmailRecipient = ghostBookshelf.Model.extend({
|
|
4
4
|
tableName: 'email_recipients',
|
|
5
5
|
hasTimestamps: false,
|
|
6
|
+
|
|
7
|
+
filterRelations: function filterRelations() {
|
|
8
|
+
return {
|
|
9
|
+
email: {
|
|
10
|
+
// Mongo-knex doesn't support belongsTo relations
|
|
11
|
+
tableName: 'emails',
|
|
12
|
+
tableNameAs: 'email',
|
|
13
|
+
type: 'manyToMany',
|
|
14
|
+
joinTable: 'email_recipients',
|
|
15
|
+
joinFrom: 'id',
|
|
16
|
+
joinTo: 'email_id'
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
},
|
|
6
20
|
|
|
7
21
|
email() {
|
|
8
22
|
return this.belongsTo('Email', 'email_id');
|
|
@@ -11,6 +11,7 @@ const Email = ghostBookshelf.Model.extend({
|
|
|
11
11
|
recipient_filter: 'status:-free',
|
|
12
12
|
track_opens: false,
|
|
13
13
|
track_clicks: false,
|
|
14
|
+
feedback_enabled: false,
|
|
14
15
|
delivered_count: 0,
|
|
15
16
|
opened_count: 0,
|
|
16
17
|
failed_count: 0
|
|
@@ -81,11 +82,7 @@ const Email = ghostBookshelf.Model.extend({
|
|
|
81
82
|
|
|
82
83
|
model.emitChange('deleted', options);
|
|
83
84
|
}
|
|
84
|
-
}, {
|
|
85
|
-
post() {
|
|
86
|
-
return this.belongsTo('Post');
|
|
87
|
-
}
|
|
88
|
-
});
|
|
85
|
+
}, {});
|
|
89
86
|
|
|
90
87
|
const Emails = ghostBookshelf.Collection.extend({
|
|
91
88
|
model: Email
|
|
@@ -10,7 +10,31 @@ const MemberClickEvent = ghostBookshelf.Model.extend({
|
|
|
10
10
|
|
|
11
11
|
member() {
|
|
12
12
|
return this.belongsTo('Member', 'member_id', 'id');
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
filterExpansions: function filterExpansions() {
|
|
16
|
+
const expansions = [{
|
|
17
|
+
key: 'post_id',
|
|
18
|
+
replacement: 'link.post_id'
|
|
19
|
+
}];
|
|
20
|
+
|
|
21
|
+
return expansions;
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
filterRelations() {
|
|
25
|
+
return {
|
|
26
|
+
link: {
|
|
27
|
+
// Mongo-knex doesn't support belongsTo relations
|
|
28
|
+
tableName: 'redirects',
|
|
29
|
+
tableNameAs: 'link',
|
|
30
|
+
type: 'manyToMany',
|
|
31
|
+
joinTable: 'members_click_events',
|
|
32
|
+
joinFrom: 'id',
|
|
33
|
+
joinTo: 'redirect_id'
|
|
34
|
+
}
|
|
35
|
+
};
|
|
13
36
|
}
|
|
37
|
+
|
|
14
38
|
}, {
|
|
15
39
|
async edit() {
|
|
16
40
|
throw new errors.IncorrectUsageError({message: 'Cannot edit MemberClickEvent'});
|
|
@@ -18,6 +42,19 @@ const MemberClickEvent = ghostBookshelf.Model.extend({
|
|
|
18
42
|
|
|
19
43
|
async destroy() {
|
|
20
44
|
throw new errors.IncorrectUsageError({message: 'Cannot destroy MemberClickEvent'});
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
permittedOptions(methodName) {
|
|
48
|
+
let options = ghostBookshelf.Model.permittedOptions.call(this, methodName);
|
|
49
|
+
const validOptions = {
|
|
50
|
+
findPage: ['selectRaw', 'whereRaw']
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
if (validOptions[methodName]) {
|
|
54
|
+
options = options.concat(validOptions[methodName]);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return options;
|
|
21
58
|
}
|
|
22
59
|
});
|
|
23
60
|
|
|
@@ -8,6 +8,13 @@ const MemberCreatedEvent = ghostBookshelf.Model.extend({
|
|
|
8
8
|
return this.belongsTo('Member', 'member_id', 'id');
|
|
9
9
|
},
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* The subscription created event that happend at the same time (if any)
|
|
13
|
+
*/
|
|
14
|
+
subscriptionCreatedEvent() {
|
|
15
|
+
return this.belongsTo('SubscriptionCreatedEvent', 'batch_id', 'batch_id');
|
|
16
|
+
},
|
|
17
|
+
|
|
11
18
|
postAttribution() {
|
|
12
19
|
return this.belongsTo('Post', 'attribution_id', 'id');
|
|
13
20
|
},
|
|
@@ -18,6 +25,22 @@ const MemberCreatedEvent = ghostBookshelf.Model.extend({
|
|
|
18
25
|
|
|
19
26
|
tagAttribution() {
|
|
20
27
|
return this.belongsTo('Tag', 'attribution_id', 'id');
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
filterRelations() {
|
|
31
|
+
return {
|
|
32
|
+
subscriptionCreatedEvent: {
|
|
33
|
+
// Mongo-knex doesn't support belongsTo relations
|
|
34
|
+
tableName: 'members_subscription_created_events',
|
|
35
|
+
tableNameAs: 'subscriptionCreatedEvent',
|
|
36
|
+
type: 'manyToMany',
|
|
37
|
+
joinTable: 'members_created_events',
|
|
38
|
+
joinFrom: 'id',
|
|
39
|
+
joinToForeign: 'batch_id',
|
|
40
|
+
joinTo: 'batch_id',
|
|
41
|
+
joinType: 'leftJoin'
|
|
42
|
+
}
|
|
43
|
+
};
|
|
21
44
|
}
|
|
22
45
|
}, {
|
|
23
46
|
async edit() {
|