ghost 5.34.1 → 5.35.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-cache-redis-5.35.0.tgz +0 -0
- package/components/{tryghost-adapter-manager-5.34.1.tgz → tryghost-adapter-manager-5.35.0.tgz} +0 -0
- package/components/{tryghost-api-framework-5.34.1.tgz → tryghost-api-framework-5.35.0.tgz} +0 -0
- package/components/tryghost-api-version-compatibility-service-5.35.0.tgz +0 -0
- package/components/tryghost-audience-feedback-5.35.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.35.0.tgz +0 -0
- package/components/tryghost-constants-5.35.0.tgz +0 -0
- package/components/{tryghost-custom-theme-settings-service-5.34.1.tgz → tryghost-custom-theme-settings-service-5.35.0.tgz} +0 -0
- package/components/tryghost-data-generator-5.35.0.tgz +0 -0
- package/components/tryghost-domain-events-5.35.0.tgz +0 -0
- package/components/tryghost-dynamic-routing-events-5.35.0.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.35.0.tgz +0 -0
- package/components/{tryghost-email-analytics-service-5.34.1.tgz → tryghost-email-analytics-service-5.35.0.tgz} +0 -0
- package/components/tryghost-email-content-generator-5.35.0.tgz +0 -0
- package/components/tryghost-email-events-5.35.0.tgz +0 -0
- package/components/tryghost-email-service-5.35.0.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.35.0.tgz +0 -0
- package/components/{tryghost-express-dynamic-redirects-5.34.1.tgz → tryghost-express-dynamic-redirects-5.35.0.tgz} +0 -0
- package/components/{tryghost-extract-api-key-5.34.1.tgz → tryghost-extract-api-key-5.35.0.tgz} +0 -0
- package/components/tryghost-html-to-plaintext-5.35.0.tgz +0 -0
- package/components/tryghost-i18n-5.35.0.tgz +0 -0
- package/components/{tryghost-importer-revue-5.34.1.tgz → tryghost-importer-revue-5.35.0.tgz} +0 -0
- package/components/tryghost-job-manager-5.35.0.tgz +0 -0
- package/components/{tryghost-link-redirects-5.34.1.tgz → tryghost-link-redirects-5.35.0.tgz} +0 -0
- package/components/tryghost-link-replacer-5.35.0.tgz +0 -0
- package/components/tryghost-link-tracking-5.35.0.tgz +0 -0
- package/components/{tryghost-magic-link-5.34.1.tgz → tryghost-magic-link-5.35.0.tgz} +0 -0
- package/components/tryghost-mailgun-client-5.35.0.tgz +0 -0
- package/components/tryghost-member-attribution-5.35.0.tgz +0 -0
- package/components/tryghost-member-events-5.35.0.tgz +0 -0
- package/components/tryghost-members-api-5.35.0.tgz +0 -0
- package/components/tryghost-members-csv-5.35.0.tgz +0 -0
- package/components/{tryghost-members-events-service-5.34.1.tgz → tryghost-members-events-service-5.35.0.tgz} +0 -0
- package/components/{tryghost-members-importer-5.34.1.tgz → tryghost-members-importer-5.35.0.tgz} +0 -0
- package/components/tryghost-members-offers-5.35.0.tgz +0 -0
- package/components/tryghost-members-payments-5.35.0.tgz +0 -0
- package/components/tryghost-members-ssr-5.35.0.tgz +0 -0
- package/components/tryghost-members-stripe-service-5.35.0.tgz +0 -0
- package/components/tryghost-milestones-5.35.0.tgz +0 -0
- package/components/tryghost-minifier-5.35.0.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.35.0.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.35.0.tgz +0 -0
- package/components/{tryghost-mw-error-handler-5.34.1.tgz → tryghost-mw-error-handler-5.35.0.tgz} +0 -0
- package/components/tryghost-mw-session-from-token-5.35.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.35.0.tgz +0 -0
- package/components/tryghost-mw-vhost-5.35.0.tgz +0 -0
- package/components/tryghost-oembed-service-5.35.0.tgz +0 -0
- package/components/{tryghost-package-json-5.34.1.tgz → tryghost-package-json-5.35.0.tgz} +0 -0
- package/components/tryghost-public-resource-repository-5.35.0.tgz +0 -0
- package/components/tryghost-referrers-5.35.0.tgz +0 -0
- package/components/tryghost-security-5.35.0.tgz +0 -0
- package/components/tryghost-session-service-5.35.0.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.35.0.tgz +0 -0
- package/components/tryghost-slack-notifications-5.35.0.tgz +0 -0
- package/components/{tryghost-staff-service-5.34.1.tgz → tryghost-staff-service-5.35.0.tgz} +0 -0
- package/components/tryghost-stats-service-5.35.0.tgz +0 -0
- package/components/tryghost-tiers-5.35.0.tgz +0 -0
- package/components/tryghost-update-check-service-5.35.0.tgz +0 -0
- package/components/tryghost-verification-trigger-5.35.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.35.0.tgz +0 -0
- package/components/tryghost-webmentions-5.35.0.tgz +0 -0
- package/core/boot.js +27 -3
- package/core/built/admin/assets/{chunk.143.07f5af56ff872bb0e9e4.js → chunk.143.d49ad252968f2ef3966d.js} +5 -5
- package/core/built/admin/assets/{chunk.178.2e831ef9072743e38dd1.js → chunk.178.3d45fff87e08a5be5eb8.js} +4 -4
- package/core/built/admin/assets/{chunk.616.181e1ad6c33f0bec7a65.js → chunk.502.c4afca88c98edad8b268.js} +1621 -1338
- package/core/built/admin/assets/{chunk.616.181e1ad6c33f0bec7a65.js.LICENSE.txt → chunk.502.c4afca88c98edad8b268.js.LICENSE.txt} +43 -0
- package/core/built/admin/assets/{ghost-ad40d109653288e74a7cd922341fb33d.js → ghost-4a6ed62455c9e367434183980b3ca3e9.js} +4344 -4322
- package/core/built/admin/assets/{vendor-253d6527ca6353855164ef65f896f762.js → vendor-c4684647d4f5213e5dbb6763de430e7e.js} +2741 -2309
- package/core/built/admin/index.html +5 -5
- package/core/cli/generate-data.js +3 -1
- package/core/server/api/endpoints/images.js +13 -6
- package/core/server/api/endpoints/pages-public.js +3 -1
- package/core/server/api/endpoints/posts-public.js +3 -1
- package/core/server/api/endpoints/utils/serializers/output/mappers/mentions.js +2 -1
- package/core/server/api/endpoints/utils/serializers/output/mappers/posts.js +11 -0
- package/core/server/data/migrations/versions/5.35/2023-02-13-06-24-add-mentions-verified-column.js +7 -0
- package/core/server/data/schema/schema.js +2 -1
- package/core/server/lib/request-external.js +1 -0
- package/core/server/models/mention.js +2 -1
- package/core/server/services/email-service/wrapper.js +2 -1
- package/core/server/services/mega/post-email-serializer.js +2 -2
- package/core/server/services/mega/template.js +1 -1
- package/core/server/services/member-attribution/index.js +8 -4
- package/core/server/services/mentions/BookshelfMentionRepository.js +4 -2
- package/core/server/services/mentions/WebmentionRequest.js +20 -0
- package/core/server/services/mentions/service.js +4 -1
- package/core/server/services/mentions-jobs/index.js +1 -0
- package/core/server/services/mentions-jobs/job-service.js +48 -0
- package/core/server/services/{milestone-emails → milestones}/MilestoneQueries.js +0 -0
- package/core/server/services/{milestone-emails → milestones}/index.js +0 -0
- package/core/server/services/milestones/service.js +78 -0
- package/core/server/services/posts-public/index.js +1 -0
- package/core/server/services/posts-public/service.js +31 -0
- package/core/server/services/slack-notifications/index.js +1 -0
- package/core/server/services/slack-notifications/service.js +60 -0
- package/core/server/services/tags-public/service.js +5 -5
- package/core/server/services/websockets/index.js +1 -0
- package/core/server/services/websockets/service.js +37 -0
- package/core/shared/config/defaults.json +2 -2
- package/core/shared/labs.js +3 -2
- package/package.json +121 -118
- package/yarn.lock +307 -102
- package/components/tryghost-adapter-cache-redis-5.34.1.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-5.34.1.tgz +0 -0
- package/components/tryghost-audience-feedback-5.34.1.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.34.1.tgz +0 -0
- package/components/tryghost-constants-5.34.1.tgz +0 -0
- package/components/tryghost-data-generator-5.34.1.tgz +0 -0
- package/components/tryghost-domain-events-5.34.1.tgz +0 -0
- package/components/tryghost-dynamic-routing-events-5.34.1.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.34.1.tgz +0 -0
- package/components/tryghost-email-content-generator-5.34.1.tgz +0 -0
- package/components/tryghost-email-events-5.34.1.tgz +0 -0
- package/components/tryghost-email-service-5.34.1.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.34.1.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.34.1.tgz +0 -0
- package/components/tryghost-i18n-5.34.1.tgz +0 -0
- package/components/tryghost-job-manager-5.34.1.tgz +0 -0
- package/components/tryghost-link-replacer-5.34.1.tgz +0 -0
- package/components/tryghost-link-tracking-5.34.1.tgz +0 -0
- package/components/tryghost-mailgun-client-5.34.1.tgz +0 -0
- package/components/tryghost-member-attribution-5.34.1.tgz +0 -0
- package/components/tryghost-member-events-5.34.1.tgz +0 -0
- package/components/tryghost-members-api-5.34.1.tgz +0 -0
- package/components/tryghost-members-csv-5.34.1.tgz +0 -0
- package/components/tryghost-members-offers-5.34.1.tgz +0 -0
- package/components/tryghost-members-payments-5.34.1.tgz +0 -0
- package/components/tryghost-members-ssr-5.34.1.tgz +0 -0
- package/components/tryghost-members-stripe-service-5.34.1.tgz +0 -0
- package/components/tryghost-milestone-emails-5.34.1.tgz +0 -0
- package/components/tryghost-minifier-5.34.1.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.34.1.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.34.1.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.34.1.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.34.1.tgz +0 -0
- package/components/tryghost-mw-vhost-5.34.1.tgz +0 -0
- package/components/tryghost-oembed-service-5.34.1.tgz +0 -0
- package/components/tryghost-referrers-5.34.1.tgz +0 -0
- package/components/tryghost-security-5.34.1.tgz +0 -0
- package/components/tryghost-session-service-5.34.1.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.34.1.tgz +0 -0
- package/components/tryghost-stats-service-5.34.1.tgz +0 -0
- package/components/tryghost-tags-public-5.34.1.tgz +0 -0
- package/components/tryghost-tiers-5.34.1.tgz +0 -0
- package/components/tryghost-update-check-service-5.34.1.tgz +0 -0
- package/components/tryghost-verification-trigger-5.34.1.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.34.1.tgz +0 -0
- package/components/tryghost-webmentions-5.34.1.tgz +0 -0
- package/core/server/services/milestone-emails/service.js +0 -58
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<title>Ghost Admin</title>
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.
|
|
11
|
+
<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.35%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
|
|
12
12
|
|
|
13
13
|
<meta name="HandheldFriendly" content="True" />
|
|
14
14
|
<meta name="MobileOptimized" content="320" />
|
|
@@ -56,9 +56,9 @@
|
|
|
56
56
|
|
|
57
57
|
<div id="ember-basic-dropdown-wormhole"></div>
|
|
58
58
|
|
|
59
|
-
<script src="assets/vendor-
|
|
60
|
-
<script src="assets/chunk.
|
|
61
|
-
<script src="assets/chunk.143.
|
|
62
|
-
<script src="assets/ghost-
|
|
59
|
+
<script src="assets/vendor-c4684647d4f5213e5dbb6763de430e7e.js"></script>
|
|
60
|
+
<script src="assets/chunk.502.c4afca88c98edad8b268.js"></script>
|
|
61
|
+
<script src="assets/chunk.143.d49ad252968f2ef3966d.js"></script>
|
|
62
|
+
<script src="assets/ghost-4a6ed62455c9e367434183980b3ca3e9.js"></script>
|
|
63
63
|
</body>
|
|
64
64
|
</html>
|
|
@@ -9,6 +9,7 @@ module.exports = class DataGeneratorCommand extends Command {
|
|
|
9
9
|
this.argument('--scale', {type: 'string', defaultValue: 'small', desc: 'Scale of the data to generate. `small` for a quick run, `large` for more content'});
|
|
10
10
|
this.argument('--single-table', {type: 'string', desc: 'Import a single table'});
|
|
11
11
|
this.argument('--quantity', {type: 'number', desc: 'When importing a single table, the quantity to import'});
|
|
12
|
+
this.argument('--clear-database', {type: 'boolean', defaultValue: false, desc: 'Clear all entries in the database before importing'});
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
initializeContext(context) {
|
|
@@ -55,7 +56,8 @@ module.exports = class DataGeneratorCommand extends Command {
|
|
|
55
56
|
debug: this.debug
|
|
56
57
|
},
|
|
57
58
|
modelQuantities,
|
|
58
|
-
baseUrl: config.getSiteUrl()
|
|
59
|
+
baseUrl: config.getSiteUrl(),
|
|
60
|
+
clearDatabase: argv['clear-database']
|
|
59
61
|
});
|
|
60
62
|
try {
|
|
61
63
|
if (argv['single-table']) {
|
|
@@ -37,13 +37,20 @@ module.exports = {
|
|
|
37
37
|
...frame.file,
|
|
38
38
|
path: out
|
|
39
39
|
});
|
|
40
|
-
const processedImagePath = store.urlToPath(processedImageUrl);
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
let processedImageName = path.basename(processedImageUrl);
|
|
42
|
+
let processedImageDir = undefined;
|
|
43
|
+
|
|
44
|
+
if (store.urlToPath) {
|
|
45
|
+
// Currently urlToPath is not part of StorageBase, so not all storage provider have implemented it
|
|
46
|
+
const processedImagePath = store.urlToPath(processedImageUrl);
|
|
47
|
+
|
|
48
|
+
// Get the path and name of the processed image
|
|
49
|
+
// We want to store the original image on the same name + _o
|
|
50
|
+
// So we need to wait for the first store to finish before generating the name of the original image
|
|
51
|
+
processedImageName = path.basename(processedImagePath);
|
|
52
|
+
processedImageDir = path.dirname(processedImagePath);
|
|
53
|
+
}
|
|
47
54
|
|
|
48
55
|
// Store the original image
|
|
49
56
|
await store.save({
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const tpl = require('@tryghost/tpl');
|
|
2
2
|
const errors = require('@tryghost/errors');
|
|
3
3
|
const models = require('../../models');
|
|
4
|
+
const postsPublicService = require('../../services/posts-public');
|
|
5
|
+
|
|
4
6
|
const ALLOWED_INCLUDES = ['tags', 'authors', 'tiers'];
|
|
5
7
|
|
|
6
8
|
const messages = {
|
|
@@ -34,7 +36,7 @@ module.exports = {
|
|
|
34
36
|
},
|
|
35
37
|
permissions: true,
|
|
36
38
|
query(frame) {
|
|
37
|
-
return
|
|
39
|
+
return postsPublicService.api.browse(frame.options);
|
|
38
40
|
}
|
|
39
41
|
},
|
|
40
42
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const models = require('../../models');
|
|
2
2
|
const tpl = require('@tryghost/tpl');
|
|
3
3
|
const errors = require('@tryghost/errors');
|
|
4
|
+
const postsPublicService = require('../../services/posts-public');
|
|
5
|
+
|
|
4
6
|
const allowedIncludes = ['tags', 'authors', 'tiers', 'sentiment'];
|
|
5
7
|
|
|
6
8
|
const messages = {
|
|
@@ -34,7 +36,7 @@ module.exports = {
|
|
|
34
36
|
},
|
|
35
37
|
permissions: true,
|
|
36
38
|
query(frame) {
|
|
37
|
-
return
|
|
39
|
+
return postsPublicService.api.browse(frame.options);
|
|
38
40
|
}
|
|
39
41
|
},
|
|
40
42
|
|
|
@@ -13,6 +13,7 @@ module.exports = (model) => {
|
|
|
13
13
|
source_excerpt: json.sourceExcerpt,
|
|
14
14
|
source_author: json.sourceAuthor,
|
|
15
15
|
source_favicon: json.sourceFavicon,
|
|
16
|
-
source_featured_image: json.sourceFeaturedImage
|
|
16
|
+
source_featured_image: json.sourceFeaturedImage,
|
|
17
|
+
verified: json.verified
|
|
17
18
|
};
|
|
18
19
|
};
|
|
@@ -18,6 +18,8 @@ const getPostServiceInstance = require('../../../../../../services/posts/posts-s
|
|
|
18
18
|
const postsService = getPostServiceInstance();
|
|
19
19
|
|
|
20
20
|
const commentsService = require('../../../../../../services/comments');
|
|
21
|
+
const memberAttribution = require('../../../../../../services/member-attribution');
|
|
22
|
+
const labs = require('../../../../../../../shared/labs');
|
|
21
23
|
|
|
22
24
|
module.exports = async (model, frame, options = {}) => {
|
|
23
25
|
const {tiers: tiersData} = options || {};
|
|
@@ -65,6 +67,15 @@ module.exports = async (model, frame, options = {}) => {
|
|
|
65
67
|
} else {
|
|
66
68
|
jsonModel.comments = false;
|
|
67
69
|
}
|
|
70
|
+
|
|
71
|
+
// Add outbound link tags
|
|
72
|
+
if (labs.isSet('outboundLinkTagging')) {
|
|
73
|
+
// Only add it in the flag! Without the flag we only add it to emails.
|
|
74
|
+
if (jsonModel.html) {
|
|
75
|
+
// Only set if HTML was requested
|
|
76
|
+
jsonModel.html = await memberAttribution.outboundLinkTagger.addToHtml(jsonModel.html);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
68
79
|
}
|
|
69
80
|
|
|
70
81
|
// Transforms post/page metadata to flat structure
|
|
@@ -995,6 +995,7 @@ module.exports = {
|
|
|
995
995
|
resource_type: {type: 'string', maxlength: 50, nullable: true},
|
|
996
996
|
created_at: {type: 'dateTime', nullable: false},
|
|
997
997
|
payload: {type: 'text', maxlength: 65535, nullable: true},
|
|
998
|
-
deleted: {type: 'boolean', nullable: false, defaultTo: false}
|
|
998
|
+
deleted: {type: 'boolean', nullable: false, defaultTo: false},
|
|
999
|
+
verified: {type: 'boolean', nullable: false, defaultTo: false}
|
|
999
1000
|
}
|
|
1000
1001
|
};
|
|
@@ -42,6 +42,7 @@ const externalRequest = got.extend({
|
|
|
42
42
|
headers: {
|
|
43
43
|
'user-agent': 'Ghost(https://github.com/TryGhost/Ghost)'
|
|
44
44
|
},
|
|
45
|
+
timeout: 10000, // default is no timeout
|
|
45
46
|
hooks: {
|
|
46
47
|
init: [(options) => {
|
|
47
48
|
if (!options.hostname || !validator.isURL(options.hostname)) {
|
|
@@ -67,7 +67,8 @@ class EmailServiceWrapper {
|
|
|
67
67
|
linkReplacer,
|
|
68
68
|
linkTracking,
|
|
69
69
|
memberAttributionService: memberAttribution.service,
|
|
70
|
-
audienceFeedbackService: audienceFeedback.service
|
|
70
|
+
audienceFeedbackService: audienceFeedback.service,
|
|
71
|
+
outboundLinkTagger: memberAttribution.outboundLinkTagger
|
|
71
72
|
});
|
|
72
73
|
|
|
73
74
|
const sendingService = new SendingService({
|
|
@@ -400,13 +400,13 @@ const PostEmailSerializer = {
|
|
|
400
400
|
|
|
401
401
|
if (isSite) {
|
|
402
402
|
// Add newsletter name as ref to the URL
|
|
403
|
-
url = memberAttribution.
|
|
403
|
+
url = memberAttribution.outboundLinkTagger.addToUrl(url, newsletter);
|
|
404
404
|
|
|
405
405
|
// Only add post attribution to our own site (because external sites could/should not process this information)
|
|
406
406
|
url = memberAttribution.service.addPostAttributionTracking(url, post);
|
|
407
407
|
} else {
|
|
408
408
|
// Add email source attribution without the newsletter name
|
|
409
|
-
url = memberAttribution.
|
|
409
|
+
url = memberAttribution.outboundLinkTagger.addToUrl(url);
|
|
410
410
|
}
|
|
411
411
|
|
|
412
412
|
// Add link click tracking
|
|
@@ -12,7 +12,7 @@ class MemberAttributionServiceWrapper {
|
|
|
12
12
|
|
|
13
13
|
// Wire up all the dependencies
|
|
14
14
|
const {
|
|
15
|
-
MemberAttributionService, UrlTranslator, ReferrerTranslator, AttributionBuilder
|
|
15
|
+
MemberAttributionService, UrlTranslator, ReferrerTranslator, AttributionBuilder, OutboundLinkTagger
|
|
16
16
|
} = require('@tryghost/member-attribution');
|
|
17
17
|
const models = require('../../models');
|
|
18
18
|
|
|
@@ -33,6 +33,12 @@ class MemberAttributionServiceWrapper {
|
|
|
33
33
|
|
|
34
34
|
this.attributionBuilder = new AttributionBuilder({urlTranslator, referrerTranslator});
|
|
35
35
|
|
|
36
|
+
this.outboundLinkTagger = new OutboundLinkTagger({
|
|
37
|
+
isEnabled: () => !labs.isSet('outboundLinkTagging') || !!settingsCache.get('outbound_link_tagging'),
|
|
38
|
+
getSiteTitle: () => settingsCache.get('title'),
|
|
39
|
+
urlUtils
|
|
40
|
+
});
|
|
41
|
+
|
|
36
42
|
// Expose the service
|
|
37
43
|
this.service = new MemberAttributionService({
|
|
38
44
|
models: {
|
|
@@ -41,9 +47,7 @@ class MemberAttributionServiceWrapper {
|
|
|
41
47
|
Integration: models.Integration
|
|
42
48
|
},
|
|
43
49
|
attributionBuilder: this.attributionBuilder,
|
|
44
|
-
getTrackingEnabled: () => !!settingsCache.get('members_track_sources')
|
|
45
|
-
getOutboundLinkTaggingEnabled: () => !labs.isSet('outboundLinkTagging') || !!settingsCache.get('outbound_link_tagging'),
|
|
46
|
-
getSiteTitle: () => settingsCache.get('title')
|
|
50
|
+
getTrackingEnabled: () => !!settingsCache.get('members_track_sources')
|
|
47
51
|
});
|
|
48
52
|
}
|
|
49
53
|
}
|
|
@@ -54,7 +54,8 @@ module.exports = class BookshelfMentionRepository {
|
|
|
54
54
|
sourceAuthor: model.get('source_author'),
|
|
55
55
|
sourceExcerpt: model.get('source_excerpt'),
|
|
56
56
|
sourceFavicon: model.get('source_favicon'),
|
|
57
|
-
sourceFeaturedImage: model.get('source_featured_image')
|
|
57
|
+
sourceFeaturedImage: model.get('source_featured_image'),
|
|
58
|
+
verified: model.get('verified')
|
|
58
59
|
});
|
|
59
60
|
}
|
|
60
61
|
|
|
@@ -107,7 +108,8 @@ module.exports = class BookshelfMentionRepository {
|
|
|
107
108
|
resource_id: mention.resourceId?.toHexString(),
|
|
108
109
|
resource_type: mention.resourceId ? 'post' : null,
|
|
109
110
|
payload: mention.payload ? JSON.stringify(mention.payload) : null,
|
|
110
|
-
deleted: Mention.isDeleted(mention)
|
|
111
|
+
deleted: Mention.isDeleted(mention),
|
|
112
|
+
verified: mention.verified
|
|
111
113
|
};
|
|
112
114
|
|
|
113
115
|
const existing = await this.#MentionModel.findOne({id: data.id}, {require: false});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const logging = require('@tryghost/logging');
|
|
2
|
+
const oembedService = require('../oembed');
|
|
3
|
+
|
|
4
|
+
module.exports = class WebmentionRequest {
|
|
5
|
+
/**
|
|
6
|
+
* @param {URL} url
|
|
7
|
+
* @returns {Promise<{html: string}>}
|
|
8
|
+
*/
|
|
9
|
+
async fetch(url) {
|
|
10
|
+
try {
|
|
11
|
+
const data = await oembedService.fetchPageHtml(url.href);
|
|
12
|
+
return {
|
|
13
|
+
html: data.body
|
|
14
|
+
};
|
|
15
|
+
} catch (err) {
|
|
16
|
+
logging.warn(err);
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const MentionController = require('./MentionController');
|
|
2
2
|
const WebmentionMetadata = require('./WebmentionMetadata');
|
|
3
|
+
const WebmentionRequest = require('./WebmentionRequest');
|
|
3
4
|
const {
|
|
4
5
|
MentionsAPI,
|
|
5
6
|
MentionSendingService,
|
|
@@ -16,7 +17,7 @@ const outputSerializerUrlUtil = require('../../../server/api/endpoints/utils/ser
|
|
|
16
17
|
const urlService = require('../url');
|
|
17
18
|
const settingsCache = require('../../../shared/settings-cache');
|
|
18
19
|
const DomainEvents = require('@tryghost/domain-events');
|
|
19
|
-
const jobsService = require('../jobs');
|
|
20
|
+
const jobsService = require('../mentions-jobs');
|
|
20
21
|
|
|
21
22
|
function getPostUrl(post) {
|
|
22
23
|
const jsonModel = {};
|
|
@@ -32,6 +33,7 @@ module.exports = {
|
|
|
32
33
|
DomainEvents
|
|
33
34
|
});
|
|
34
35
|
const webmentionMetadata = new WebmentionMetadata();
|
|
36
|
+
const webmentionRequest = new WebmentionRequest();
|
|
35
37
|
const discoveryService = new MentionDiscoveryService({externalRequest});
|
|
36
38
|
const resourceService = new ResourceService({
|
|
37
39
|
urlUtils,
|
|
@@ -47,6 +49,7 @@ module.exports = {
|
|
|
47
49
|
const api = new MentionsAPI({
|
|
48
50
|
repository,
|
|
49
51
|
webmentionMetadata,
|
|
52
|
+
webmentionRequest,
|
|
50
53
|
resourceService,
|
|
51
54
|
routingService
|
|
52
55
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./job-service');
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal wrapper around our external lib
|
|
3
|
+
* Intended for passing any Ghost internals such as logging and config
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const JobManager = require('@tryghost/job-manager');
|
|
7
|
+
const logging = require('@tryghost/logging');
|
|
8
|
+
const models = require('../../models');
|
|
9
|
+
const sentry = require('../../../shared/sentry');
|
|
10
|
+
const domainEvents = require('@tryghost/domain-events');
|
|
11
|
+
|
|
12
|
+
const errorHandler = (error, workerMeta) => {
|
|
13
|
+
logging.info(`Capturing error for worker during execution of job: ${workerMeta.name}`);
|
|
14
|
+
logging.error(error);
|
|
15
|
+
sentry.captureException(error);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const workerMessageHandler = ({name, message}) => {
|
|
19
|
+
if (typeof message === 'string') {
|
|
20
|
+
logging.info(`Worker for job ${name} sent a message: ${message}`);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const initTestMode = () => {
|
|
25
|
+
// Output job queue length every 5 seconds
|
|
26
|
+
setInterval(() => {
|
|
27
|
+
logging.warn(`${jobManager.queue.length()} jobs in the queue. Idle: ${jobManager.queue.idle()}`);
|
|
28
|
+
|
|
29
|
+
const runningScheduledjobs = Object.keys(jobManager.bree.workers);
|
|
30
|
+
if (Object.keys(jobManager.bree.workers).length) {
|
|
31
|
+
logging.warn(`${Object.keys(jobManager.bree.workers).length} jobs running: ${runningScheduledjobs}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const scheduledJobs = Object.keys(jobManager.bree.intervals);
|
|
35
|
+
if (Object.keys(jobManager.bree.intervals).length) {
|
|
36
|
+
logging.warn(`${Object.keys(jobManager.bree.intervals).length} scheduled jobs: ${scheduledJobs}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (runningScheduledjobs.length === 0 && scheduledJobs.length === 0) {
|
|
40
|
+
logging.warn('No scheduled or running jobs');
|
|
41
|
+
}
|
|
42
|
+
}, 5000);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const jobManager = new JobManager({errorHandler, workerMessageHandler, JobModel: models.Job, domainEvents});
|
|
46
|
+
|
|
47
|
+
module.exports = jobManager;
|
|
48
|
+
module.exports.initTestMode = initTestMode;
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const DomainEvents = require('@tryghost/domain-events');
|
|
2
|
+
|
|
3
|
+
const getStripeLiveEnabled = () => {
|
|
4
|
+
const settingsCache = require('../../../shared/settings-cache');
|
|
5
|
+
const stripeConnect = settingsCache.get('stripe_connect_publishable_key');
|
|
6
|
+
const stripeKey = settingsCache.get('stripe_publishable_key');
|
|
7
|
+
|
|
8
|
+
const stripeLiveRegex = /pk_live_/;
|
|
9
|
+
|
|
10
|
+
if (stripeConnect && stripeConnect.match(stripeLiveRegex)) {
|
|
11
|
+
return true;
|
|
12
|
+
} else if (stripeKey && stripeKey.match(stripeLiveRegex)) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return false;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
/** @type {import('@tryghost/milestones/lib/MilestonesService')} */
|
|
21
|
+
api: null,
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @returns {Promise<void>}
|
|
25
|
+
*/
|
|
26
|
+
async init() {
|
|
27
|
+
if (!this.api) {
|
|
28
|
+
const db = require('../../data/db');
|
|
29
|
+
const MilestoneQueries = require('./MilestoneQueries');
|
|
30
|
+
|
|
31
|
+
const {
|
|
32
|
+
MilestonesService,
|
|
33
|
+
InMemoryMilestoneRepository
|
|
34
|
+
} = require('@tryghost/milestones');
|
|
35
|
+
const config = require('../../../shared/config');
|
|
36
|
+
const milestonesConfig = config.get('milestones');
|
|
37
|
+
|
|
38
|
+
const repository = new InMemoryMilestoneRepository({DomainEvents});
|
|
39
|
+
const queries = new MilestoneQueries({db});
|
|
40
|
+
|
|
41
|
+
this.api = new MilestonesService({
|
|
42
|
+
repository,
|
|
43
|
+
milestonesConfig, // avoid using getters and pass as JSON
|
|
44
|
+
queries
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @returns {Promise<object>}
|
|
51
|
+
*/
|
|
52
|
+
async run() {
|
|
53
|
+
const labs = require('../../../shared/labs');
|
|
54
|
+
|
|
55
|
+
if (labs.isSet('milestoneEmails')) {
|
|
56
|
+
const members = await this.api.checkMilestones('members');
|
|
57
|
+
let arr;
|
|
58
|
+
const stripeLiveEnabled = getStripeLiveEnabled();
|
|
59
|
+
|
|
60
|
+
if (stripeLiveEnabled) {
|
|
61
|
+
arr = await this.api.checkMilestones('arr');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
members,
|
|
66
|
+
arr
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @returns {Promise<object>}
|
|
73
|
+
*/
|
|
74
|
+
async initAndRun() {
|
|
75
|
+
await this.init();
|
|
76
|
+
return await this.run();
|
|
77
|
+
}
|
|
78
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./service');
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class PostsPublicServiceWrapper {
|
|
2
|
+
async init() {
|
|
3
|
+
if (this.api) {
|
|
4
|
+
// Already done
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Wire up all the dependencies
|
|
9
|
+
const {Post} = require('../../models');
|
|
10
|
+
const adapterManager = require('../adapter-manager');
|
|
11
|
+
const config = require('../../../shared/config');
|
|
12
|
+
|
|
13
|
+
let postsCache;
|
|
14
|
+
if (config.get('hostSettings:postsPublicCache:enabled')) {
|
|
15
|
+
postsCache = adapterManager.getAdapter('cache:postsPublic');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const {PublicResourcesRepository} = require('@tryghost/public-resource-repository');
|
|
19
|
+
|
|
20
|
+
this.postsRepository = new PublicResourcesRepository({
|
|
21
|
+
Model: Post,
|
|
22
|
+
cache: postsCache
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
this.api = {
|
|
26
|
+
browse: this.postsRepository.getAll.bind(this.postsRepository)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = new PostsPublicServiceWrapper();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./service');
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const DomainEvents = require('@tryghost/domain-events');
|
|
2
|
+
const config = require('../../../shared/config');
|
|
3
|
+
const labs = require('../../../shared/labs');
|
|
4
|
+
const logging = require('@tryghost/logging');
|
|
5
|
+
|
|
6
|
+
class SlackNotificationsServiceWrapper {
|
|
7
|
+
/** @type {import('@tryghost/slack-notifications/lib/SlackNotificationsService')} */
|
|
8
|
+
#api;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* @param {object} deps
|
|
13
|
+
* @param {string} deps.siteUrl
|
|
14
|
+
* @param {boolean} deps.isEnabled
|
|
15
|
+
* @param {URL} deps.webhookUrl
|
|
16
|
+
*
|
|
17
|
+
* @returns {import('@tryghost/slack-notifications/lib/SlackNotificationsService')}
|
|
18
|
+
*/
|
|
19
|
+
static create({siteUrl, isEnabled, webhookUrl}) {
|
|
20
|
+
const {
|
|
21
|
+
SlackNotificationsService,
|
|
22
|
+
SlackNotifications
|
|
23
|
+
} = require('@tryghost/slack-notifications');
|
|
24
|
+
|
|
25
|
+
const slackNotifications = new SlackNotifications({
|
|
26
|
+
webhookUrl,
|
|
27
|
+
siteUrl,
|
|
28
|
+
logging
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return new SlackNotificationsService({
|
|
32
|
+
DomainEvents,
|
|
33
|
+
logging,
|
|
34
|
+
config: {
|
|
35
|
+
isEnabled,
|
|
36
|
+
webhookUrl
|
|
37
|
+
},
|
|
38
|
+
slackNotifications
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
init() {
|
|
43
|
+
if (this.#api) {
|
|
44
|
+
// Prevent creating duplicate DomainEvents subscribers
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const hostSettings = config.get('hostSettings');
|
|
49
|
+
const urlUtils = require('../../../shared/url-utils');
|
|
50
|
+
const siteUrl = urlUtils.getSiteUrl();
|
|
51
|
+
const isEnabled = labs.isSet('milestoneEmails') && hostSettings?.milestones?.enabled && hostSettings?.milestones?.url;
|
|
52
|
+
const webhookUrl = hostSettings?.milestones?.url;
|
|
53
|
+
|
|
54
|
+
this.#api = SlackNotificationsServiceWrapper.create({siteUrl, isEnabled, webhookUrl});
|
|
55
|
+
|
|
56
|
+
this.#api.subscribeEvents();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = new SlackNotificationsServiceWrapper();
|
|
@@ -6,7 +6,7 @@ class TagsPublicServiceWrapper {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
// Wire up all the dependencies
|
|
9
|
-
const
|
|
9
|
+
const {TagPublic} = require('../../models');
|
|
10
10
|
const adapterManager = require('../adapter-manager');
|
|
11
11
|
const config = require('../../../shared/config');
|
|
12
12
|
|
|
@@ -15,15 +15,15 @@ class TagsPublicServiceWrapper {
|
|
|
15
15
|
tagsCache = adapterManager.getAdapter('cache:tagsPublic');
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const {
|
|
18
|
+
const {PublicResourcesRepository} = require('@tryghost/public-resource-repository');
|
|
19
19
|
|
|
20
|
-
this.
|
|
21
|
-
|
|
20
|
+
this.tagsPublicRepository = new PublicResourcesRepository({
|
|
21
|
+
Model: TagPublic,
|
|
22
22
|
cache: tagsCache
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
this.api = {
|
|
26
|
-
browse: this.
|
|
26
|
+
browse: this.tagsPublicRepository.getAll.bind(this.tagsPublicRepository)
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./service');
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const {Server} = require('socket.io');
|
|
2
|
+
const debug = require('@tryghost/debug')('websockets');
|
|
3
|
+
const logging = require('@tryghost/logging');
|
|
4
|
+
|
|
5
|
+
const labs = require('../../../shared/labs');
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
async init(ghostServer) {
|
|
9
|
+
debug(`[Websockets] Is labs set? ${labs.isSet('websockets')}`);
|
|
10
|
+
|
|
11
|
+
if (labs.isSet('websockets')) {
|
|
12
|
+
logging.info(`Starting websockets service`);
|
|
13
|
+
|
|
14
|
+
const io = new Server(ghostServer.httpServer);
|
|
15
|
+
let count = 0;
|
|
16
|
+
|
|
17
|
+
io.on(`connection`, (socket) => {
|
|
18
|
+
debug(`[Websockets] Client connected`);
|
|
19
|
+
// on connect, send current value
|
|
20
|
+
socket.emit('addCount', count);
|
|
21
|
+
// listen to to changes in value from client
|
|
22
|
+
socket.on('addCount', () => {
|
|
23
|
+
count = count + 1;
|
|
24
|
+
debug(`[Websockets] received addCount from client, count is now ${count}`);
|
|
25
|
+
socket.broadcast.emit('addCount', count);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
ghostServer.registerCleanupTask(async () => {
|
|
30
|
+
logging.warn(`Stopping websockets service`);
|
|
31
|
+
await new Promise((resolve) => {
|
|
32
|
+
io.close(resolve);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
@@ -210,9 +210,9 @@
|
|
|
210
210
|
"arr": [
|
|
211
211
|
{
|
|
212
212
|
"currency": "usd",
|
|
213
|
-
"values": [1000, 10000, 50000, 100000, 250000, 500000, 1000000]
|
|
213
|
+
"values": [100, 1000, 10000, 50000, 100000, 250000, 500000, 1000000]
|
|
214
214
|
}
|
|
215
215
|
],
|
|
216
|
-
"members": [100, 1000, 10000, 50000, 100000, 250000, 500000, 1000000]
|
|
216
|
+
"members": [100, 1000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000]
|
|
217
217
|
}
|
|
218
218
|
}
|