ghost 4.18.0 → 4.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +9 -8
- package/Gruntfile.js +1 -1
- package/PRIVACY.md +3 -0
- package/content/adapters/README.md +2 -2
- package/core/boot.js +17 -12
- package/core/bridge.js +9 -1
- package/core/built/assets/{chunk.3.b80d3e1e6b8556aaff3c.js → chunk.3.777d43e2ce954ba8b2f5.js} +25 -25
- package/core/built/assets/codemirror/{codemirror-21a09582262987037db73b152fb35f7c.js → codemirror-d25c379b87ec8b33d54ac7149bc0b6ae.js} +14 -14
- package/core/built/assets/ghost-dark-20e2892d4f30d0d1183c9ac725ea37d0.css +1 -0
- package/core/built/assets/{ghost.min-88d647a008a5b1dd678a89ae1e55c038.js → ghost.min-26e427944e719b616b8dc7fbb3bbd2f9.js} +709 -422
- package/core/built/assets/ghost.min-57e46fd3b1145ecf2cbd185a13611f3b.css +1 -0
- package/core/built/assets/icons/arrow-left-small.svg +0 -4
- package/core/built/assets/icons/paintbrush.svg +10 -1
- package/core/built/assets/icons/post.svg +3 -1
- package/core/built/assets/img/footer-marketplace-bg-572b6c6486a7e26316954d599eaa9f30.png +0 -0
- package/core/built/assets/img/marketing/offers-1-f2e1b653c4d5bb90eea9d7a2862530f9.jpg +0 -0
- package/core/built/assets/img/marketing/offers-2-28a225d34cc39d133748431536961d00.jpg +0 -0
- package/core/built/assets/img/marketing/offers-3-2094c91ab21a16c37fbe6ec16c140160.jpg +0 -0
- package/core/built/assets/img/themes/Alto-f4db5af43ca9771c7ac1f754de3ddf2f.png +0 -0
- package/core/built/assets/img/themes/Bulletin-57d45b992ff0e26e0acdce7ed4cccd67.png +0 -0
- package/core/built/assets/img/themes/Casper-c7e784d7188cc5d7f097d9b6c97b0263.jpg +0 -0
- package/core/built/assets/img/themes/Dawn-be81aa8c8caae8fcfb5d5fbec823fdcc.png +0 -0
- package/core/built/assets/img/themes/Digest-d3467ac22a290e1ad3a543014758286e.png +0 -0
- package/core/built/assets/img/themes/Dope-6f8e0bbc199ce4af9a60859e9e6a74ad.png +0 -0
- package/core/built/assets/img/themes/Ease-9c279ea6cec3c0f1823f81c9dd24b116.png +0 -0
- package/core/built/assets/img/themes/Edge-0258906309e11fd075a1d9880aa09b20.png +0 -0
- package/core/built/assets/img/themes/Edition-d8f508e93bc24bdf2716ae6f8b3d44f8.png +0 -0
- package/core/built/assets/img/themes/Editorial-a25a4a34c04dedd858bd5e05ef388b1c.jpg +0 -0
- package/core/built/assets/img/themes/Journal-accf0031bbae0919900a049061e65a04.png +0 -0
- package/core/built/assets/img/themes/London-3f07efcee9e5bfb9a33827064eb77e70.jpg +0 -0
- package/core/built/assets/img/themes/Massively-06edf00108429f7fb8e65f190fba34fe.jpg +0 -0
- package/core/built/assets/img/themes/Ruby-11a53c62015612f4b3aca8f503121225.png +0 -0
- package/core/built/assets/img/themes/Wave-86e8044c2d76cb57a9030e4c24ac9520.png +0 -0
- package/core/built/assets/simplemde/{simplemde-232f69d126310434489071a1891e6d8b.js → simplemde-3ffc0ec9e9fecf29b9a499db678c9e65.js} +14 -14
- package/core/built/assets/{vendor.min-7dc7cf9c92175ebfb9cea95c120ee8a7.js → vendor.min-af502ac4142871500fc424f6a5a254ec.js} +2206 -1859
- package/core/frontend/apps/amp/lib/router.js +1 -1
- package/core/frontend/helpers/match.js +17 -23
- package/core/frontend/meta/author-url.js +1 -1
- package/core/frontend/meta/url.js +1 -1
- package/core/{server → frontend}/public/favicon.ico +0 -0
- package/core/{server → frontend}/public/ghost.css +0 -0
- package/core/{server → frontend}/public/ghost.min.css +0 -0
- package/core/{server → frontend}/public/robots.txt +0 -0
- package/core/{server → frontend}/public/sitemap.xsl +0 -0
- package/core/frontend/services/proxy.js +1 -1
- package/core/frontend/services/rendering.js +1 -1
- package/core/frontend/services/routing/CollectionRouter.js +3 -49
- package/core/frontend/services/routing/ParentRouter.js +1 -4
- package/core/frontend/services/routing/StaticPagesRouter.js +3 -5
- package/core/frontend/services/routing/StaticRoutesRouter.js +4 -6
- package/core/frontend/services/routing/TaxonomyRouter.js +4 -5
- package/core/frontend/services/routing/controllers/collection.js +2 -2
- package/core/frontend/services/routing/controllers/email-post.js +2 -2
- package/core/frontend/services/routing/controllers/entry.js +2 -2
- package/core/frontend/services/routing/controllers/preview.js +2 -2
- package/core/frontend/services/routing/index.js +6 -12
- package/core/frontend/services/routing/registry.js +13 -0
- package/core/frontend/services/routing/router-manager.js +185 -0
- package/core/frontend/services/rss/generate-feed.js +2 -2
- package/core/frontend/services/theme-engine/i18n/i18n.js +267 -28
- package/core/frontend/services/theme-engine/i18n/index.js +1 -1
- package/core/frontend/services/theme-engine/i18n/theme-i18n.js +73 -0
- package/core/frontend/web/index.js +1 -0
- package/core/{server/web/site → frontend/web}/middleware/handle-image-sizes.js +4 -4
- package/core/{server/web/site → frontend/web}/middleware/index.js +0 -0
- package/core/{server/web/site → frontend/web}/middleware/redirect-ghost-to-admin.js +3 -3
- package/core/{server/web/site → frontend/web}/middleware/serve-favicon.js +6 -6
- package/core/{server/web/site → frontend/web}/middleware/serve-public-file.js +2 -2
- package/core/{server/web/site → frontend/web}/middleware/static-theme.js +3 -3
- package/core/frontend/web/routes.js +13 -0
- package/core/{server/web/site/app.js → frontend/web/site.js} +12 -16
- package/core/server/adapters/storage/LocalFileStorage.js +35 -39
- package/core/server/adapters/storage/index.js +12 -2
- package/core/server/api/canary/custom-theme-settings.js +2 -2
- package/core/server/api/canary/images.js +1 -1
- package/core/server/api/canary/oembed.js +2 -2
- package/core/server/api/canary/offers.js +29 -1
- package/core/server/api/canary/posts-public.js +6 -2
- package/core/server/api/canary/products.js +6 -2
- package/core/server/api/canary/tags-public.js +6 -2
- package/core/server/api/canary/users.js +9 -4
- package/core/server/api/canary/utils/serializers/output/custom-theme-settings.js +2 -2
- package/core/server/api/canary/utils/serializers/output/notifications.js +1 -0
- package/core/server/api/canary/utils/serializers/output/settings.js +2 -3
- package/core/server/api/canary/utils/serializers/output/utils/url.js +1 -1
- package/core/server/api/canary/utils/validators/input/oembed.js +4 -1
- package/core/server/api/canary/utils/validators/input/passwordreset.js +8 -3
- package/core/server/api/canary/utils/validators/input/settings.js +5 -4
- package/core/server/api/canary/utils/validators/input/setup.js +6 -2
- package/core/server/api/canary/utils/validators/input/users.js +6 -2
- package/core/server/api/canary/utils/validators/input/webhooks.js +8 -3
- package/core/server/api/v2/images.js +1 -1
- package/core/server/api/v2/utils/serializers/output/authentication.js +9 -4
- package/core/server/api/v2/utils/serializers/output/notifications.js +1 -0
- package/core/server/api/v2/utils/serializers/output/users.js +5 -3
- package/core/server/api/v2/utils/serializers/output/utils/url.js +1 -1
- package/core/server/api/v2/utils/validators/input/images.js +11 -6
- package/core/server/api/v2/utils/validators/input/invitations.js +14 -6
- package/core/server/api/v2/utils/validators/input/invites.js +6 -2
- package/core/server/api/v2/utils/validators/input/oembed.js +6 -2
- package/core/server/api/v2/utils/validators/input/passwordreset.js +8 -3
- package/core/server/api/v2/utils/validators/input/settings.js +10 -4
- package/core/server/api/v2/utils/validators/input/setup.js +6 -2
- package/core/server/api/v2/utils/validators/input/users.js +5 -2
- package/core/server/api/v3/authentication.js +6 -2
- package/core/server/api/v3/authors-public.js +6 -2
- package/core/server/api/v3/email.js +9 -4
- package/core/server/api/v3/images.js +1 -1
- package/core/server/api/v3/integrations.js +7 -3
- package/core/server/api/v3/invites.js +6 -3
- package/core/server/api/v3/labels.js +10 -5
- package/core/server/api/v3/memberSigninUrls.js +5 -2
- package/core/server/api/v3/oembed.js +2 -2
- package/core/server/api/v3/pages-public.js +5 -2
- package/core/server/api/v3/pages.js +6 -3
- package/core/server/api/v3/posts-public.js +5 -3
- package/core/server/api/v3/posts.js +7 -3
- package/core/server/api/v3/preview.js +5 -3
- package/core/server/api/v3/session.js +7 -3
- package/core/server/api/v3/settings.js +8 -3
- package/core/server/api/v3/slugs.js +5 -4
- package/core/server/api/v3/utils/serializers/output/authentication.js +10 -4
- package/core/server/api/v3/utils/serializers/output/notifications.js +1 -0
- package/core/server/api/v3/utils/serializers/output/settings.js +2 -3
- package/core/server/api/v3/utils/serializers/output/users.js +6 -2
- package/core/server/api/v3/utils/serializers/output/utils/url.js +1 -1
- package/core/server/api/v3/utils/validators/input/images.js +12 -7
- package/core/server/api/v3/utils/validators/input/invitations.js +14 -6
- package/core/server/api/v3/utils/validators/input/invites.js +6 -2
- package/core/server/api/v3/utils/validators/input/oembed.js +6 -2
- package/core/server/api/v3/utils/validators/input/passwordreset.js +8 -3
- package/core/server/api/v3/utils/validators/input/settings.js +5 -4
- package/core/server/api/v3/utils/validators/input/setup.js +6 -2
- package/core/server/api/v3/utils/validators/input/users.js +6 -2
- package/core/server/api/v3/utils/validators/input/webhooks.js +8 -3
- package/core/server/data/exporter/table-lists.js +2 -1
- package/core/server/data/importer/handlers/image.js +1 -1
- package/core/server/data/importer/importers/image.js +1 -1
- package/core/server/data/migrations/init/1-create-tables.js +7 -8
- package/core/server/data/migrations/init/2-create-fixtures.js +8 -8
- package/core/server/data/migrations/versions/4.19/01-add-active-column-to-offers.js +7 -0
- package/core/server/data/migrations/versions/4.19/02-add-offer-redemptions-table.js +8 -0
- package/core/server/data/migrations/versions/4.20/01-remove-offer-redemptions-table.js +19 -0
- package/core/server/data/migrations/versions/4.20/02-remove-offers-table.js +30 -0
- package/core/server/data/migrations/versions/4.20/03-add-offers-table.js +21 -0
- package/core/server/data/migrations/versions/4.20/04-add-offer-redemptions-table.js +9 -0
- package/core/server/data/migrations/versions/4.20/05-remove-not-null-constraint-from-portal-title.js +41 -0
- package/core/server/data/schema/fixtures/utils.js +150 -143
- package/core/server/data/schema/schema.js +15 -3
- package/core/server/frontend/ghost.min.css +1 -0
- package/core/server/lib/image/blog-icon.js +10 -10
- package/core/server/lib/image/image-size.js +5 -5
- package/core/server/lib/image/image-utils.js +4 -4
- package/core/server/lib/image/index.js +1 -2
- package/core/server/lib/mobiledoc.js +3 -2
- package/core/server/models/action.js +7 -4
- package/core/server/models/base/plugins/overrides.js +19 -6
- package/core/server/models/custom-theme-setting.js +56 -1
- package/core/server/models/index.js +4 -45
- package/core/server/models/member.js +5 -0
- package/core/server/models/offer-redemption.js +10 -0
- package/core/server/models/user.js +2 -1
- package/core/server/overrides.js +6 -2
- package/core/server/run-update-check.js +0 -3
- package/core/server/services/adapter-manager/config.js +1 -0
- package/core/server/services/adapter-manager/index.js +9 -5
- package/core/server/services/adapter-manager/options-resolver.js +18 -0
- package/core/server/services/bulk-email/bulk-email-processor.js +6 -2
- package/core/server/services/bulk-email/mailgun.js +1 -1
- package/core/server/services/custom-theme-settings.js +10 -4
- package/core/server/services/invites/index.js +0 -2
- package/core/server/services/invites/invites.js +5 -5
- package/core/server/services/mail/GhostMailer.js +18 -10
- package/core/server/services/mega/mega.js +3 -3
- package/core/server/services/mega/post-email-serializer.js +2 -2
- package/core/server/services/members/api.js +3 -4
- package/core/server/services/members/emails/signin.js +1 -1
- package/core/server/services/members/emails/signup.js +1 -1
- package/core/server/services/members/emails/subscribe.js +1 -1
- package/core/server/services/members/middleware.js +10 -0
- package/core/server/services/members/service.js +2 -1
- package/core/server/services/notifications/index.js +1 -1
- package/core/server/services/notifications/notifications.js +40 -35
- package/core/server/services/oembed.js +4 -9
- package/core/server/services/offers/service.js +16 -6
- package/core/server/services/permissions/public.js +6 -2
- package/core/server/services/route-settings/route-settings.js +1 -1
- package/core/server/services/settings/index.js +3 -1
- package/core/server/services/settings/settings-bread-service.js +42 -20
- package/core/server/services/slack.js +1 -1
- package/core/server/services/themes/activate.js +2 -2
- package/core/server/services/themes/activation-bridge.js +6 -6
- package/core/server/services/themes/storage.js +1 -1
- package/core/{frontend → server}/services/url/Queue.js +0 -0
- package/core/{frontend → server}/services/url/Resource.js +0 -0
- package/core/{frontend → server}/services/url/Resources.js +2 -2
- package/core/{frontend → server}/services/url/UrlGenerator.js +14 -14
- package/core/{frontend → server}/services/url/UrlService.js +12 -15
- package/core/{frontend → server}/services/url/Urls.js +1 -1
- package/core/{frontend → server}/services/url/configs/canary.js +0 -0
- package/core/{frontend → server}/services/url/configs/v2.js +0 -0
- package/core/{frontend → server}/services/url/configs/v3.js +0 -0
- package/core/{frontend → server}/services/url/configs/v4.js +0 -0
- package/core/{frontend → server}/services/url/index.js +0 -0
- package/core/server/services/xmlrpc.js +1 -1
- package/core/server/update-check.js +3 -3
- package/core/server/web/admin/controller.js +11 -0
- package/core/server/web/admin/views/default-prod.html +4 -4
- package/core/server/web/admin/views/default.html +4 -4
- package/core/server/web/api/app.js +8 -9
- package/core/server/web/members/app.js +1 -0
- package/core/server/web/oauth/app.js +4 -2
- package/core/server/web/parent/backend.js +3 -3
- package/core/server/web/parent/frontend.js +2 -2
- package/core/server/web/shared/middlewares/api/spam-prevention.js +0 -2
- package/core/server/web/shared/middlewares/custom-redirects.js +0 -8
- package/core/server/web/shared/middlewares/maintenance.js +1 -1
- package/core/server/web/well-known.js +10 -10
- package/core/shared/config/defaults.json +2 -2
- package/core/shared/config/overrides.json +1 -1
- package/core/shared/express.js +10 -0
- package/core/shared/html-to-plaintext.js +2 -2
- package/core/shared/labs.js +14 -6
- package/loggingrc.js +10 -0
- package/package.json +60 -57
- package/yarn.lock +1317 -914
- package/core/built/assets/ghost-dark-13627f10941a7dbb2b12e1d41dc51c34.css +0 -1
- package/core/built/assets/ghost.min-d9cbfb4eb2db8915fcd2bf2416218616.css +0 -1
- package/core/built/assets/img/themes/London-68501c8ab797de7f2851cf9ea0a28e26.jpg +0 -0
- package/core/frontend/services/routing/bootstrap.js +0 -114
- package/core/server/public/404-ghost.png +0 -0
- package/core/server/public/404-ghost@2x.png +0 -0
- package/core/server/web/site/index.js +0 -1
- package/core/server/web/site/routes.js +0 -9
- package/core/shared/i18n/i18n.js +0 -312
- package/core/shared/i18n/index.js +0 -6
- package/core/shared/i18n/translations/en.json +0 -675
|
@@ -70,7 +70,6 @@ function createApiInstance(config) {
|
|
|
70
70
|
For your security, the link will expire in 24 hours time.
|
|
71
71
|
|
|
72
72
|
All the best!
|
|
73
|
-
The team at ${siteTitle}
|
|
74
73
|
|
|
75
74
|
---
|
|
76
75
|
|
|
@@ -88,7 +87,6 @@ function createApiInstance(config) {
|
|
|
88
87
|
For your security, the link will expire in 24 hours time.
|
|
89
88
|
|
|
90
89
|
See you soon!
|
|
91
|
-
The team at ${siteTitle}
|
|
92
90
|
|
|
93
91
|
---
|
|
94
92
|
|
|
@@ -122,7 +120,6 @@ function createApiInstance(config) {
|
|
|
122
120
|
For your security, the link will expire in 24 hours time.
|
|
123
121
|
|
|
124
122
|
See you soon!
|
|
125
|
-
The team at ${siteTitle}
|
|
126
123
|
|
|
127
124
|
---
|
|
128
125
|
|
|
@@ -180,6 +177,8 @@ function createApiInstance(config) {
|
|
|
180
177
|
MemberStatusEvent: models.MemberStatusEvent,
|
|
181
178
|
MemberProductEvent: models.MemberProductEvent,
|
|
182
179
|
MemberAnalyticEvent: models.MemberAnalyticEvent,
|
|
180
|
+
OfferRedemption: models.OfferRedemption,
|
|
181
|
+
Offer: models.Offer,
|
|
183
182
|
StripeProduct: models.StripeProduct,
|
|
184
183
|
StripePrice: models.StripePrice,
|
|
185
184
|
Product: models.Product,
|
|
@@ -187,7 +186,7 @@ function createApiInstance(config) {
|
|
|
187
186
|
},
|
|
188
187
|
stripeAPIService: stripeService.api,
|
|
189
188
|
logger: logging,
|
|
190
|
-
|
|
189
|
+
offersAPI: offersService.api,
|
|
191
190
|
labsService: labsService
|
|
192
191
|
});
|
|
193
192
|
|
|
@@ -134,7 +134,7 @@ module.exports = ({siteTitle, email, url, accentColor = '#15212A', siteDomain, s
|
|
|
134
134
|
</tbody>
|
|
135
135
|
</table>
|
|
136
136
|
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; line-height: 25px; margin: 0; margin-bottom: 25px;">For your security, the link will expire in 24 hours time.</p>
|
|
137
|
-
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; line-height: 25px; margin: 0; margin-bottom: 30px;">See you soon
|
|
137
|
+
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; line-height: 25px; margin: 0; margin-bottom: 30px;">See you soon!</p>
|
|
138
138
|
<hr/>
|
|
139
139
|
<p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 5px;">You can also copy & paste this URL into your browser:</p>
|
|
140
140
|
<p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 25px; margin-top:0; color: #3A464C;">${url}</p>
|
|
@@ -134,7 +134,7 @@ module.exports = ({siteTitle, email, url, accentColor = '#15212A', siteDomain, s
|
|
|
134
134
|
</tbody>
|
|
135
135
|
</table>
|
|
136
136
|
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; line-height: 25px; margin: 0; margin-bottom: 25px;">For your security, the link will expire in 24 hours time.</p>
|
|
137
|
-
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; line-height: 25px; margin: 0; margin-bottom: 30px;">See you soon
|
|
137
|
+
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; line-height: 25px; margin: 0; margin-bottom: 30px;">See you soon!</p>
|
|
138
138
|
<hr/>
|
|
139
139
|
<p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; color: #3A464C; font-weight: normal; line-height: 25px; margin: 0; margin-bottom: 5px;">You can also copy & paste this URL into your browser:</p>
|
|
140
140
|
<p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 25px; margin-top: 0; color: #3A464C;">${url}</p>
|
|
@@ -134,7 +134,7 @@ module.exports = ({siteTitle, email, url, accentColor = '#15212A', siteDomain, s
|
|
|
134
134
|
</tbody>
|
|
135
135
|
</table>
|
|
136
136
|
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 25px;">For your security, the link will expire in 24 hours time.</p>
|
|
137
|
-
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 30px;">All the best
|
|
137
|
+
<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 30px;">All the best!</p>
|
|
138
138
|
<hr/>
|
|
139
139
|
<p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; color: #3A464C; font-weight: normal; margin: 0; line-height: 25px; margin-bottom: 5px;">You can also copy & paste this URL into your browser:</p>
|
|
140
140
|
<p style="word-break: break-all; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15px; line-height: 25px; margin-top: 0; color: #3A464C;">${url}</p>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
2
|
const logging = require('@tryghost/logging');
|
|
3
3
|
const membersService = require('./service');
|
|
4
|
+
const offersService = require('../offers/service');
|
|
4
5
|
const urlUtils = require('../../../shared/url-utils');
|
|
5
6
|
const ghostVersion = require('@tryghost/version');
|
|
6
7
|
const settingsCache = require('../../../shared/settings-cache');
|
|
@@ -58,6 +59,14 @@ const getMemberData = async function (req, res) {
|
|
|
58
59
|
}
|
|
59
60
|
};
|
|
60
61
|
|
|
62
|
+
const getOfferData = async function (req, res) {
|
|
63
|
+
const offerId = req.params.id;
|
|
64
|
+
const offer = await offersService.api.getOffer({id: offerId});
|
|
65
|
+
return res.json({
|
|
66
|
+
offers: [offer]
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
61
70
|
const updateMemberData = async function (req, res) {
|
|
62
71
|
try {
|
|
63
72
|
const data = _.pick(req.body, 'name', 'subscribed');
|
|
@@ -222,6 +231,7 @@ module.exports = {
|
|
|
222
231
|
createSessionFromMagicLink,
|
|
223
232
|
getIdentityToken,
|
|
224
233
|
getMemberData,
|
|
234
|
+
getOfferData,
|
|
225
235
|
updateMemberData,
|
|
226
236
|
getMemberSiteData,
|
|
227
237
|
deleteSession,
|
|
@@ -61,7 +61,8 @@ function reconfigureMembersAPI() {
|
|
|
61
61
|
*/
|
|
62
62
|
const fetchImportThreshold = async () => {
|
|
63
63
|
const membersTotal = await membersService.stats.getTotalMembers();
|
|
64
|
-
const
|
|
64
|
+
const configThreshold = _.get(config.get('hostSettings'), 'emailVerification.importThreshold');
|
|
65
|
+
const volumeThreshold = (configThreshold === undefined) ? Infinity : configThreshold;
|
|
65
66
|
const threshold = Math.max(membersTotal, volumeThreshold);
|
|
66
67
|
|
|
67
68
|
return threshold;
|
|
@@ -16,8 +16,7 @@ class Notifications {
|
|
|
16
16
|
*
|
|
17
17
|
* @param {Object} options
|
|
18
18
|
* @param {Object} options.settingsCache - settings cache instance
|
|
19
|
-
* @param {
|
|
20
|
-
* @param {String} options.ghostVersion.full - Ghost instance version in "full" format - major.minor.patch
|
|
19
|
+
* @param {String} options.ghostVersion - Ghost instance version in "full" format - major.minor.patch
|
|
21
20
|
* @param {Object} options.SettingsModel - Ghost's Setting model instance
|
|
22
21
|
*/
|
|
23
22
|
constructor({settingsCache, ghostVersion, SettingsModel}) {
|
|
@@ -75,40 +74,45 @@ class Notifications {
|
|
|
75
74
|
browse({user}) {
|
|
76
75
|
let allNotifications = this.fetchAllNotifications();
|
|
77
76
|
allNotifications = _.orderBy(allNotifications, 'addedAt', 'desc');
|
|
77
|
+
const blogVersion = this.ghostVersion.match(/^(\d+\.)(\d+\.)(\d+)/);
|
|
78
78
|
|
|
79
79
|
allNotifications = allNotifications.filter((notification) => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
80
|
+
if (notification.createdAtVersion && !this.wasSeen(notification, user)) {
|
|
81
|
+
return semver.gte(notification.createdAtVersion, blogVersion[0]);
|
|
82
|
+
} else {
|
|
83
|
+
// NOTE: Filtering by version below is just a patch for bigger problem - notifications are not removed
|
|
84
|
+
// after Ghost update. Logic below should be removed when Ghost upgrade detection
|
|
85
|
+
// is done (https://github.com/TryGhost/Ghost/issues/10236) and notifications are
|
|
86
|
+
// be removed permanently on upgrade event.
|
|
87
|
+
// NOTE: this whole else block can be removed with the first version after Ghost v5.0
|
|
88
|
+
// as the "createdAtVersion" mechanism will be enough to detect major version updates.
|
|
89
|
+
const ghostMajorRegEx = /Ghost (?<major>\d).0 is now available/gi;
|
|
90
|
+
const ghostSec43 = /GHSA-9fgx-q25h-jxrg/gi;
|
|
91
|
+
|
|
92
|
+
// CASE: do not return old release notification
|
|
93
|
+
if (notification.message
|
|
94
|
+
&& (!notification.custom || notification.message.match(ghostMajorRegEx) || notification.message.match(ghostSec43))) {
|
|
95
|
+
let notificationVersion = notification.message.match(/(\d+\.)(\d+\.)(\d+)/);
|
|
96
|
+
|
|
97
|
+
if (!notificationVersion && notification.message.match(ghostSec43)) {
|
|
98
|
+
// Treating "GHSA-9fgx-q25h-jxrg" notification as 4.3.3 because there's no way to detect version
|
|
99
|
+
// from it's message. In the future we should consider having a separate field with version
|
|
100
|
+
// coming with each notification
|
|
101
|
+
notificationVersion = ['4.3.3'];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const ghostMajorMatch = ghostMajorRegEx.exec(notification.message);
|
|
105
|
+
if (ghostMajorMatch && ghostMajorMatch.groups && ghostMajorMatch.groups.major) {
|
|
106
|
+
notificationVersion = `${ghostMajorMatch.groups.major}.0.0`;
|
|
107
|
+
} else if (notificationVersion){
|
|
108
|
+
notificationVersion = notificationVersion[0];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (notificationVersion && blogVersion && semver.gt(notificationVersion, blogVersion[0])) {
|
|
112
|
+
return true;
|
|
113
|
+
} else {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
112
116
|
}
|
|
113
117
|
}
|
|
114
118
|
|
|
@@ -123,7 +127,8 @@ class Notifications {
|
|
|
123
127
|
dismissible: true,
|
|
124
128
|
location: 'bottom',
|
|
125
129
|
status: 'alert',
|
|
126
|
-
id: ObjectId().toHexString()
|
|
130
|
+
id: ObjectId().toHexString(),
|
|
131
|
+
createdAtVersion: this.ghostVersion
|
|
127
132
|
};
|
|
128
133
|
|
|
129
134
|
const overrides = {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const Promise = require('bluebird');
|
|
2
2
|
const errors = require('@tryghost/errors');
|
|
3
|
+
const tpl = require('@tryghost/tpl');
|
|
3
4
|
const {extract, hasProvider} = require('oembed-parser');
|
|
4
5
|
const cheerio = require('cheerio');
|
|
5
6
|
const _ = require('lodash');
|
|
@@ -34,10 +35,6 @@ const findUrlWithProvider = (url) => {
|
|
|
34
35
|
return {url, provider};
|
|
35
36
|
};
|
|
36
37
|
|
|
37
|
-
/**
|
|
38
|
-
* @typedef {(string: string) => string} ITpl
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
38
|
/**
|
|
42
39
|
* @typedef {Object} IConfig
|
|
43
40
|
* @prop {(key: string) => string} get
|
|
@@ -51,19 +48,17 @@ class OEmbed {
|
|
|
51
48
|
/**
|
|
52
49
|
*
|
|
53
50
|
* @param {Object} dependencies
|
|
54
|
-
* @param {ITpl} dependencies.tpl
|
|
55
51
|
* @param {IConfig} dependencies.config
|
|
56
52
|
* @param {IExternalRequest} dependencies.externalRequest
|
|
57
53
|
*/
|
|
58
|
-
constructor({config, externalRequest
|
|
54
|
+
constructor({config, externalRequest}) {
|
|
59
55
|
this.config = config;
|
|
60
56
|
this.externalRequest = externalRequest;
|
|
61
|
-
this.tpl = tpl;
|
|
62
57
|
}
|
|
63
58
|
|
|
64
59
|
unknownProvider(url) {
|
|
65
60
|
return Promise.reject(new errors.ValidationError({
|
|
66
|
-
message:
|
|
61
|
+
message: tpl(messages.unknownProvider),
|
|
67
62
|
context: url
|
|
68
63
|
}));
|
|
69
64
|
}
|
|
@@ -133,7 +128,7 @@ class OEmbed {
|
|
|
133
128
|
}
|
|
134
129
|
|
|
135
130
|
return Promise.reject(new errors.ValidationError({
|
|
136
|
-
message:
|
|
131
|
+
message: tpl(messages.insufficientMetadata),
|
|
137
132
|
context: url
|
|
138
133
|
}));
|
|
139
134
|
}
|
|
@@ -11,33 +11,43 @@ const urlUtils = require('../../../shared/url-utils');
|
|
|
11
11
|
const models = require('../../models');
|
|
12
12
|
|
|
13
13
|
const redirectManager = new DynamicRedirectManager({
|
|
14
|
-
permanentMaxAge: config.get('caching:customRedirects:maxAge')
|
|
15
|
-
|
|
14
|
+
permanentMaxAge: config.get('caching:customRedirects:maxAge'),
|
|
15
|
+
getSubdirectoryURL: (pathname) => {
|
|
16
|
+
return urlUtils.urlJoin(urlUtils.getSubdir(), pathname);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
16
19
|
|
|
17
20
|
module.exports = {
|
|
18
21
|
async init() {
|
|
19
22
|
const offersModule = OffersModule.create({
|
|
20
23
|
OfferModel: models.Offer,
|
|
24
|
+
OfferRedemptionModel: models.OfferRedemption,
|
|
21
25
|
redirectManager: redirectManager,
|
|
22
26
|
stripeAPIService: stripeService.api
|
|
23
27
|
});
|
|
24
28
|
|
|
25
29
|
this.api = offersModule.api;
|
|
26
|
-
this.repository = offersModule.repository;
|
|
27
30
|
|
|
31
|
+
let initCalled = false;
|
|
28
32
|
if (labs.isSet('offers')) {
|
|
29
33
|
// handles setting up redirects
|
|
30
|
-
|
|
34
|
+
const promise = offersModule.init();
|
|
35
|
+
initCalled = true;
|
|
36
|
+
await promise;
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
// TODO: Delete after GA
|
|
34
40
|
let offersEnabled = labs.isSet('offers');
|
|
35
41
|
events.on('settings.labs.edited', async () => {
|
|
36
|
-
if (labs.isSet('offers')
|
|
42
|
+
if (labs.isSet('offers') && !initCalled) {
|
|
43
|
+
const promise = offersModule.init();
|
|
44
|
+
initCalled = true;
|
|
45
|
+
await promise;
|
|
46
|
+
} else if (labs.isSet('offers') !== offersEnabled) {
|
|
37
47
|
offersEnabled = labs.isSet('offers');
|
|
38
48
|
|
|
39
49
|
if (offersEnabled) {
|
|
40
|
-
const offers = await this.api.listOffers();
|
|
50
|
+
const offers = await this.api.listOffers({});
|
|
41
51
|
for (const offer of offers) {
|
|
42
52
|
redirectManager.addRedirect(`/${offer.code}`, `/#/portal/offers/${offer.id}`, {permanent: false});
|
|
43
53
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
2
|
const Promise = require('bluebird');
|
|
3
3
|
const errors = require('@tryghost/errors');
|
|
4
|
-
const
|
|
4
|
+
const tpl = require('@tryghost/tpl');
|
|
5
5
|
const parseContext = require('./parse-context');
|
|
6
6
|
const _private = {};
|
|
7
7
|
|
|
8
|
+
const messages = {
|
|
9
|
+
error: 'You do not have permission to retrieve {docName} with that status'
|
|
10
|
+
};
|
|
11
|
+
|
|
8
12
|
/**
|
|
9
13
|
* @TODO:
|
|
10
14
|
*
|
|
@@ -17,7 +21,7 @@ const _private = {};
|
|
|
17
21
|
* - public context cannot fetch draft/scheduled posts
|
|
18
22
|
*/
|
|
19
23
|
_private.applyStatusRules = function applyStatusRules(docName, method, opts) {
|
|
20
|
-
const err = new errors.NoPermissionError({message:
|
|
24
|
+
const err = new errors.NoPermissionError({message: tpl(messages.error, {docName: docName})});
|
|
21
25
|
|
|
22
26
|
// Enforce status 'active' for users
|
|
23
27
|
if (docName === 'users') {
|
|
@@ -3,7 +3,7 @@ const moment = require('moment-timezone');
|
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const crypto = require('crypto');
|
|
6
|
-
const urlService = require('
|
|
6
|
+
const urlService = require('../url');
|
|
7
7
|
|
|
8
8
|
const debug = require('@tryghost/debug')('services:route-settings');
|
|
9
9
|
const errors = require('@tryghost/errors');
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
const events = require('../../lib/common/events');
|
|
6
6
|
const models = require('../../models');
|
|
7
|
+
const labs = require('../../../shared/labs');
|
|
7
8
|
const SettingsCache = require('../../../shared/settings-cache');
|
|
8
9
|
const SettingsBREADService = require('./settings-bread-service');
|
|
9
10
|
const {obfuscatedSetting, isSecretSetting, hideValueIfSecret} = require('./settings-utils');
|
|
@@ -14,7 +15,8 @@ const {obfuscatedSetting, isSecretSetting, hideValueIfSecret} = require('./setti
|
|
|
14
15
|
const getSettingsBREADServiceInstance = () => {
|
|
15
16
|
return new SettingsBREADService({
|
|
16
17
|
SettingsModel: models.Settings,
|
|
17
|
-
settingsCache: SettingsCache
|
|
18
|
+
settingsCache: SettingsCache,
|
|
19
|
+
labsService: labs
|
|
18
20
|
});
|
|
19
21
|
};
|
|
20
22
|
|
|
@@ -14,10 +14,12 @@ class SettingsBREADService {
|
|
|
14
14
|
* @param {Object} options
|
|
15
15
|
* @param {Object} options.SettingsModel
|
|
16
16
|
* @param {Object} options.settingsCache - SettingsCache instance
|
|
17
|
+
* @param {Object} options.labsService - labs service instance
|
|
17
18
|
*/
|
|
18
|
-
constructor({SettingsModel, settingsCache}) {
|
|
19
|
+
constructor({SettingsModel, settingsCache, labsService}) {
|
|
19
20
|
this.SettingsModel = SettingsModel;
|
|
20
21
|
this.settingsCache = settingsCache;
|
|
22
|
+
this.labs = labsService;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
/**
|
|
@@ -28,24 +30,7 @@ class SettingsBREADService {
|
|
|
28
30
|
browse(context) {
|
|
29
31
|
let settings = this.settingsCache.getAll();
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
if (!context) {
|
|
33
|
-
return Promise.resolve(settings.filter((setting) => {
|
|
34
|
-
return setting.group === 'site';
|
|
35
|
-
}));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (!context.internal) {
|
|
39
|
-
// CASE: omit core settings unless internal request
|
|
40
|
-
settings = _.filter(settings, (setting) => {
|
|
41
|
-
const isCore = setting.group === 'core';
|
|
42
|
-
return !isCore;
|
|
43
|
-
});
|
|
44
|
-
// CASE: omit secret settings unless internal request
|
|
45
|
-
settings = settings.map(hideValueIfSecret);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return settings;
|
|
33
|
+
return this._formatBrowse(settings, context);
|
|
49
34
|
}
|
|
50
35
|
|
|
51
36
|
/**
|
|
@@ -86,6 +71,12 @@ class SettingsBREADService {
|
|
|
86
71
|
}));
|
|
87
72
|
}
|
|
88
73
|
|
|
74
|
+
// NOTE: Labs flags can exist outside of the DB when they are forced on/off
|
|
75
|
+
// so we grab them from the labs service instead as that's source-of-truth
|
|
76
|
+
if (setting.key === 'labs') {
|
|
77
|
+
setting.value = JSON.stringify(this.labs.getAll());
|
|
78
|
+
}
|
|
79
|
+
|
|
89
80
|
setting = hideValueIfSecret(setting);
|
|
90
81
|
|
|
91
82
|
return {
|
|
@@ -161,7 +152,9 @@ class SettingsBREADService {
|
|
|
161
152
|
});
|
|
162
153
|
}
|
|
163
154
|
|
|
164
|
-
return this.SettingsModel.edit(filteredSettings, options)
|
|
155
|
+
return this.SettingsModel.edit(filteredSettings, options).then((result) => {
|
|
156
|
+
return this._formatBrowse(_.keyBy(_.invokeMap(result, 'toJSON'), 'key'), options.context);
|
|
157
|
+
});
|
|
165
158
|
}
|
|
166
159
|
|
|
167
160
|
/**
|
|
@@ -183,6 +176,35 @@ class SettingsBREADService {
|
|
|
183
176
|
}
|
|
184
177
|
}
|
|
185
178
|
}
|
|
179
|
+
|
|
180
|
+
_formatBrowse(inputSettings, context) {
|
|
181
|
+
let settings = _.values(inputSettings);
|
|
182
|
+
// CASE: no context passed (functional call)
|
|
183
|
+
if (!context) {
|
|
184
|
+
return Promise.resolve(settings.filter((setting) => {
|
|
185
|
+
return setting.group === 'site';
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!context.internal) {
|
|
190
|
+
// CASE: omit core settings unless internal request
|
|
191
|
+
settings = _.filter(settings, (setting) => {
|
|
192
|
+
const isCore = setting.group === 'core';
|
|
193
|
+
return !isCore;
|
|
194
|
+
});
|
|
195
|
+
// CASE: omit secret settings unless internal request
|
|
196
|
+
settings = settings.map(hideValueIfSecret);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// NOTE: Labs flags can exist outside of the DB when they are forced on/off
|
|
200
|
+
// so we grab them from the labs service instead as that's source-of-truth
|
|
201
|
+
const labsSetting = settings.find(setting => setting.key === 'labs');
|
|
202
|
+
if (labsSetting) {
|
|
203
|
+
labsSetting.value = JSON.stringify(this.labs.getAll());
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return settings;
|
|
207
|
+
}
|
|
186
208
|
}
|
|
187
209
|
|
|
188
210
|
module.exports = SettingsBREADService;
|
|
@@ -4,7 +4,7 @@ const logging = require('@tryghost/logging');
|
|
|
4
4
|
const request = require('@tryghost/request');
|
|
5
5
|
const {blogIcon} = require('../lib/image');
|
|
6
6
|
const urlUtils = require('../../shared/url-utils');
|
|
7
|
-
const urlService = require('
|
|
7
|
+
const urlService = require('./url');
|
|
8
8
|
const settingsCache = require('../../shared/settings-cache');
|
|
9
9
|
const schema = require('../data/schema').checks;
|
|
10
10
|
const moment = require('moment');
|
|
@@ -30,7 +30,7 @@ module.exports.loadAndActivate = async (themeName) => {
|
|
|
30
30
|
logging.warn(validate.getThemeValidationError('activeThemeHasErrors', themeName, checkedTheme));
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
activator.activateFromBoot(themeName, loadedTheme, checkedTheme);
|
|
33
|
+
await activator.activateFromBoot(themeName, loadedTheme, checkedTheme);
|
|
34
34
|
} catch (err) {
|
|
35
35
|
if (err instanceof errors.NotFoundError) {
|
|
36
36
|
// CASE: active theme is missing, we don't want to exit because the admin panel will still work
|
|
@@ -56,7 +56,7 @@ module.exports.activate = async (themeName) => {
|
|
|
56
56
|
// Validate
|
|
57
57
|
const checkedTheme = await validate.checkSafe(themeName, loadedTheme);
|
|
58
58
|
// Activate
|
|
59
|
-
activator.activateFromAPI(themeName, loadedTheme, checkedTheme);
|
|
59
|
+
await activator.activateFromAPI(themeName, loadedTheme, checkedTheme);
|
|
60
60
|
// Return the checked theme
|
|
61
61
|
return checkedTheme;
|
|
62
62
|
};
|
|
@@ -8,27 +8,27 @@ const customThemeSettings = require('../custom-theme-settings');
|
|
|
8
8
|
* And also adds a little debug statement, which is very handy when debugging theme logic
|
|
9
9
|
*/
|
|
10
10
|
module.exports = {
|
|
11
|
-
activateFromBoot: (themeName, theme, checkedTheme) => {
|
|
11
|
+
activateFromBoot: async (themeName, theme, checkedTheme) => {
|
|
12
12
|
debug('Activating theme (method A on boot)', themeName);
|
|
13
13
|
// TODO: probably a better place for this to happen - after successful activation / when reloading site?
|
|
14
14
|
if (labs.isSet('customThemeSettings')) {
|
|
15
|
-
customThemeSettings.activateTheme(checkedTheme);
|
|
15
|
+
await customThemeSettings.api.activateTheme(themeName, checkedTheme);
|
|
16
16
|
}
|
|
17
17
|
bridge.activateTheme(theme, checkedTheme);
|
|
18
18
|
},
|
|
19
|
-
activateFromAPI: (themeName, theme, checkedTheme) => {
|
|
19
|
+
activateFromAPI: async (themeName, theme, checkedTheme) => {
|
|
20
20
|
debug('Activating theme (method B on API "activate")', themeName);
|
|
21
21
|
// TODO: probably a better place for this to happen - after successful activation / when reloading site?
|
|
22
22
|
if (labs.isSet('customThemeSettings')) {
|
|
23
|
-
customThemeSettings.activateTheme(checkedTheme);
|
|
23
|
+
await customThemeSettings.api.activateTheme(themeName, checkedTheme);
|
|
24
24
|
}
|
|
25
25
|
bridge.activateTheme(theme, checkedTheme);
|
|
26
26
|
},
|
|
27
|
-
activateFromAPIOverride: (themeName, theme, checkedTheme) => {
|
|
27
|
+
activateFromAPIOverride: async (themeName, theme, checkedTheme) => {
|
|
28
28
|
debug('Activating theme (method C on API "override")', themeName);
|
|
29
29
|
// TODO: probably a better place for this to happen - after successful activation / when reloading site?
|
|
30
30
|
if (labs.isSet('customThemeSettings')) {
|
|
31
|
-
customThemeSettings.activateTheme(checkedTheme);
|
|
31
|
+
await customThemeSettings.api.activateTheme(themeName, checkedTheme);
|
|
32
32
|
}
|
|
33
33
|
bridge.activateTheme(theme, checkedTheme);
|
|
34
34
|
}
|
|
@@ -83,7 +83,7 @@ module.exports = {
|
|
|
83
83
|
// CASE: if this is the active theme, we are overriding
|
|
84
84
|
if (overrideTheme) {
|
|
85
85
|
debug('setFromZip Theme is active already');
|
|
86
|
-
activator.activateFromAPIOverride(themeName, loadedTheme, checkedTheme);
|
|
86
|
+
await activator.activateFromAPIOverride(themeName, loadedTheme, checkedTheme);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
// @TODO: unify the name across gscan and Ghost!
|
|
File without changes
|
|
File without changes
|
|
@@ -3,10 +3,10 @@ const Promise = require('bluebird');
|
|
|
3
3
|
const debug = require('@tryghost/debug')('services:url:resources');
|
|
4
4
|
const Resource = require('./Resource');
|
|
5
5
|
const config = require('../../../shared/config');
|
|
6
|
-
const models = require('
|
|
6
|
+
const models = require('../../models');
|
|
7
7
|
|
|
8
8
|
// This listens to all manner of model events to find new content that needs a URL...
|
|
9
|
-
const events = require('
|
|
9
|
+
const events = require('../../lib/common/events');
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* @description At the moment the resources class is directly responsible for data population
|
|
@@ -68,24 +68,24 @@ class UrlGenerator {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
|
-
* @
|
|
72
|
-
* @
|
|
71
|
+
* @NOTE: currently only used if the permalink setting changes and it's used for this url generator.
|
|
72
|
+
* @TODO: https://github.com/TryGhost/Ghost/issues/10699
|
|
73
73
|
*/
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
* @NOTE: currently only used if the permalink setting changes and it's used for this url generator.
|
|
77
|
-
* @TODO: https://github.com/TryGhost/Ghost/issues/10699
|
|
78
|
-
*/
|
|
79
|
-
this.router.addListener('updated', () => {
|
|
80
|
-
const myResources = this.urls.getByGeneratorId(this.uid);
|
|
74
|
+
regenerateResources() {
|
|
75
|
+
const myResources = this.urls.getByGeneratorId(this.uid);
|
|
81
76
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
});
|
|
77
|
+
myResources.forEach((object) => {
|
|
78
|
+
this.urls.removeResourceId(object.resource.data.id);
|
|
79
|
+
object.resource.release();
|
|
80
|
+
this._try(object.resource);
|
|
87
81
|
});
|
|
82
|
+
}
|
|
88
83
|
|
|
84
|
+
/**
|
|
85
|
+
* @description Helper function to register listeners for each url generator instance.
|
|
86
|
+
* @private
|
|
87
|
+
*/
|
|
88
|
+
_listeners() {
|
|
89
89
|
/**
|
|
90
90
|
* Listen on two events:
|
|
91
91
|
*
|