ghost 5.10.1 → 5.11.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.10.1.tgz → tryghost-adapter-manager-5.11.0.tgz} +0 -0
- package/components/tryghost-api-framework-5.11.0.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-5.11.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.11.0.tgz +0 -0
- package/components/tryghost-constants-5.11.0.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-5.11.0.tgz +0 -0
- package/components/{tryghost-domain-events-5.10.1.tgz → tryghost-domain-events-5.11.0.tgz} +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.11.0.tgz +0 -0
- package/components/{tryghost-email-analytics-service-5.10.1.tgz → tryghost-email-analytics-service-5.11.0.tgz} +0 -0
- package/components/tryghost-email-content-generator-5.11.0.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.11.0.tgz +0 -0
- package/components/{tryghost-extract-api-key-5.10.1.tgz → tryghost-extract-api-key-5.11.0.tgz} +0 -0
- package/components/tryghost-html-to-plaintext-5.11.0.tgz +0 -0
- package/components/{tryghost-job-manager-5.10.1.tgz → tryghost-job-manager-5.11.0.tgz} +0 -0
- package/components/{tryghost-magic-link-5.10.1.tgz → tryghost-magic-link-5.11.0.tgz} +0 -0
- package/components/tryghost-mailgun-client-5.11.0.tgz +0 -0
- package/components/tryghost-member-analytics-service-5.11.0.tgz +0 -0
- package/components/tryghost-member-attribution-5.11.0.tgz +0 -0
- package/components/{tryghost-member-events-5.10.1.tgz → tryghost-member-events-5.11.0.tgz} +0 -0
- package/components/tryghost-members-analytics-ingress-5.11.0.tgz +0 -0
- package/components/tryghost-members-api-5.11.0.tgz +0 -0
- package/components/{tryghost-members-csv-5.10.1.tgz → tryghost-members-csv-5.11.0.tgz} +0 -0
- package/components/tryghost-members-events-service-5.11.0.tgz +0 -0
- package/components/tryghost-members-importer-5.11.0.tgz +0 -0
- package/components/tryghost-members-offers-5.11.0.tgz +0 -0
- package/components/tryghost-members-payments-5.11.0.tgz +0 -0
- package/components/{tryghost-members-ssr-5.10.1.tgz → tryghost-members-ssr-5.11.0.tgz} +0 -0
- package/components/{tryghost-members-stripe-service-5.10.1.tgz → tryghost-members-stripe-service-5.11.0.tgz} +0 -0
- package/components/tryghost-minifier-5.11.0.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.11.0.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.11.0.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.11.0.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.11.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.11.0.tgz +0 -0
- package/components/{tryghost-mw-vhost-5.10.1.tgz → tryghost-mw-vhost-5.11.0.tgz} +0 -0
- package/components/tryghost-oembed-service-5.11.0.tgz +0 -0
- package/components/{tryghost-package-json-5.10.1.tgz → tryghost-package-json-5.11.0.tgz} +0 -0
- package/components/tryghost-security-5.11.0.tgz +0 -0
- package/components/{tryghost-session-service-5.10.1.tgz → tryghost-session-service-5.11.0.tgz} +0 -0
- package/components/tryghost-settings-path-manager-5.11.0.tgz +0 -0
- package/components/{tryghost-update-check-service-5.10.1.tgz → tryghost-update-check-service-5.11.0.tgz} +0 -0
- package/components/tryghost-verification-trigger-5.11.0.tgz +0 -0
- package/components/{tryghost-version-notifications-data-service-5.10.1.tgz → tryghost-version-notifications-data-service-5.11.0.tgz} +0 -0
- package/core/built/admin/assets/chunk.143.14589cc066b8120b73e3.js +49 -0
- package/core/built/admin/assets/{chunk.174.0364e8abdae8210d8e6d.js → chunk.174.ae492405065373dbe102.js} +1 -1
- package/core/built/admin/assets/{chunk.178.bb46965ba0483c3e79ae.js → chunk.178.131e85a10d2031148425.js} +4 -4
- package/core/built/admin/assets/{chunk.351.ea4a4ff4b40d5f2ad141.js → chunk.579.65e09dd89eec70d059a0.js} +3 -11
- package/core/built/admin/assets/{chunk.351.ea4a4ff4b40d5f2ad141.js.LICENSE.txt → chunk.579.65e09dd89eec70d059a0.js.LICENSE.txt} +0 -0
- package/core/built/admin/assets/ghost-1b0d7c731511bb738ec457d2932c43c0.css +1 -0
- package/core/built/admin/assets/{ghost-ced03a7ac75c3148e0ea7d1bf51e39fc.js → ghost-40f5bd12d121c54bbc39e7939e78244f.js} +745 -566
- package/core/built/admin/assets/ghost-dark-7b2825a050b0382630180f48aa78ea5d.css +1 -0
- package/core/built/admin/assets/icons/calendar-stroke.svg +1 -0
- package/core/built/admin/assets/icons/pen-stroke.svg +1 -0
- package/core/built/admin/assets/{vendor-a1ae7a38d5c38fcba5609eed4e37f02a.js → vendor-741dc0e4078e044a0c9bfaad104de8b3.js} +55 -51
- package/core/built/admin/index.html +6 -6
- package/core/server/api/endpoints/comments-members.js +10 -7
- package/core/server/api/endpoints/invites.js +1 -9
- package/core/server/api/endpoints/labels.js +1 -7
- package/core/server/api/endpoints/members.js +3 -13
- package/core/server/api/endpoints/offers.js +2 -2
- package/core/server/api/endpoints/pages.js +2 -10
- package/core/server/api/endpoints/posts.js +1 -9
- package/core/server/api/endpoints/snippets.js +1 -9
- package/core/server/api/endpoints/tags.js +1 -7
- package/core/server/api/endpoints/utils/serializers/input/pages.js +1 -1
- package/core/server/api/endpoints/utils/serializers/output/members.js +2 -1
- package/core/server/api/endpoints/utils/serializers/output/site.js +1 -0
- package/core/server/api/endpoints/utils/serializers/output/utils/clean.js +6 -7
- package/core/server/api/endpoints/webhooks.js +2 -19
- package/core/server/data/migrations/versions/5.11/2022-08-22-11-03-add-member-alert-settings-columns-to-users.js +21 -0
- package/core/server/data/migrations/versions/5.11/2022-08-23-13-41-backfill-members-created-events.js +32 -0
- package/core/server/data/migrations/versions/5.11/2022-08-23-13-59-fix-page-resource-type.js +22 -0
- package/core/server/data/schema/fixtures/fixtures.json +3 -0
- package/core/server/data/schema/schema.js +3 -0
- package/core/server/lib/image/gravatar.js +8 -7
- package/core/server/lib/image/image-size.js +60 -56
- package/core/server/models/action.js +0 -10
- package/core/server/models/base/plugins/actions.js +26 -3
- package/core/server/models/member.js +18 -0
- package/core/server/models/offer.js +3 -0
- package/core/server/models/post.js +2 -3
- package/core/server/models/product.js +3 -0
- package/core/server/models/settings.js +4 -0
- package/core/server/models/user.js +4 -1
- package/core/server/services/auth/api-key/admin.js +0 -3
- package/core/server/services/auth/passwordreset.js +0 -3
- package/core/server/services/explore/service.js +7 -6
- package/core/server/services/member-attribution/index.js +34 -6
- package/core/server/services/public-config/site.js +1 -0
- package/core/server/services/route-settings/default-settings-manager.js +19 -17
- package/core/server/services/webhooks/trigger.js +14 -5
- package/core/shared/config/defaults.json +3 -2
- package/core/shared/labs.js +4 -4
- package/package.json +82 -82
- package/yarn.lock +92 -109
- package/components/tryghost-api-framework-5.10.1.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-5.10.1.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.10.1.tgz +0 -0
- package/components/tryghost-constants-5.10.1.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-5.10.1.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.10.1.tgz +0 -0
- package/components/tryghost-email-content-generator-5.10.1.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.10.1.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.10.1.tgz +0 -0
- package/components/tryghost-mailgun-client-5.10.1.tgz +0 -0
- package/components/tryghost-member-analytics-service-5.10.1.tgz +0 -0
- package/components/tryghost-member-attribution-5.10.1.tgz +0 -0
- package/components/tryghost-members-analytics-ingress-5.10.1.tgz +0 -0
- package/components/tryghost-members-api-5.10.1.tgz +0 -0
- package/components/tryghost-members-events-service-5.10.1.tgz +0 -0
- package/components/tryghost-members-importer-5.10.1.tgz +0 -0
- package/components/tryghost-members-offers-5.10.1.tgz +0 -0
- package/components/tryghost-members-payments-5.10.1.tgz +0 -0
- package/components/tryghost-minifier-5.10.1.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.10.1.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.10.1.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.10.1.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.10.1.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.10.1.tgz +0 -0
- package/components/tryghost-oembed-service-5.10.1.tgz +0 -0
- package/components/tryghost-security-5.10.1.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.10.1.tgz +0 -0
- package/components/tryghost-verification-trigger-5.10.1.tgz +0 -0
- package/core/built/admin/assets/chunk.143.71da0e884297554a8ec4.js +0 -41
- package/core/built/admin/assets/ghost-13baab17b3f54b21f341fb8f36f83110.css +0 -1
- package/core/built/admin/assets/ghost-dark-b0500577a42e2770994e6aef0e70f182.css +0 -1
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// NOTE: We must not cache references to membersService.api
|
|
2
2
|
// as it is a getter and may change during runtime.
|
|
3
|
-
const Promise = require('bluebird');
|
|
4
3
|
const moment = require('moment-timezone');
|
|
5
4
|
const errors = require('@tryghost/errors');
|
|
6
5
|
const models = require('../../models');
|
|
@@ -253,20 +252,11 @@ module.exports = {
|
|
|
253
252
|
},
|
|
254
253
|
permissions: true,
|
|
255
254
|
async query(frame) {
|
|
256
|
-
|
|
257
|
-
frame.options.cancelStripeSubscriptions = frame.options.cancel;
|
|
258
|
-
|
|
259
|
-
await Promise.resolve(membersService.api.members.destroy({
|
|
255
|
+
return membersService.api.members.destroy({
|
|
260
256
|
id: frame.options.id
|
|
261
|
-
},
|
|
262
|
-
|
|
263
|
-
message: tpl(messages.resourceNotFound, {
|
|
264
|
-
resource: 'Member'
|
|
265
|
-
})
|
|
266
|
-
});
|
|
257
|
+
}, {
|
|
258
|
+
...frame.options, require: true, cancelStripeSubscriptions: frame.options.cancel
|
|
267
259
|
});
|
|
268
|
-
|
|
269
|
-
return null;
|
|
270
260
|
}
|
|
271
261
|
},
|
|
272
262
|
|
|
@@ -49,7 +49,7 @@ module.exports = {
|
|
|
49
49
|
const offer = await offersService.api.updateOffer({
|
|
50
50
|
...frame.data.offers[0],
|
|
51
51
|
id: frame.options.id
|
|
52
|
-
});
|
|
52
|
+
}, frame.options);
|
|
53
53
|
|
|
54
54
|
if (!offer) {
|
|
55
55
|
throw new errors.NotFoundError({
|
|
@@ -69,7 +69,7 @@ module.exports = {
|
|
|
69
69
|
cacheInvalidate: true
|
|
70
70
|
},
|
|
71
71
|
async query(frame) {
|
|
72
|
-
const offer = await offersService.api.createOffer(frame.data.offers[0]);
|
|
72
|
+
const offer = await offersService.api.createOffer(frame.data.offers[0], frame.options);
|
|
73
73
|
return {
|
|
74
74
|
data: [offer]
|
|
75
75
|
};
|
|
@@ -2,7 +2,7 @@ const models = require('../../models');
|
|
|
2
2
|
const tpl = require('@tryghost/tpl');
|
|
3
3
|
const errors = require('@tryghost/errors');
|
|
4
4
|
const getPostServiceInstance = require('../../services/posts/posts-service');
|
|
5
|
-
const ALLOWED_INCLUDES = ['tags', 'authors', 'authors.roles', 'tiers'];
|
|
5
|
+
const ALLOWED_INCLUDES = ['tags', 'authors', 'authors.roles', 'tiers', 'count.signups', 'count.conversions'];
|
|
6
6
|
const UNSAFE_ATTRS = ['status', 'authors', 'visibility'];
|
|
7
7
|
|
|
8
8
|
const messages = {
|
|
@@ -186,15 +186,7 @@ module.exports = {
|
|
|
186
186
|
unsafeAttrs: UNSAFE_ATTRS
|
|
187
187
|
},
|
|
188
188
|
query(frame) {
|
|
189
|
-
frame.options
|
|
190
|
-
|
|
191
|
-
return models.Post.destroy(frame.options)
|
|
192
|
-
.then(() => null)
|
|
193
|
-
.catch(models.Post.NotFoundError, () => {
|
|
194
|
-
return Promise.reject(new errors.NotFoundError({
|
|
195
|
-
message: tpl(messages.pageNotFound)
|
|
196
|
-
}));
|
|
197
|
-
});
|
|
189
|
+
return models.Post.destroy({...frame.options, require: true});
|
|
198
190
|
}
|
|
199
191
|
}
|
|
200
192
|
};
|
|
@@ -192,15 +192,7 @@ module.exports = {
|
|
|
192
192
|
unsafeAttrs: unsafeAttrs
|
|
193
193
|
},
|
|
194
194
|
query(frame) {
|
|
195
|
-
frame.options
|
|
196
|
-
|
|
197
|
-
return models.Post.destroy(frame.options)
|
|
198
|
-
.then(() => null)
|
|
199
|
-
.catch(models.Post.NotFoundError, () => {
|
|
200
|
-
return Promise.reject(new errors.NotFoundError({
|
|
201
|
-
message: tpl(messages.postNotFound)
|
|
202
|
-
}));
|
|
203
|
-
});
|
|
195
|
+
return models.Post.destroy({...frame.options, require: true});
|
|
204
196
|
}
|
|
205
197
|
}
|
|
206
198
|
};
|
|
@@ -101,15 +101,7 @@ module.exports = {
|
|
|
101
101
|
},
|
|
102
102
|
permissions: true,
|
|
103
103
|
query(frame) {
|
|
104
|
-
frame.options
|
|
105
|
-
|
|
106
|
-
return models.Snippet.destroy(frame.options)
|
|
107
|
-
.then(() => null)
|
|
108
|
-
.catch(models.Snippet.NotFoundError, () => {
|
|
109
|
-
return Promise.reject(new errors.NotFoundError({
|
|
110
|
-
message: tpl(messages.snippetNotFound)
|
|
111
|
-
}));
|
|
112
|
-
});
|
|
104
|
+
return models.Snippet.destroy({...frame.options, require: true});
|
|
113
105
|
}
|
|
114
106
|
}
|
|
115
107
|
};
|
|
@@ -147,13 +147,7 @@ module.exports = {
|
|
|
147
147
|
},
|
|
148
148
|
permissions: true,
|
|
149
149
|
query(frame) {
|
|
150
|
-
return models.Tag.destroy(frame.options)
|
|
151
|
-
.then(() => null)
|
|
152
|
-
.catch(models.Tag.NotFoundError, () => {
|
|
153
|
-
return Promise.reject(new errors.NotFoundError({
|
|
154
|
-
message: tpl(messages.tagNotFound)
|
|
155
|
-
}));
|
|
156
|
-
});
|
|
150
|
+
return models.Tag.destroy({...frame.options, require: true});
|
|
157
151
|
}
|
|
158
152
|
}
|
|
159
153
|
};
|
|
@@ -23,7 +23,7 @@ function defaultRelations(frame) {
|
|
|
23
23
|
return false;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'tiers'];
|
|
26
|
+
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'tiers', 'count.signups', 'count.conversions'];
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
function setDefaultOrder(frame) {
|
|
@@ -128,7 +128,8 @@ function serializeMember(member, options) {
|
|
|
128
128
|
email_open_rate: json.email_open_rate,
|
|
129
129
|
email_recipients: json.email_recipients,
|
|
130
130
|
status: json.status,
|
|
131
|
-
last_seen_at: json.last_seen_at
|
|
131
|
+
last_seen_at: json.last_seen_at,
|
|
132
|
+
attribution: json.attribution
|
|
132
133
|
};
|
|
133
134
|
|
|
134
135
|
if (json.products) {
|
|
@@ -32,6 +32,9 @@ const author = (attrs, frame) => {
|
|
|
32
32
|
delete attrs.status;
|
|
33
33
|
delete attrs.email;
|
|
34
34
|
delete attrs.comment_notifications;
|
|
35
|
+
delete attrs.free_member_signup_notification;
|
|
36
|
+
delete attrs.paid_subscription_started_notification;
|
|
37
|
+
delete attrs.paid_subscription_canceled_notification;
|
|
35
38
|
|
|
36
39
|
// @NOTE: used for night shift
|
|
37
40
|
delete attrs.accessibility;
|
|
@@ -130,9 +133,6 @@ const post = (attrs, frame) => {
|
|
|
130
133
|
|
|
131
134
|
const action = (attrs) => {
|
|
132
135
|
if (attrs.actor) {
|
|
133
|
-
delete attrs.actor_id;
|
|
134
|
-
delete attrs.resource_id;
|
|
135
|
-
|
|
136
136
|
if (attrs.actor_type === 'user') {
|
|
137
137
|
attrs.actor = _.pick(attrs.actor, ['id', 'name', 'slug', 'profile_image']);
|
|
138
138
|
attrs.actor.image = attrs.actor.profile_image;
|
|
@@ -142,12 +142,11 @@ const action = (attrs) => {
|
|
|
142
142
|
attrs.actor.image = attrs.actor.icon_image;
|
|
143
143
|
delete attrs.actor.icon_image;
|
|
144
144
|
}
|
|
145
|
-
}
|
|
146
|
-
delete attrs.actor_id;
|
|
147
|
-
delete attrs.resource_id;
|
|
145
|
+
}
|
|
148
146
|
|
|
147
|
+
if (attrs.resource) {
|
|
149
148
|
// @NOTE: we only support posts right now
|
|
150
|
-
attrs.resource = _.pick(attrs.resource, ['id', 'title', 'slug', 'feature_image']);
|
|
149
|
+
attrs.resource = _.pick(attrs.resource, ['id', 'title', 'slug', 'feature_image', 'name']);
|
|
151
150
|
attrs.resource.image = attrs.resource.feature_image;
|
|
152
151
|
delete attrs.resource.feature_image;
|
|
153
152
|
}
|
|
@@ -78,14 +78,7 @@ module.exports = {
|
|
|
78
78
|
}
|
|
79
79
|
},
|
|
80
80
|
query({data, options}) {
|
|
81
|
-
return models.Webhook.edit(data.webhooks[0],
|
|
82
|
-
.catch(models.Webhook.NotFoundError, () => {
|
|
83
|
-
throw new errors.NotFoundError({
|
|
84
|
-
message: tpl(messages.resourceNotFound, {
|
|
85
|
-
resource: 'Webhook'
|
|
86
|
-
})
|
|
87
|
-
});
|
|
88
|
-
});
|
|
81
|
+
return models.Webhook.edit(data.webhooks[0], {...options, require: true});
|
|
89
82
|
}
|
|
90
83
|
},
|
|
91
84
|
|
|
@@ -130,17 +123,7 @@ module.exports = {
|
|
|
130
123
|
}
|
|
131
124
|
},
|
|
132
125
|
query(frame) {
|
|
133
|
-
frame.options
|
|
134
|
-
|
|
135
|
-
return models.Webhook.destroy(frame.options)
|
|
136
|
-
.then(() => null)
|
|
137
|
-
.catch(models.Webhook.NotFoundError, () => {
|
|
138
|
-
return Promise.reject(new errors.NotFoundError({
|
|
139
|
-
message: tpl(messages.resourceNotFound, {
|
|
140
|
-
resource: 'Webhook'
|
|
141
|
-
})
|
|
142
|
-
}));
|
|
143
|
-
});
|
|
126
|
+
return models.Webhook.destroy({...frame.options, require: true});
|
|
144
127
|
}
|
|
145
128
|
}
|
|
146
129
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const {createAddColumnMigration, combineNonTransactionalMigrations} = require('../../utils');
|
|
2
|
+
|
|
3
|
+
module.exports = combineNonTransactionalMigrations(
|
|
4
|
+
createAddColumnMigration('users', 'free_member_signup_notification', {
|
|
5
|
+
type: 'boolean',
|
|
6
|
+
nullable: false,
|
|
7
|
+
defaultTo: true
|
|
8
|
+
}),
|
|
9
|
+
|
|
10
|
+
createAddColumnMigration('users', 'paid_subscription_canceled_notification', {
|
|
11
|
+
type: 'boolean',
|
|
12
|
+
nullable: false,
|
|
13
|
+
defaultTo: false
|
|
14
|
+
}),
|
|
15
|
+
|
|
16
|
+
createAddColumnMigration('users', 'paid_subscription_started_notification', {
|
|
17
|
+
type: 'boolean',
|
|
18
|
+
nullable: false,
|
|
19
|
+
defaultTo: true
|
|
20
|
+
})
|
|
21
|
+
);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const ObjectID = require('bson-objectid').default;
|
|
2
|
+
const logging = require('@tryghost/logging');
|
|
3
|
+
|
|
4
|
+
const {createTransactionalMigration} = require('../../utils');
|
|
5
|
+
|
|
6
|
+
module.exports = createTransactionalMigration(
|
|
7
|
+
async function up(knex) {
|
|
8
|
+
const members = await knex('members')
|
|
9
|
+
.select('id', 'created_at');
|
|
10
|
+
|
|
11
|
+
if (members.length === 0) {
|
|
12
|
+
logging.warn(`Skipping migration because no members found`);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const toInsert = members.map((member) => {
|
|
17
|
+
return {
|
|
18
|
+
id: ObjectID().toHexString(),
|
|
19
|
+
member_id: member.id,
|
|
20
|
+
created_at: member.created_at,
|
|
21
|
+
source: 'member'
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
logging.info(`Inserting ${toInsert.length} members created events`);
|
|
26
|
+
await knex.batchInsert('members_created_events', toInsert);
|
|
27
|
+
},
|
|
28
|
+
async function down(knex) {
|
|
29
|
+
logging.info(`Clearing all members created events`);
|
|
30
|
+
await knex('members_created_events').del();
|
|
31
|
+
}
|
|
32
|
+
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const logging = require('@tryghost/logging');
|
|
2
|
+
const {createTransactionalMigration} = require('../../utils');
|
|
3
|
+
|
|
4
|
+
module.exports = createTransactionalMigration(
|
|
5
|
+
async function up(knex) {
|
|
6
|
+
logging.info(`Changing Action event 'page' resource_type to 'post'`);
|
|
7
|
+
|
|
8
|
+
const affectedRows = await knex('actions')
|
|
9
|
+
.update({
|
|
10
|
+
resource_type: 'post',
|
|
11
|
+
context: JSON.stringify({
|
|
12
|
+
type: 'page'
|
|
13
|
+
})
|
|
14
|
+
})
|
|
15
|
+
.where('resource_type', 'page');
|
|
16
|
+
|
|
17
|
+
logging.info(`Updated ${affectedRows} Action events from 'page' to 'post'`);
|
|
18
|
+
},
|
|
19
|
+
async function down() {
|
|
20
|
+
// no-op: we don't want to put `pages` back as a resource type
|
|
21
|
+
}
|
|
22
|
+
);
|
|
@@ -626,6 +626,9 @@
|
|
|
626
626
|
"name": "Ghost",
|
|
627
627
|
"email": "ghost@example.com",
|
|
628
628
|
"status": "inactive",
|
|
629
|
+
"free_member_signup_notification": true,
|
|
630
|
+
"paid_subscription_started_notification": true,
|
|
631
|
+
"paid_subscription_canceled_notification": false,
|
|
629
632
|
"roles": []
|
|
630
633
|
}
|
|
631
634
|
]
|
|
@@ -149,6 +149,9 @@ module.exports = {
|
|
|
149
149
|
tour: {type: 'text', maxlength: 65535, nullable: true},
|
|
150
150
|
last_seen: {type: 'dateTime', nullable: true},
|
|
151
151
|
comment_notifications: {type: 'boolean', nullable: false, defaultTo: true},
|
|
152
|
+
free_member_signup_notification: {type: 'boolean', nullable: false, defaultTo: true},
|
|
153
|
+
paid_subscription_started_notification: {type: 'boolean', nullable: false, defaultTo: true},
|
|
154
|
+
paid_subscription_canceled_notification: {type: 'boolean', nullable: false, defaultTo: false},
|
|
152
155
|
created_at: {type: 'dateTime', nullable: false},
|
|
153
156
|
created_by: {type: 'string', maxlength: 24, nullable: false},
|
|
154
157
|
updated_at: {type: 'dateTime', nullable: true},
|
|
@@ -40,15 +40,16 @@ class Gravatar {
|
|
|
40
40
|
image: imageUrl
|
|
41
41
|
};
|
|
42
42
|
})
|
|
43
|
-
.catch(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
.catch(function (err) {
|
|
44
|
+
if (err.statusCode === 404) {
|
|
45
|
+
return {
|
|
46
|
+
image: undefined
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
49
50
|
// ignore error, just resolve with no image url
|
|
50
51
|
});
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
module.exports = Gravatar;
|
|
55
|
+
module.exports = Gravatar;
|
|
@@ -163,39 +163,41 @@ class ImageSize {
|
|
|
163
163
|
width: dimensions.width,
|
|
164
164
|
height: dimensions.height
|
|
165
165
|
};
|
|
166
|
-
}).catch(
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
166
|
+
}).catch((err) => {
|
|
167
|
+
if (err.code === 'URL_MISSING_INVALID') {
|
|
168
|
+
return Promise.reject(new errors.InternalServerError({
|
|
169
|
+
message: err.message,
|
|
170
|
+
code: 'IMAGE_SIZE_URL',
|
|
171
|
+
statusCode: err.statusCode,
|
|
172
|
+
context: err.url || imagePath
|
|
173
|
+
}));
|
|
174
|
+
} else if (err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT' || err.code === 'ECONNRESET' || err.statusCode === 408) {
|
|
175
|
+
return Promise.reject(new errors.InternalServerError({
|
|
176
|
+
message: 'Request timed out.',
|
|
177
|
+
code: 'IMAGE_SIZE_URL',
|
|
178
|
+
statusCode: err.statusCode,
|
|
179
|
+
context: err.url || imagePath
|
|
180
|
+
}));
|
|
181
|
+
} else if (err.code === 'ENOENT' || err.code === 'ENOTFOUND' || err.statusCode === 404) {
|
|
182
|
+
return Promise.reject(new errors.NotFoundError({
|
|
183
|
+
message: 'Image not found.',
|
|
184
|
+
code: 'IMAGE_SIZE_URL',
|
|
185
|
+
statusCode: err.statusCode,
|
|
186
|
+
context: err.url || imagePath
|
|
187
|
+
}));
|
|
188
|
+
} else {
|
|
189
|
+
if (errors.utils.isGhostError(err)) {
|
|
190
|
+
return Promise.reject(err);
|
|
191
|
+
}
|
|
191
192
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
193
|
+
return Promise.reject(new errors.InternalServerError({
|
|
194
|
+
message: 'Unknown Request error.',
|
|
195
|
+
code: 'IMAGE_SIZE_URL',
|
|
196
|
+
statusCode: err.statusCode,
|
|
197
|
+
context: err.url || imagePath,
|
|
198
|
+
err: err
|
|
199
|
+
}));
|
|
200
|
+
}
|
|
199
201
|
});
|
|
200
202
|
}
|
|
201
203
|
|
|
@@ -237,32 +239,34 @@ class ImageSize {
|
|
|
237
239
|
height: dimensions.height
|
|
238
240
|
};
|
|
239
241
|
})
|
|
240
|
-
.catch(
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
242
|
+
.catch((err) => {
|
|
243
|
+
if (err.code === 'ENOENT') {
|
|
244
|
+
return Promise.reject(new errors.NotFoundError({
|
|
245
|
+
message: err.message,
|
|
246
|
+
code: 'IMAGE_SIZE_STORAGE',
|
|
247
|
+
err: err,
|
|
248
|
+
context: filePath,
|
|
249
|
+
errorDetails: {
|
|
250
|
+
originalPath: imagePath,
|
|
251
|
+
reqFilePath: filePath
|
|
252
|
+
}
|
|
253
|
+
}));
|
|
254
|
+
} else {
|
|
255
|
+
if (errors.utils.isGhostError(err)) {
|
|
256
|
+
return Promise.reject(err);
|
|
249
257
|
}
|
|
250
|
-
}));
|
|
251
|
-
}).catch((err) => {
|
|
252
|
-
if (errors.utils.isGhostError(err)) {
|
|
253
|
-
return Promise.reject(err);
|
|
254
|
-
}
|
|
255
258
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
259
|
+
return Promise.reject(new errors.InternalServerError({
|
|
260
|
+
message: err.message,
|
|
261
|
+
code: 'IMAGE_SIZE_STORAGE',
|
|
262
|
+
err: err,
|
|
263
|
+
context: filePath,
|
|
264
|
+
errorDetails: {
|
|
265
|
+
originalPath: imagePath,
|
|
266
|
+
reqFilePath: filePath
|
|
267
|
+
}
|
|
268
|
+
}));
|
|
269
|
+
}
|
|
266
270
|
});
|
|
267
271
|
}
|
|
268
272
|
|
|
@@ -19,16 +19,6 @@ const Action = ghostBookshelf.Model.extend({
|
|
|
19
19
|
|
|
20
20
|
resource() {
|
|
21
21
|
return this.morphTo('resource', ['resource_type', 'resource_id'], ...candidates);
|
|
22
|
-
},
|
|
23
|
-
|
|
24
|
-
toJSON(unfilteredOptions) {
|
|
25
|
-
const options = Action.filterOptions(unfilteredOptions, 'toJSON');
|
|
26
|
-
const attrs = ghostBookshelf.Model.prototype.toJSON.call(this, options);
|
|
27
|
-
|
|
28
|
-
// @TODO: context is not implemented yet
|
|
29
|
-
delete attrs.context;
|
|
30
|
-
|
|
31
|
-
return attrs;
|
|
32
22
|
}
|
|
33
23
|
}, {
|
|
34
24
|
orderDefaultOptions: function orderDefaultOptions() {
|
|
@@ -29,14 +29,37 @@ module.exports = function (Bookshelf) {
|
|
|
29
29
|
resourceType = resourceType.bind(this)();
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
if (!resourceType) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let context = {};
|
|
37
|
+
|
|
38
|
+
if (this.actionsExtraContext && Array.isArray(this.actionsExtraContext)) {
|
|
39
|
+
for (const c of this.actionsExtraContext) {
|
|
40
|
+
context[c] = this.get(c) || this.previous(c);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (event === 'deleted') {
|
|
45
|
+
context.primary_name = (this.previous('title') || this.previous('name'));
|
|
46
|
+
} else if (['added', 'edited'].includes(event)) {
|
|
47
|
+
context.primary_name = (this.get('title') || this.get('name') || this.previous('title') || this.previous('name'));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const data = {
|
|
51
|
+
event,
|
|
35
52
|
resource_id: this.id || this.previous('id'),
|
|
36
53
|
resource_type: resourceType,
|
|
37
54
|
actor_id: actor.id,
|
|
38
55
|
actor_type: actor.type
|
|
39
56
|
};
|
|
57
|
+
|
|
58
|
+
if (context && Object.keys(context).length) {
|
|
59
|
+
data.context = context;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return data;
|
|
40
63
|
},
|
|
41
64
|
|
|
42
65
|
/**
|
|
@@ -40,6 +40,12 @@ const Member = ghostBookshelf.Model.extend({
|
|
|
40
40
|
}, {
|
|
41
41
|
key: 'newsletters',
|
|
42
42
|
replacement: 'newsletters.slug'
|
|
43
|
+
}, {
|
|
44
|
+
key: 'signup',
|
|
45
|
+
replacement: 'signups.attribution_id'
|
|
46
|
+
}, {
|
|
47
|
+
key: 'conversion',
|
|
48
|
+
replacement: 'conversions.attribution_id'
|
|
43
49
|
}];
|
|
44
50
|
},
|
|
45
51
|
|
|
@@ -74,6 +80,18 @@ const Member = ghostBookshelf.Model.extend({
|
|
|
74
80
|
joinFrom: 'member_id',
|
|
75
81
|
joinTo: 'customer_id',
|
|
76
82
|
joinToForeign: 'customer_id'
|
|
83
|
+
},
|
|
84
|
+
signups: {
|
|
85
|
+
tableName: 'members_created_events',
|
|
86
|
+
tableNameAs: 'signups',
|
|
87
|
+
type: 'oneToOne',
|
|
88
|
+
joinFrom: 'member_id'
|
|
89
|
+
},
|
|
90
|
+
conversions: {
|
|
91
|
+
tableName: 'members_subscription_created_events',
|
|
92
|
+
tableNameAs: 'conversions',
|
|
93
|
+
type: 'oneToOne',
|
|
94
|
+
joinFrom: 'member_id'
|
|
77
95
|
}
|
|
78
96
|
};
|
|
79
97
|
},
|
|
@@ -39,9 +39,8 @@ Post = ghostBookshelf.Model.extend({
|
|
|
39
39
|
tableName: 'posts',
|
|
40
40
|
|
|
41
41
|
actionsCollectCRUD: true,
|
|
42
|
-
actionsResourceType:
|
|
43
|
-
|
|
44
|
-
},
|
|
42
|
+
actionsResourceType: 'post',
|
|
43
|
+
actionsExtraContext: ['type'],
|
|
45
44
|
|
|
46
45
|
/**
|
|
47
46
|
* @NOTE
|
|
@@ -97,6 +97,10 @@ Settings = ghostBookshelf.Model.extend({
|
|
|
97
97
|
|
|
98
98
|
tableName: 'settings',
|
|
99
99
|
|
|
100
|
+
actionsCollectCRUD: true,
|
|
101
|
+
actionsResourceType: 'setting',
|
|
102
|
+
actionsExtraContext: ['key', 'group'],
|
|
103
|
+
|
|
100
104
|
emitChange: function emitChange(event, options) {
|
|
101
105
|
const eventToTrigger = 'settings' + '.' + event;
|
|
102
106
|
ghostBookshelf.Model.prototype.emitChange.bind(this)(this, eventToTrigger, options);
|
|
@@ -65,7 +65,10 @@ User = ghostBookshelf.Model.extend({
|
|
|
65
65
|
password: security.identifier.uid(50),
|
|
66
66
|
visibility: 'public',
|
|
67
67
|
status: 'active',
|
|
68
|
-
comment_notifications: true
|
|
68
|
+
comment_notifications: true,
|
|
69
|
+
free_member_signup_notification: true,
|
|
70
|
+
paid_subscription_started_notification: true,
|
|
71
|
+
paid_subscription_canceled_notification: false
|
|
69
72
|
};
|
|
70
73
|
},
|
|
71
74
|
|