ghost 5.8.1 → 5.9.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.
Files changed (117) hide show
  1. package/components/tryghost-adapter-manager-0.0.0.tgz +0 -0
  2. package/components/tryghost-api-framework-0.0.0.tgz +0 -0
  3. package/components/tryghost-bootstrap-socket-0.0.0.tgz +0 -0
  4. package/components/tryghost-custom-theme-settings-service-0.0.0.tgz +0 -0
  5. package/components/tryghost-email-analytics-provider-mailgun-0.0.0.tgz +0 -0
  6. package/components/tryghost-email-analytics-service-0.0.0.tgz +0 -0
  7. package/components/tryghost-job-manager-0.0.0.tgz +0 -0
  8. package/components/tryghost-mailgun-client-0.0.0.tgz +0 -0
  9. package/components/tryghost-member-analytics-service-0.0.0.tgz +0 -0
  10. package/components/tryghost-members-api-0.0.0.tgz +0 -0
  11. package/components/tryghost-members-importer-0.0.0.tgz +0 -0
  12. package/components/tryghost-members-offers-0.0.0.tgz +0 -0
  13. package/components/tryghost-members-payments-0.0.0.tgz +0 -0
  14. package/components/tryghost-members-ssr-0.0.0.tgz +0 -0
  15. package/components/tryghost-members-stripe-service-0.0.0.tgz +0 -0
  16. package/components/tryghost-minifier-0.0.0.tgz +0 -0
  17. package/components/tryghost-mw-cache-control-0.0.0.tgz +0 -0
  18. package/components/tryghost-mw-error-handler-0.0.0.tgz +0 -0
  19. package/components/tryghost-package-json-0.0.0.tgz +0 -0
  20. package/components/tryghost-session-service-0.0.0.tgz +0 -0
  21. package/components/tryghost-settings-path-manager-0.0.0.tgz +0 -0
  22. package/components/tryghost-update-check-service-0.0.0.tgz +0 -0
  23. package/content/themes/casper/README.md +1 -1
  24. package/content/themes/casper/assets/built/portal.min.js +3 -0
  25. package/content/themes/casper/assets/built/screen.css +1 -1
  26. package/content/themes/casper/assets/built/screen.css.map +1 -1
  27. package/content/themes/casper/assets/css/screen.css +119 -37
  28. package/content/themes/casper/package.json +3 -3
  29. package/content/themes/casper/partials/post-card.hbs +3 -1
  30. package/content/themes/casper/post.hbs +7 -7
  31. package/content/themes/casper/yarn.lock +69 -68
  32. package/core/boot.js +2 -0
  33. package/core/built/admin/assets/{chunk.143.904e017ad397bb681e9d.js → chunk.143.e35fdb482bc822313f0c.js} +5 -5
  34. package/core/built/admin/assets/{chunk.178.9541bdb92bded29cd60d.js → chunk.178.1d381d687652f2597fe2.js} +4 -4
  35. package/core/built/admin/assets/{chunk.351.cbc224ca65c14ef5322d.js → chunk.351.73f27952f867334a8228.js} +3 -3
  36. package/core/built/admin/assets/{chunk.351.cbc224ca65c14ef5322d.js.LICENSE.txt → chunk.351.73f27952f867334a8228.js.LICENSE.txt} +0 -0
  37. package/core/built/admin/assets/{ghost-b469423d0fbe5e40af17b560f7e3cead.css → ghost-686c383caa6a3469cefb939ab10e21b6.css} +1 -1
  38. package/core/built/admin/assets/{ghost-dark-bcb6f4517a2dfe23a0a280632bfca00c.css → ghost-dark-6814c399ff5b3d9c8efe2d92bc7ec779.css} +1 -1
  39. package/core/built/admin/assets/{ghost-a66a04418efe85083a3adca0fb16bb52.js → ghost-eca1a709a74b1af277e48aad4e16c9db.js} +94 -92
  40. package/core/built/admin/assets/{vendor-46baf13852f545c6c89756c8e0ccbff2.js → vendor-516c9e43b4aeb92079dc1ab92c9ce492.js} +3 -3
  41. package/core/built/admin/index.html +6 -6
  42. package/core/frontend/helpers/comment_count.js +7 -15
  43. package/core/frontend/helpers/comments.js +4 -16
  44. package/core/frontend/helpers/ghost_head.js +1 -1
  45. package/core/frontend/public/ghost.min.css +1 -1
  46. package/core/frontend/src/comment-counts/js/comment-counts.js +12 -1
  47. package/core/server/api/endpoints/comments-members.js +23 -1
  48. package/core/server/api/endpoints/index.js +52 -52
  49. package/core/server/api/endpoints/utils/serializers/input/comments.js +18 -0
  50. package/core/server/api/endpoints/utils/serializers/input/db.js +1 -1
  51. package/core/server/api/endpoints/utils/serializers/input/index.js +4 -0
  52. package/core/server/api/endpoints/utils/serializers/input/integrations.js +2 -2
  53. package/core/server/api/endpoints/utils/serializers/input/tiers.js +1 -1
  54. package/core/server/api/{shared → endpoints/utils}/serializers/input/utils/settings-filter-type-group-mapper.js +0 -0
  55. package/core/server/api/{shared → endpoints/utils}/serializers/input/utils/settings-key-group-mapper.js +0 -0
  56. package/core/server/api/{shared → endpoints/utils}/serializers/input/utils/settings-key-type-mapper.js +0 -0
  57. package/core/server/api/endpoints/utils/serializers/output/mappers/comments.js +12 -12
  58. package/core/server/api/endpoints/utils/serializers/output/tiers.js +1 -1
  59. package/core/server/api/index.js +0 -2
  60. package/core/server/data/db/connection.js +0 -4
  61. package/core/server/data/importer/importers/data/settings.js +2 -2
  62. package/core/server/data/migrations/versions/5.9/2022-08-09-08-32-added-new-integration-type.js +24 -0
  63. package/core/server/data/schema/clients/mysql.js +0 -15
  64. package/core/server/data/schema/commands.js +0 -9
  65. package/core/server/data/schema/fixtures/fixtures.json +1 -1
  66. package/core/server/data/schema/schema.js +3 -3
  67. package/core/server/models/base/plugins/user-type.js +1 -9
  68. package/core/server/models/comment.js +96 -15
  69. package/core/server/models/label.js +14 -0
  70. package/core/server/models/newsletter.js +21 -0
  71. package/core/server/models/stripe-customer-subscription.js +6 -0
  72. package/core/server/models/tag.js +20 -0
  73. package/core/server/models/user.js +20 -0
  74. package/core/server/run-update-check.js +1 -1
  75. package/core/server/services/auth/api-key/admin.js +1 -1
  76. package/core/server/services/auth/api-key/content.js +1 -1
  77. package/core/server/services/bulk-email/bulk-email-processor.js +18 -11
  78. package/core/server/services/bulk-email/index.js +1 -17
  79. package/core/server/services/comments/controller.js +9 -0
  80. package/core/server/services/comments/email-templates/new-comment-reply.hbs +2 -2
  81. package/core/server/services/comments/email-templates/new-comment.hbs +2 -2
  82. package/core/server/services/comments/email-templates/report.hbs +2 -2
  83. package/core/server/services/comments/service.js +16 -3
  84. package/core/server/services/comments/stats.js +2 -0
  85. package/core/server/services/email-analytics/jobs/fetch-latest.js +1 -1
  86. package/core/server/services/mega/post-email-serializer.js +2 -2
  87. package/core/server/services/permissions/can-this.js +154 -161
  88. package/core/server/services/permissions/parse-context.js +1 -8
  89. package/core/server/services/webhooks/serialize.js +3 -3
  90. package/core/server/web/api/endpoints/admin/routes.js +1 -1
  91. package/core/server/web/api/endpoints/content/routes.js +1 -1
  92. package/core/server/web/api/testmode/jobs/graceful-job.js +1 -1
  93. package/core/server/web/comments/routes.js +2 -1
  94. package/core/server/web/shared/middleware/index.js +1 -1
  95. package/core/shared/config/defaults.json +2 -2
  96. package/core/shared/labs.js +0 -1
  97. package/package.json +31 -29
  98. package/yarn.lock +330 -276
  99. package/core/server/api/README.md +0 -130
  100. package/core/server/api/shared/frame.js +0 -95
  101. package/core/server/api/shared/headers.js +0 -152
  102. package/core/server/api/shared/http.js +0 -127
  103. package/core/server/api/shared/index.js +0 -25
  104. package/core/server/api/shared/pipeline.js +0 -259
  105. package/core/server/api/shared/serializers/handle.js +0 -140
  106. package/core/server/api/shared/serializers/index.js +0 -13
  107. package/core/server/api/shared/serializers/input/all.js +0 -41
  108. package/core/server/api/shared/serializers/input/index.js +0 -5
  109. package/core/server/api/shared/serializers/output/index.js +0 -1
  110. package/core/server/api/shared/utils/index.js +0 -5
  111. package/core/server/api/shared/utils/options.js +0 -23
  112. package/core/server/api/shared/validators/handle.js +0 -68
  113. package/core/server/api/shared/validators/index.js +0 -9
  114. package/core/server/api/shared/validators/input/all.js +0 -213
  115. package/core/server/api/shared/validators/input/index.js +0 -5
  116. package/core/server/services/bulk-email/mailgun.js +0 -122
  117. package/core/server/web/shared/middleware/cache-control.js +0 -43
@@ -1,213 +0,0 @@
1
- const debug = require('@tryghost/debug')('api:shared:validators:input:all');
2
- const _ = require('lodash');
3
- const Promise = require('bluebird');
4
- const tpl = require('@tryghost/tpl');
5
- const {BadRequestError, ValidationError} = require('@tryghost/errors');
6
- const validator = require('@tryghost/validator');
7
-
8
- const messages = {
9
- validationFailed: 'Validation ({validationName}) failed for {key}',
10
- noRootKeyProvided: 'No root key (\'{docName}\') provided.',
11
- invalidIdProvided: 'Invalid id provided.'
12
- };
13
-
14
- const GLOBAL_VALIDATORS = {
15
- id: {matches: /^[a-f\d]{24}$|^1$|me/i},
16
- page: {matches: /^\d+$/},
17
- limit: {matches: /^\d+|all$/},
18
- from: {isDate: true},
19
- to: {isDate: true},
20
- columns: {matches: /^[\w, ]+$/},
21
- order: {matches: /^[a-z0-9_,. ]+$/i},
22
- uuid: {isUUID: true},
23
- slug: {isSlug: true},
24
- name: {},
25
- email: {isEmail: true},
26
- filter: false,
27
- context: false,
28
- forUpdate: false,
29
- transacting: false,
30
- include: false,
31
- formats: false
32
- };
33
-
34
- const validate = (config, attrs) => {
35
- let errors = [];
36
-
37
- _.each(config, (value, key) => {
38
- if (value.required && !attrs[key]) {
39
- errors.push(new ValidationError({
40
- message: tpl(messages.validationFailed, {
41
- validationName: 'FieldIsRequired',
42
- key: key
43
- })
44
- }));
45
- }
46
- });
47
-
48
- _.each(attrs, (value, key) => {
49
- debug(key, value);
50
-
51
- if (GLOBAL_VALIDATORS[key]) {
52
- debug('global validation');
53
- errors = errors.concat(validator.validate(value, key, GLOBAL_VALIDATORS[key]));
54
- }
55
-
56
- if (config && config[key]) {
57
- const allowedValues = Array.isArray(config[key]) ? config[key] : config[key].values;
58
-
59
- if (allowedValues) {
60
- debug('ctrl validation');
61
-
62
- // CASE: we allow e.g. `formats=`
63
- if (!value || !value.length) {
64
- return;
65
- }
66
-
67
- const valuesAsArray = Array.isArray(value) ? value : value.trim().toLowerCase().split(',');
68
- const unallowedValues = _.filter(valuesAsArray, (valueToFilter) => {
69
- return !allowedValues.includes(valueToFilter);
70
- });
71
-
72
- if (unallowedValues.length) {
73
- // CASE: we do not error for invalid includes, just silently remove
74
- if (key === 'include') {
75
- attrs.include = valuesAsArray.filter(x => allowedValues.includes(x));
76
- return;
77
- }
78
-
79
- errors.push(new ValidationError({
80
- message: tpl(messages.validationFailed, {
81
- validationName: 'AllowedValues',
82
- key: key
83
- })
84
- }));
85
- }
86
- }
87
- }
88
- });
89
-
90
- return errors;
91
- };
92
-
93
- module.exports = {
94
- all(apiConfig, frame) {
95
- debug('validate all');
96
-
97
- let validationErrors = validate(apiConfig.options, frame.options);
98
-
99
- if (!_.isEmpty(validationErrors)) {
100
- return Promise.reject(validationErrors[0]);
101
- }
102
-
103
- return Promise.resolve();
104
- },
105
-
106
- browse(apiConfig, frame) {
107
- debug('validate browse');
108
-
109
- let validationErrors = [];
110
-
111
- if (frame.data) {
112
- validationErrors = validate(apiConfig.data, frame.data);
113
- }
114
-
115
- if (!_.isEmpty(validationErrors)) {
116
- return Promise.reject(validationErrors[0]);
117
- }
118
- },
119
-
120
- read() {
121
- debug('validate read');
122
- return this.browse(...arguments);
123
- },
124
-
125
- add(apiConfig, frame) {
126
- debug('validate add');
127
-
128
- // NOTE: this block should be removed completely once JSON Schema validations
129
- // are introduced for all of the endpoints
130
- if (!['posts', 'tags'].includes(apiConfig.docName)) {
131
- if (_.isEmpty(frame.data) || _.isEmpty(frame.data[apiConfig.docName]) || _.isEmpty(frame.data[apiConfig.docName][0])) {
132
- return Promise.reject(new BadRequestError({
133
- message: tpl(messages.noRootKeyProvided, {docName: apiConfig.docName})
134
- }));
135
- }
136
- }
137
-
138
- const jsonpath = require('jsonpath');
139
-
140
- if (apiConfig.data) {
141
- const missedDataProperties = [];
142
- const nilDataProperties = [];
143
-
144
- _.each(apiConfig.data, (value, key) => {
145
- if (jsonpath.query(frame.data[apiConfig.docName][0], key).length === 0) {
146
- missedDataProperties.push(key);
147
- } else if (_.isNil(frame.data[apiConfig.docName][0][key])) {
148
- nilDataProperties.push(key);
149
- }
150
- });
151
-
152
- if (missedDataProperties.length) {
153
- return Promise.reject(new ValidationError({
154
- message: tpl(messages.validationFailed, {
155
- validationName: 'FieldIsRequired',
156
- key: JSON.stringify(missedDataProperties)
157
- })
158
- }));
159
- }
160
-
161
- if (nilDataProperties.length) {
162
- return Promise.reject(new ValidationError({
163
- message: tpl(messages.validationFailed, {
164
- validationName: 'FieldIsInvalid',
165
- key: JSON.stringify(nilDataProperties)
166
- })
167
- }));
168
- }
169
- }
170
- },
171
-
172
- edit(apiConfig, frame) {
173
- debug('validate edit');
174
- const result = this.add(...arguments);
175
-
176
- if (result instanceof Promise) {
177
- return result;
178
- }
179
-
180
- // NOTE: this block should be removed completely once JSON Schema validations
181
- // are introduced for all of the endpoints. `id` property is currently
182
- // stripped from the request body and only the one provided in `options`
183
- // is used in later logic
184
- if (!['posts', 'tags'].includes(apiConfig.docName)) {
185
- if (frame.options.id && frame.data[apiConfig.docName][0].id
186
- && frame.options.id !== frame.data[apiConfig.docName][0].id) {
187
- return Promise.reject(new BadRequestError({
188
- message: tpl(messages.invalidIdProvided)
189
- }));
190
- }
191
- }
192
- },
193
-
194
- changePassword() {
195
- debug('validate changePassword');
196
- return this.add(...arguments);
197
- },
198
-
199
- resetPassword() {
200
- debug('validate resetPassword');
201
- return this.add(...arguments);
202
- },
203
-
204
- setup() {
205
- debug('validate setup');
206
- return this.add(...arguments);
207
- },
208
-
209
- publish() {
210
- debug('validate schedule');
211
- return this.browse(...arguments);
212
- }
213
- };
@@ -1,5 +0,0 @@
1
- module.exports = {
2
- get all() {
3
- return require('./all');
4
- }
5
- };
@@ -1,122 +0,0 @@
1
- const _ = require('lodash');
2
- const {URL} = require('url');
3
- const logging = require('@tryghost/logging');
4
- const configService = require('../../../shared/config');
5
- const settingsCache = require('../../../shared/settings-cache');
6
-
7
- const BATCH_SIZE = 1000;
8
-
9
- function createMailgun(config) {
10
- const mailgun = require('mailgun-js');
11
- const baseUrl = new URL(config.baseUrl);
12
-
13
- return mailgun({
14
- apiKey: config.apiKey,
15
- domain: config.domain,
16
- protocol: baseUrl.protocol,
17
- host: baseUrl.hostname,
18
- port: baseUrl.port,
19
- endpoint: baseUrl.pathname,
20
- retry: 5
21
- });
22
- }
23
-
24
- function getInstance() {
25
- const bulkEmailConfig = configService.get('bulkEmail');
26
- const bulkEmailSetting = {
27
- apiKey: settingsCache.get('mailgun_api_key'),
28
- domain: settingsCache.get('mailgun_domain'),
29
- baseUrl: settingsCache.get('mailgun_base_url')
30
- };
31
- const hasMailgunConfig = !!(bulkEmailConfig && bulkEmailConfig.mailgun);
32
- const hasMailgunSetting = !!(bulkEmailSetting && bulkEmailSetting.apiKey && bulkEmailSetting.baseUrl && bulkEmailSetting.domain);
33
-
34
- if (!hasMailgunConfig && !hasMailgunSetting) {
35
- logging.warn(`Bulk email service is not configured`);
36
- } else {
37
- let mailgunConfig = hasMailgunConfig ? bulkEmailConfig.mailgun : bulkEmailSetting;
38
- return createMailgun(mailgunConfig);
39
- }
40
- return null;
41
- }
42
-
43
- // recipientData format:
44
- // {
45
- // 'test@example.com': {
46
- // name: 'Test User',
47
- // unique_id: '12345abcde',
48
- // unsubscribe_url: 'https://example.com/unsub/me'
49
- // }
50
- // }
51
- function send(message, recipientData, replacements) {
52
- if (recipientData.length > BATCH_SIZE) {
53
- // err - too many recipients
54
- }
55
-
56
- let messageData = {};
57
-
58
- try {
59
- const bulkEmailConfig = configService.get('bulkEmail');
60
- const mailgunInstance = getInstance();
61
-
62
- const messageContent = _.pick(message, 'subject', 'html', 'plaintext');
63
-
64
- // update content to use Mailgun variable syntax for replacements
65
- replacements.forEach((replacement) => {
66
- messageContent[replacement.format] = messageContent[replacement.format].replace(
67
- replacement.match,
68
- `%recipient.${replacement.id}%`
69
- );
70
- });
71
-
72
- messageData = {
73
- to: Object.keys(recipientData),
74
- from: message.from,
75
- 'h:Reply-To': message.replyTo || message.reply_to,
76
- subject: messageContent.subject,
77
- html: messageContent.html,
78
- text: messageContent.plaintext,
79
- 'recipient-variables': recipientData
80
- };
81
-
82
- // add a reference to the original email record for easier mapping of mailgun event -> email
83
- if (message.id) {
84
- messageData['v:email-id'] = message.id;
85
- }
86
-
87
- const tags = ['bulk-email'];
88
- if (bulkEmailConfig && bulkEmailConfig.mailgun && bulkEmailConfig.mailgun.tag) {
89
- tags.push(bulkEmailConfig.mailgun.tag);
90
- }
91
- messageData['o:tag'] = tags;
92
-
93
- if (bulkEmailConfig && bulkEmailConfig.mailgun && bulkEmailConfig.mailgun.testmode) {
94
- messageData['o:testmode'] = true;
95
- }
96
-
97
- // enable tracking if turned on for this email
98
- if (message.track_opens) {
99
- messageData['o:tracking-opens'] = true;
100
- }
101
-
102
- return new Promise((resolve, reject) => {
103
- mailgunInstance.messages().send(messageData, (error, body) => {
104
- if (error || !body) {
105
- return reject(error);
106
- }
107
-
108
- return resolve({
109
- id: body.id
110
- });
111
- });
112
- });
113
- } catch (error) {
114
- return Promise.reject({error, messageData});
115
- }
116
- }
117
-
118
- module.exports = {
119
- BATCH_SIZE,
120
- getInstance,
121
- send
122
- };
@@ -1,43 +0,0 @@
1
- // # CacheControl Middleware
2
- // Usage: cacheControl(profile), where profile is one of 'public' or 'private'
3
- // After: checkIsPrivate
4
- // Before: routes
5
- // App: Admin|Site|API
6
- //
7
- // Allows each app to declare its own default caching rules
8
-
9
- const isString = require('lodash/isString');
10
-
11
- /**
12
- * @param {'public'|'private'} profile Use "private" if you do not want caching
13
- * @param {object} [options]
14
- * @param {number} [options.maxAge] The max-age in seconds to use when profile is "public"
15
- */
16
- const cacheControl = (profile, options = {maxAge: 0}) => {
17
- const profiles = {
18
- public: `public, max-age=${options.maxAge}`,
19
- private: 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'
20
- };
21
-
22
- let output;
23
-
24
- if (isString(profile) && Object.prototype.hasOwnProperty.call(profiles, profile)) {
25
- output = profiles[profile];
26
- }
27
-
28
- /**
29
- * @param {import('express').Request} req
30
- * @param {import('express').Response} res
31
- * @param {() => void} next
32
- *
33
- * @returns {void}
34
- */
35
- return function cacheControlHeaders(req, res, next) {
36
- if (output) {
37
- res.set({'Cache-Control': output});
38
- }
39
- next();
40
- };
41
- };
42
-
43
- module.exports = cacheControl;