ghost 4.22.1 → 4.23.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 (128) hide show
  1. package/.c8rc.json +24 -0
  2. package/.eslintrc.js +6 -0
  3. package/Gruntfile.js +1 -1
  4. package/content/public/README.md +3 -0
  5. package/core/boot.js +20 -12
  6. package/core/built/assets/{chunk.3.1148677ff3b78e5aeaee.js → chunk.3.8f95b516d88ff4eec64c.js} +18 -18
  7. package/core/built/assets/{ghost-dark-684ad238e1a858c7cb5be6988de7c6f5.css → ghost-dark-42cf6e0c730578940ec069bda45aea41.css} +1 -1
  8. package/core/built/assets/{ghost.min-f7037eca328f4d4eb99f0309c19c9bae.js → ghost.min-cccc107e881b74c7aaf1a73e1e5e0dee.js} +189 -143
  9. package/core/built/assets/{ghost.min-66e08535f8bb797a8c40e0a2b31f1e9e.css → ghost.min-fcf6a0738421f86c47c55f20d00c5ba9.css} +1 -1
  10. package/core/built/assets/icons/powered-by-tenor.svg +35 -0
  11. package/core/built/assets/icons/tenor.svg +7 -0
  12. package/core/built/assets/{vendor.min-7c8fdd90f7ecd2e94328a07ea3b64608.js → vendor.min-c9002845b6c30ac978abdadde9f33d7c.js} +8189 -7601
  13. package/core/frontend/apps/amp/lib/views/amp.hbs +104 -0
  14. package/core/frontend/apps/private-blogging/lib/router.js +1 -1
  15. package/core/frontend/services/card-assets/service.js +21 -13
  16. package/core/frontend/services/routing/CollectionRouter.js +4 -5
  17. package/core/frontend/services/routing/EmailRouter.js +1 -1
  18. package/core/frontend/services/routing/ParentRouter.js +0 -8
  19. package/core/frontend/services/routing/PreviewRouter.js +1 -1
  20. package/core/frontend/services/routing/StaticPagesRouter.js +1 -1
  21. package/core/frontend/services/routing/StaticRoutesRouter.js +4 -4
  22. package/core/frontend/services/routing/TaxonomyRouter.js +3 -3
  23. package/core/frontend/services/routing/{middlewares → middleware}/index.js +0 -0
  24. package/core/frontend/services/routing/{middlewares → middleware}/page-param.js +0 -0
  25. package/core/frontend/services/routing/router-manager.js +7 -2
  26. package/core/frontend/services/rss/generate-feed.js +2 -1
  27. package/core/frontend/src/cards/css/bookmark.css +66 -48
  28. package/core/frontend/src/cards/css/button.css +30 -0
  29. package/core/frontend/src/cards/css/callout.css +50 -0
  30. package/core/frontend/src/cards/css/gallery.css +8 -13
  31. package/core/frontend/src/cards/css/nft.css +94 -0
  32. package/core/frontend/src/cards/css/toggle.css +47 -0
  33. package/core/frontend/src/cards/js/toggle.js +16 -0
  34. package/core/frontend/web/middleware/serve-public-file.js +14 -8
  35. package/core/frontend/web/routes.js +0 -1
  36. package/core/frontend/web/site.js +15 -12
  37. package/core/server/adapters/storage/LocalFilesStorage.js +17 -0
  38. package/core/server/adapters/storage/LocalImagesStorage.js +1 -0
  39. package/core/server/adapters/storage/LocalMediaStorage.js +2 -1
  40. package/core/server/adapters/storage/LocalStorageBase.js +30 -5
  41. package/core/server/api/canary/authentication.js +1 -1
  42. package/core/server/api/canary/files.js +19 -0
  43. package/core/server/api/canary/index.js +4 -0
  44. package/core/server/api/canary/media.js +25 -5
  45. package/core/server/api/canary/oembed.js +3 -0
  46. package/core/server/api/canary/utils/serializers/input/index.js +4 -0
  47. package/core/server/api/canary/utils/serializers/input/media.js +8 -0
  48. package/core/server/api/canary/utils/serializers/output/config.js +21 -14
  49. package/core/server/api/canary/utils/serializers/output/files.js +27 -0
  50. package/core/server/api/canary/utils/serializers/output/index.js +4 -0
  51. package/core/server/api/canary/utils/serializers/output/media.js +9 -0
  52. package/core/server/api/canary/utils/validators/input/files.js +7 -0
  53. package/core/server/api/canary/utils/validators/input/index.js +4 -0
  54. package/core/server/api/canary/utils/validators/input/media.js +4 -0
  55. package/core/server/api/v2/authentication.js +1 -1
  56. package/core/server/api/v3/authentication.js +1 -1
  57. package/core/server/data/db/connection.js +7 -0
  58. package/core/server/data/importer/importers/data/data-importer.js +3 -3
  59. package/core/server/data/migrations/init/2-create-fixtures.js +3 -20
  60. package/core/server/data/migrations/versions/1.21/1-add-contributor-role.js +5 -5
  61. package/core/server/data/migrations/versions/2.15/2-insert-zapier-integration.js +3 -3
  62. package/core/server/data/migrations/versions/2.2/3-insert-admin-integration-role.js +5 -5
  63. package/core/server/data/migrations/versions/2.27/1-insert-ghost-db-backup-role.js +5 -6
  64. package/core/server/data/migrations/versions/2.27/2-insert-db-backup-integration.js +3 -4
  65. package/core/server/data/migrations/versions/2.28/3-insert-ghost-scheduler-role.js +7 -7
  66. package/core/server/data/migrations/versions/2.28/4-insert-scheduler-integration.js +3 -3
  67. package/core/server/data/migrations/versions/4.23/01-truncate-offer-names.js +58 -0
  68. package/core/server/data/schema/fixtures/fixture-manager.js +340 -0
  69. package/core/server/data/schema/fixtures/index.js +8 -2
  70. package/core/server/services/mega/post-email-serializer.js +5 -1
  71. package/core/server/services/mega/segment-parser.js +1 -2
  72. package/core/server/services/mega/template.js +69 -1
  73. package/core/server/services/nft-oembed.js +57 -0
  74. package/core/server/services/oembed.js +161 -126
  75. package/core/server/services/public-config/config.js +2 -1
  76. package/core/server/services/stripe/index.js +4 -2
  77. package/core/server/services/url/Resource.js +1 -1
  78. package/core/server/services/url/Resources.js +36 -23
  79. package/core/server/services/url/UrlGenerator.js +23 -20
  80. package/core/server/services/url/UrlService.js +123 -21
  81. package/core/server/services/url/Urls.js +7 -2
  82. package/core/server/services/url/index.js +9 -1
  83. package/core/server/web/admin/app.js +6 -6
  84. package/core/server/web/admin/views/default-prod.html +4 -4
  85. package/core/server/web/admin/views/default.html +4 -4
  86. package/core/server/web/api/app.js +1 -1
  87. package/core/server/web/api/canary/admin/app.js +4 -4
  88. package/core/server/web/api/canary/admin/middleware.js +6 -6
  89. package/core/server/web/api/canary/admin/routes.js +20 -5
  90. package/core/server/web/api/canary/content/app.js +4 -4
  91. package/core/server/web/api/canary/content/middleware.js +3 -3
  92. package/core/server/web/api/middleware/cors.js +7 -7
  93. package/core/server/web/api/v2/admin/app.js +4 -4
  94. package/core/server/web/api/v2/admin/middleware.js +6 -6
  95. package/core/server/web/api/v2/admin/routes.js +5 -5
  96. package/core/server/web/api/v2/content/app.js +4 -4
  97. package/core/server/web/api/v2/content/middleware.js +3 -3
  98. package/core/server/web/api/v3/admin/app.js +4 -4
  99. package/core/server/web/api/v3/admin/middleware.js +6 -6
  100. package/core/server/web/api/v3/admin/routes.js +5 -5
  101. package/core/server/web/api/v3/content/app.js +4 -4
  102. package/core/server/web/api/v3/content/middleware.js +3 -3
  103. package/core/server/web/members/app.js +7 -7
  104. package/core/server/web/oauth/app.js +1 -1
  105. package/core/server/web/parent/app.js +2 -3
  106. package/core/server/web/parent/frontend.js +1 -1
  107. package/core/server/web/shared/index.js +2 -2
  108. package/core/server/web/shared/{middlewares → middleware}/api/index.js +0 -0
  109. package/core/server/web/shared/{middlewares → middleware}/api/spam-prevention.js +0 -0
  110. package/core/server/web/shared/{middlewares → middleware}/brute.js +0 -0
  111. package/core/server/web/shared/{middlewares → middleware}/cache-control.js +0 -0
  112. package/core/server/web/shared/{middlewares → middleware}/error-handler.js +0 -0
  113. package/core/server/web/shared/{middlewares → middleware}/index.js +0 -0
  114. package/core/server/web/shared/{middlewares → middleware}/maintenance.js +0 -0
  115. package/core/server/web/shared/{middlewares → middleware}/pretty-urls.js +0 -0
  116. package/core/server/web/shared/{middlewares → middleware}/uncapitalise.js +0 -0
  117. package/core/server/web/shared/{middlewares → middleware}/url-redirects.js +0 -0
  118. package/core/shared/config/defaults.json +10 -2
  119. package/core/shared/config/helpers.js +44 -0
  120. package/core/shared/config/loader.js +1 -1
  121. package/core/shared/config/overrides.json +2 -2
  122. package/core/shared/labs.js +8 -1
  123. package/loggingrc.js +19 -20
  124. package/package.json +35 -35
  125. package/urls.json +597 -0
  126. package/yarn.lock +655 -339
  127. package/core/server/data/schema/fixtures/utils.js +0 -321
  128. package/core/server/web/parent/vhost-utils.js +0 -39
@@ -1,321 +0,0 @@
1
- // # Fixture Utils
2
- // Standalone file which can be required to help with advanced operations on the fixtures.json file
3
- const _ = require('lodash');
4
-
5
- const Promise = require('bluebird');
6
- const logging = require('@tryghost/logging');
7
- const models = require('../../../models');
8
- const baseUtils = require('../../../models/base/utils');
9
- const {sequence} = require('@tryghost/promise');
10
- const moment = require('moment');
11
- const fixtures = require('./fixtures');
12
-
13
- /**
14
- * ### Match Func
15
- * Figures out how to match across various combinations of keys and values.
16
- * Match can be a string or an array containing 2 strings
17
- * Key and Value are the values to be found
18
- * Value can also be an array, in which case we look for a match in the array.
19
- * @api private
20
- * @param {String|Array} match
21
- * @param {String|Integer} key
22
- * @param {String|Array} [value]
23
- * @returns {Function} matching function
24
- */
25
- const matchFunc = function matchFunc(match, key, value) {
26
- if (_.isArray(match)) {
27
- return function (item) {
28
- let valueTest = true;
29
-
30
- if (_.isArray(value)) {
31
- valueTest = value.indexOf(item.get(match[1])) > -1;
32
- } else if (value !== 'all') {
33
- valueTest = item.get(match[1]) === value;
34
- }
35
-
36
- return item.get(match[0]) === key && valueTest;
37
- };
38
- }
39
-
40
- return function (item) {
41
- key = key === 0 && value ? value : key;
42
- return item.get(match) === key;
43
- };
44
- };
45
-
46
- const matchObj = function matchObj(match, item) {
47
- const matchedObj = {};
48
-
49
- if (_.isArray(match)) {
50
- _.each(match, (matchProp) => {
51
- matchedObj[matchProp] = item.get(matchProp);
52
- });
53
- } else {
54
- matchedObj[match] = item.get(match);
55
- }
56
-
57
- return matchedObj;
58
- };
59
-
60
- /**
61
- * ### Fetch Relation Data
62
- * Before we build relations we need to fetch all of the models from both sides so that we can
63
- * use filter and find to quickly locate the correct models.
64
- * @api private
65
- * @param {{from, to, entries}} relation
66
- * @returns {Promise<*>}
67
- */
68
- const fetchRelationData = function fetchRelationData(relation, options) {
69
- const fromOptions = _.extend({}, options, {withRelated: [relation.from.relation]});
70
-
71
- const props = {
72
- from: models[relation.from.model].findAll(fromOptions),
73
- to: models[relation.to.model].findAll(options)
74
- };
75
-
76
- return Promise.props(props);
77
- };
78
-
79
- /*
80
- * Find methods - use the local fixtures
81
- */
82
-
83
- /**
84
- * ### Find Model Fixture
85
- * Finds a model fixture based on model name
86
- * @api private
87
- * @param {String} modelName
88
- * @returns {Object} model fixture
89
- */
90
- const findModelFixture = function findModelFixture(modelName) {
91
- return _.find(fixtures.models, (modelFixture) => {
92
- return modelFixture.name === modelName;
93
- });
94
- };
95
-
96
- /**
97
- * ### Find Model Fixture Entry
98
- * Find a single model fixture entry by model name & a matching expression for the FIND function
99
- * @param {String} modelName
100
- * @param {String|Object|Function} matchExpr
101
- * @returns {Object} model fixture entry
102
- */
103
- const findModelFixtureEntry = function findModelFixtureEntry(modelName, matchExpr) {
104
- return _.find(findModelFixture(modelName).entries, matchExpr);
105
- };
106
-
107
- /**
108
- * ### Find Model Fixtures
109
- * Find a model fixture name & a matching expression for the FILTER function
110
- * @param {String} modelName
111
- * @param {String|Object|Function} matchExpr
112
- * @returns {Object} model fixture
113
- */
114
- const findModelFixtures = function findModelFixtures(modelName, matchExpr) {
115
- const foundModel = _.cloneDeep(findModelFixture(modelName));
116
- foundModel.entries = _.filter(foundModel.entries, matchExpr);
117
- return foundModel;
118
- };
119
-
120
- /**
121
- * ### Find Relation Fixture
122
- * Find a relation fixture by from & to models
123
- * @api private
124
- * @param {String} from
125
- * @param {String} to
126
- * @returns {Object} relation fixture
127
- */
128
- const findRelationFixture = function findRelationFixture(from, to) {
129
- return _.find(fixtures.relations, (relation) => {
130
- return relation.from.model === from && relation.to.model === to;
131
- });
132
- };
133
-
134
- /**
135
- * ### Find Permission Relations For Object
136
- * Specialist function can return the permission relation fixture with only entries for a particular object.model
137
- * @param {String} objName
138
- * @returns {Object} fixture relation
139
- */
140
- const findPermissionRelationsForObject = function findPermissionRelationsForObject(objName, role) {
141
- // Make a copy and delete any entries we don't want
142
- const foundRelation = _.cloneDeep(findRelationFixture('Role', 'Permission'));
143
-
144
- _.each(foundRelation.entries, (entry, key) => {
145
- _.each(entry, (perm, obj) => {
146
- if (obj !== objName) {
147
- delete entry[obj];
148
- }
149
- });
150
-
151
- if (_.isEmpty(entry) || (role && role !== key)) {
152
- delete foundRelation.entries[key];
153
- }
154
- });
155
-
156
- return foundRelation;
157
- };
158
-
159
- /*
160
- * Add and Remove Functions, require access to models
161
- */
162
-
163
- /**
164
- * ### Add Fixtures for Model
165
- * Takes a model fixture, with a name and some entries and processes these
166
- * into a sequence of promises to get each fixture added.
167
- *
168
- * @param {{name, entries}} modelFixture
169
- * @returns {Promise<any>}
170
- */
171
- const addFixturesForModel = async function addFixturesForModel(modelFixture, options = {}) {
172
- // Clone the fixtures as they get changed in this function.
173
- // The initial blog posts will be added a `published_at` property, which
174
- // would change the fixturesHash.
175
- modelFixture = _.cloneDeep(modelFixture);
176
- // The Post model fixtures need a `published_at` date, where at least the seconds
177
- // are different, otherwise `prev_post` and `next_post` helpers won't workd with
178
- // them.
179
- if (modelFixture.name === 'Post') {
180
- _.forEach(modelFixture.entries, (post, index) => {
181
- if (!post.published_at) {
182
- post.published_at = moment().add(index, 'seconds');
183
- }
184
- });
185
- }
186
-
187
- const results = await Promise.mapSeries(modelFixture.entries, async (entry) => {
188
- let data = {};
189
-
190
- // CASE: if id is specified, only query by id
191
- if (entry.id) {
192
- data.id = entry.id;
193
- } else if (entry.slug) {
194
- data.slug = entry.slug;
195
- } else {
196
- data = _.cloneDeep(entry);
197
- }
198
-
199
- if (modelFixture.name === 'Post') {
200
- data.status = 'all';
201
- }
202
-
203
- const found = await models[modelFixture.name].findOne(data, options);
204
- if (!found) {
205
- return models[modelFixture.name].add(entry, options);
206
- }
207
- });
208
-
209
- return {expected: modelFixture.entries.length, done: _.compact(results).length};
210
- };
211
-
212
- /**
213
- * ## Add Fixtures for Relation
214
- * Takes a relation fixtures object, with a from, to and some entries and processes these
215
- * into a sequence of promises, to get each fixture added.
216
- *
217
- * @param {{from, to, entries}} relationFixture
218
- * @returns {Promise<any>}
219
- */
220
- const addFixturesForRelation = async function addFixturesForRelation(relationFixture, options) {
221
- const ops = [];
222
- let max = 0;
223
-
224
- const data = await fetchRelationData(relationFixture, options);
225
-
226
- _.each(relationFixture.entries, (entry, key) => {
227
- const fromItem = data.from.find(matchFunc(relationFixture.from.match, key));
228
-
229
- // CASE: You add new fixtures e.g. a new role in a new release.
230
- // As soon as an **older** migration script wants to add permissions for any resource, it iterates over the
231
- // permissions for each role. But if the role does not exist yet, it won't find the matching db entry and breaks.
232
- if (!fromItem) {
233
- logging.warn('Skip: Target database entry not found for key: ' + key);
234
- return Promise.resolve();
235
- }
236
-
237
- _.each(entry, (value, entryKey) => {
238
- let toItems = data.to.filter(matchFunc(relationFixture.to.match, entryKey, value));
239
- max += toItems.length;
240
-
241
- // Remove any duplicates that already exist in the collection
242
- toItems = _.reject(toItems, (item) => {
243
- return fromItem
244
- .related(relationFixture.from.relation)
245
- .find((model) => {
246
- const objectToMatch = matchObj(relationFixture.to.match, item);
247
- return Object.keys(objectToMatch).every((keyToCheck) => {
248
- return model.get(keyToCheck) === objectToMatch[keyToCheck];
249
- });
250
- });
251
- });
252
-
253
- if (toItems && toItems.length > 0) {
254
- ops.push(function addRelationItems() {
255
- return baseUtils.attach(
256
- models[relationFixture.from.Model || relationFixture.from.model],
257
- fromItem.id,
258
- relationFixture.from.relation,
259
- toItems,
260
- options
261
- );
262
- });
263
- }
264
- });
265
- });
266
-
267
- const result = await sequence(ops);
268
- return {expected: max, done: _(result).map('length').sum()};
269
- };
270
-
271
- const removeFixturesForModel = async function removeFixturesForModel(modelFixture, options) {
272
- const results = await Promise.mapSeries(modelFixture.entries, async (entry) => {
273
- const found = models[modelFixture.name].findOne(entry.id ? {id: entry.id} : entry, options);
274
- if (found) {
275
- return models[modelFixture.name].destroy(_.extend(options, {id: found.id}));
276
- }
277
- });
278
-
279
- return {expected: modelFixture.entries.length, done: results.length};
280
- };
281
-
282
- const removeFixturesForRelation = async function removeFixturesForRelation(relationFixture, options) {
283
- const data = await fetchRelationData(relationFixture, options);
284
- const ops = [];
285
-
286
- _.each(relationFixture.entries, (entry, key) => {
287
- const fromItem = data.from.find(matchFunc(relationFixture.from.match, key));
288
-
289
- _.each(entry, (value, entryKey) => {
290
- const toItems = data.to.filter(matchFunc(relationFixture.to.match, entryKey, value));
291
-
292
- if (toItems && toItems.length > 0) {
293
- ops.push(function detachRelation() {
294
- return baseUtils.detach(
295
- models[relationFixture.from.Model || relationFixture.from.model],
296
- fromItem.id,
297
- relationFixture.from.relation,
298
- toItems,
299
- options
300
- );
301
- });
302
- }
303
- });
304
- });
305
-
306
- return await sequence(ops);
307
- };
308
-
309
- module.exports = {
310
- // find
311
- findModelFixtureEntry: findModelFixtureEntry,
312
- findModelFixtures: findModelFixtures,
313
- findRelationFixture: findRelationFixture,
314
- findPermissionRelationsForObject: findPermissionRelationsForObject,
315
-
316
- // add / remove
317
- addFixturesForModel: addFixturesForModel,
318
- addFixturesForRelation: addFixturesForRelation,
319
- removeFixturesForModel: removeFixturesForModel,
320
- removeFixturesForRelation: removeFixturesForRelation
321
- };
@@ -1,39 +0,0 @@
1
- const config = require('../../../shared/config');
2
- const escapeRegExp = require('lodash/escapeRegExp');
3
- const {URL} = require('url');
4
-
5
- const DEFAULT_HOST_ARG = /.*/;
6
-
7
- const getHostsFromConfig = () => {
8
- const frontendHost = new URL(config.getSiteUrl()).hostname;
9
-
10
- const backendHost = config.getAdminUrl() ? (new URL(config.getAdminUrl()).hostname) : '';
11
- const hasSeparateBackendHost = backendHost && backendHost !== frontendHost;
12
-
13
- return {
14
- backendHost,
15
- hasSeparateBackendHost
16
- };
17
- };
18
-
19
- /**
20
- *
21
- * @returns {string|RegExp}
22
- */
23
- module.exports.getBackendHostArg = () => {
24
- const {backendHost, hasSeparateBackendHost} = getHostsFromConfig();
25
-
26
- // with a separate admin url only serve on that host, otherwise serve on all hosts
27
- return (hasSeparateBackendHost) && backendHost ? backendHost : DEFAULT_HOST_ARG;
28
- };
29
-
30
- /**
31
- *
32
- * @returns {string|RegExp}
33
- */
34
- module.exports.getFrontendHostArg = () => {
35
- const {backendHost, hasSeparateBackendHost} = getHostsFromConfig();
36
-
37
- // with a separate admin url we adjust the frontend vhost to exclude requests to that host, otherwise serve on all hosts
38
- return (hasSeparateBackendHost && backendHost) ? new RegExp(`^(?!${escapeRegExp(backendHost)}).*`) : DEFAULT_HOST_ARG;
39
- };