ghost 5.35.1 → 5.36.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.
Files changed (147) hide show
  1. package/components/tryghost-adapter-cache-memory-ttl-5.36.1.tgz +0 -0
  2. package/components/tryghost-adapter-cache-redis-5.36.1.tgz +0 -0
  3. package/components/{tryghost-adapter-manager-5.35.1.tgz → tryghost-adapter-manager-5.36.1.tgz} +0 -0
  4. package/components/tryghost-api-framework-5.36.1.tgz +0 -0
  5. package/components/tryghost-api-version-compatibility-service-5.36.1.tgz +0 -0
  6. package/components/{tryghost-audience-feedback-5.35.1.tgz → tryghost-audience-feedback-5.36.1.tgz} +0 -0
  7. package/components/tryghost-bootstrap-socket-5.36.1.tgz +0 -0
  8. package/components/tryghost-constants-5.36.1.tgz +0 -0
  9. package/components/{tryghost-custom-theme-settings-service-5.35.1.tgz → tryghost-custom-theme-settings-service-5.36.1.tgz} +0 -0
  10. package/components/tryghost-data-generator-5.36.1.tgz +0 -0
  11. package/components/{tryghost-domain-events-5.35.1.tgz → tryghost-domain-events-5.36.1.tgz} +0 -0
  12. package/components/tryghost-dynamic-routing-events-5.36.1.tgz +0 -0
  13. package/components/{tryghost-email-analytics-provider-mailgun-5.35.1.tgz → tryghost-email-analytics-provider-mailgun-5.36.1.tgz} +0 -0
  14. package/components/tryghost-email-analytics-service-5.36.1.tgz +0 -0
  15. package/components/{tryghost-email-content-generator-5.35.1.tgz → tryghost-email-content-generator-5.36.1.tgz} +0 -0
  16. package/components/{tryghost-email-events-5.35.1.tgz → tryghost-email-events-5.36.1.tgz} +0 -0
  17. package/components/{tryghost-email-service-5.35.1.tgz → tryghost-email-service-5.36.1.tgz} +0 -0
  18. package/components/{tryghost-email-suppression-list-5.35.1.tgz → tryghost-email-suppression-list-5.36.1.tgz} +0 -0
  19. package/components/tryghost-event-aware-cache-wrapper-5.36.1.tgz +0 -0
  20. package/components/{tryghost-express-dynamic-redirects-5.35.1.tgz → tryghost-express-dynamic-redirects-5.36.1.tgz} +0 -0
  21. package/components/tryghost-extract-api-key-5.36.1.tgz +0 -0
  22. package/components/{tryghost-html-to-plaintext-5.35.1.tgz → tryghost-html-to-plaintext-5.36.1.tgz} +0 -0
  23. package/components/tryghost-i18n-5.36.1.tgz +0 -0
  24. package/components/tryghost-importer-revue-5.36.1.tgz +0 -0
  25. package/components/tryghost-job-manager-5.36.1.tgz +0 -0
  26. package/components/{tryghost-link-redirects-5.35.1.tgz → tryghost-link-redirects-5.36.1.tgz} +0 -0
  27. package/components/{tryghost-link-replacer-5.35.1.tgz → tryghost-link-replacer-5.36.1.tgz} +0 -0
  28. package/components/tryghost-link-tracking-5.36.1.tgz +0 -0
  29. package/components/{tryghost-magic-link-5.35.1.tgz → tryghost-magic-link-5.36.1.tgz} +0 -0
  30. package/components/tryghost-mailgun-client-5.36.1.tgz +0 -0
  31. package/components/{tryghost-member-attribution-5.35.1.tgz → tryghost-member-attribution-5.36.1.tgz} +0 -0
  32. package/components/{tryghost-member-events-5.35.1.tgz → tryghost-member-events-5.36.1.tgz} +0 -0
  33. package/components/tryghost-members-api-5.36.1.tgz +0 -0
  34. package/components/{tryghost-members-csv-5.35.1.tgz → tryghost-members-csv-5.36.1.tgz} +0 -0
  35. package/components/{tryghost-members-events-service-5.35.1.tgz → tryghost-members-events-service-5.36.1.tgz} +0 -0
  36. package/components/tryghost-members-importer-5.36.1.tgz +0 -0
  37. package/components/{tryghost-members-offers-5.35.1.tgz → tryghost-members-offers-5.36.1.tgz} +0 -0
  38. package/components/tryghost-members-payments-5.36.1.tgz +0 -0
  39. package/components/{tryghost-members-ssr-5.35.1.tgz → tryghost-members-ssr-5.36.1.tgz} +0 -0
  40. package/components/{tryghost-members-stripe-service-5.35.1.tgz → tryghost-members-stripe-service-5.36.1.tgz} +0 -0
  41. package/components/tryghost-milestones-5.36.1.tgz +0 -0
  42. package/components/tryghost-minifier-5.36.1.tgz +0 -0
  43. package/components/tryghost-mw-api-version-mismatch-5.36.1.tgz +0 -0
  44. package/components/tryghost-mw-cache-control-5.36.1.tgz +0 -0
  45. package/components/tryghost-mw-error-handler-5.36.1.tgz +0 -0
  46. package/components/tryghost-mw-session-from-token-5.36.1.tgz +0 -0
  47. package/components/{tryghost-mw-update-user-last-seen-5.35.1.tgz → tryghost-mw-update-user-last-seen-5.36.1.tgz} +0 -0
  48. package/components/tryghost-mw-vhost-5.36.1.tgz +0 -0
  49. package/components/tryghost-oembed-service-5.36.1.tgz +0 -0
  50. package/components/tryghost-package-json-5.36.1.tgz +0 -0
  51. package/components/tryghost-referrers-5.36.1.tgz +0 -0
  52. package/components/tryghost-security-5.36.1.tgz +0 -0
  53. package/components/tryghost-session-service-5.36.1.tgz +0 -0
  54. package/components/tryghost-settings-path-manager-5.36.1.tgz +0 -0
  55. package/components/tryghost-slack-notifications-5.36.1.tgz +0 -0
  56. package/components/tryghost-staff-service-5.36.1.tgz +0 -0
  57. package/components/tryghost-stats-service-5.36.1.tgz +0 -0
  58. package/components/tryghost-tiers-5.36.1.tgz +0 -0
  59. package/components/tryghost-update-check-service-5.36.1.tgz +0 -0
  60. package/components/tryghost-verification-trigger-5.36.1.tgz +0 -0
  61. package/components/{tryghost-version-notifications-data-service-5.35.1.tgz → tryghost-version-notifications-data-service-5.36.1.tgz} +0 -0
  62. package/components/tryghost-webmentions-5.36.1.tgz +0 -0
  63. package/core/built/admin/assets/{chunk.143.3e5760df9072a9463476.js → chunk.143.26ea9f26571d656653f0.js} +6 -6
  64. package/core/built/admin/assets/{chunk.178.773722be9deba376bacb.js → chunk.178.dd71b3a764b73facc400.js} +4 -4
  65. package/core/built/admin/assets/{chunk.502.c4afca88c98edad8b268.js → chunk.502.800e1515996bcc900013.js} +3 -3
  66. package/core/built/admin/assets/{chunk.79.ec143a398298020c87e6.js → chunk.79.53e8aa9671b2d5dae8ba.js} +1 -1
  67. package/core/built/admin/assets/codemirror/{codemirror-6c43f4894cbd8db73d7f35cde836c58e.js → codemirror-3f3b9966a7237652dd31484694e38ad5.js} +1 -1
  68. package/core/built/admin/assets/{ghost-1d4b69d04b8a97e8a1bd83ed5bb20777.css → ghost-7ecf5c7934d90798485ee5ac2956f7fe.css} +1 -1
  69. package/core/built/admin/assets/{ghost-5f530fdaca961aa2ec5c339d5bb13443.js → ghost-b828e9e3c161aae92909c2e163656bb1.js} +281 -261
  70. package/core/built/admin/assets/{ghost-dark-633bf4628beead68e8a0d1fa668735ff.css → ghost-dark-e50717df8e57d3e7fee67a0bcea895ad.css} +1 -1
  71. package/core/built/admin/assets/img/mentions-background-fa39b7597e875c165b12190eda606993.png +0 -0
  72. package/core/built/admin/assets/simplemde/{simplemde-28049a9bd7f432b0648747eb26958a33.js → simplemde-9cd5549b68db674742d6ec2ecd72ac30.js} +1 -1
  73. package/core/built/admin/assets/vendor-c4684647d4f5213e5dbb6763de430e7e.js +22 -21
  74. package/core/built/admin/index.html +5 -5
  75. package/core/server/adapters/cache/MemoryTTL.js +3 -0
  76. package/core/server/api/endpoints/pages-public.js +1 -2
  77. package/core/server/api/endpoints/posts-public.js +2 -1
  78. package/core/server/api/endpoints/tags-public.js +2 -1
  79. package/core/server/api/endpoints/utils/serializers/input/index.js +4 -0
  80. package/core/server/api/endpoints/utils/serializers/input/mentions.js +11 -0
  81. package/core/server/api/endpoints/utils/serializers/output/mappers/posts.js +2 -5
  82. package/core/server/api/endpoints/utils/serializers/output/utils/clean.js +1 -0
  83. package/core/server/api/endpoints/utils/serializers/output/utils/extra-attrs.js +19 -11
  84. package/core/server/data/exporter/table-lists.js +2 -1
  85. package/core/server/data/migrations/versions/5.36/2023-02-20-12-22-add-milestones-table.js +10 -0
  86. package/core/server/data/migrations/versions/5.36/2023-02-21-12-29-add-milestone-notifications-column.js +7 -0
  87. package/core/server/data/migrations/versions/5.36/2023-02-23-10-40-set-outbound-link-tagging-based-on-source-tracking.js +31 -0
  88. package/core/server/data/schema/schema.js +9 -0
  89. package/core/server/lib/request-external.js +14 -13
  90. package/core/server/models/milestone.js +9 -0
  91. package/core/server/models/user.js +4 -1
  92. package/core/server/services/email-suppression-list/MailgunEmailSuppressionList.js +2 -0
  93. package/core/server/services/mentions/BookshelfMentionRepository.js +2 -1
  94. package/core/server/services/mentions/ResourceService.js +6 -0
  95. package/core/server/services/mentions/RoutingService.js +2 -1
  96. package/core/server/services/mentions/service.js +1 -3
  97. package/core/server/services/milestones/BookshelfMilestoneRepository.js +136 -0
  98. package/core/server/services/milestones/MilestoneQueries.js +8 -3
  99. package/core/server/services/milestones/service.js +47 -9
  100. package/core/server/services/oembed/nft-oembed.js +1 -2
  101. package/core/server/services/oembed/twitter-embed.js +2 -5
  102. package/core/server/services/posts-public/service.js +21 -9
  103. package/core/server/services/tags-public/service.js +21 -10
  104. package/core/server/services/websockets/service.js +2 -1
  105. package/core/shared/config/defaults.json +5 -2
  106. package/core/shared/labs.js +4 -3
  107. package/package.json +125 -124
  108. package/yarn.lock +151 -199
  109. package/components/tryghost-adapter-cache-redis-5.35.1.tgz +0 -0
  110. package/components/tryghost-api-framework-5.35.1.tgz +0 -0
  111. package/components/tryghost-api-version-compatibility-service-5.35.1.tgz +0 -0
  112. package/components/tryghost-bootstrap-socket-5.35.1.tgz +0 -0
  113. package/components/tryghost-constants-5.35.1.tgz +0 -0
  114. package/components/tryghost-data-generator-5.35.1.tgz +0 -0
  115. package/components/tryghost-dynamic-routing-events-5.35.1.tgz +0 -0
  116. package/components/tryghost-email-analytics-service-5.35.1.tgz +0 -0
  117. package/components/tryghost-extract-api-key-5.35.1.tgz +0 -0
  118. package/components/tryghost-i18n-5.35.1.tgz +0 -0
  119. package/components/tryghost-importer-revue-5.35.1.tgz +0 -0
  120. package/components/tryghost-job-manager-5.35.1.tgz +0 -0
  121. package/components/tryghost-link-tracking-5.35.1.tgz +0 -0
  122. package/components/tryghost-mailgun-client-5.35.1.tgz +0 -0
  123. package/components/tryghost-members-api-5.35.1.tgz +0 -0
  124. package/components/tryghost-members-importer-5.35.1.tgz +0 -0
  125. package/components/tryghost-members-payments-5.35.1.tgz +0 -0
  126. package/components/tryghost-milestones-5.35.1.tgz +0 -0
  127. package/components/tryghost-minifier-5.35.1.tgz +0 -0
  128. package/components/tryghost-mw-api-version-mismatch-5.35.1.tgz +0 -0
  129. package/components/tryghost-mw-cache-control-5.35.1.tgz +0 -0
  130. package/components/tryghost-mw-error-handler-5.35.1.tgz +0 -0
  131. package/components/tryghost-mw-session-from-token-5.35.1.tgz +0 -0
  132. package/components/tryghost-mw-vhost-5.35.1.tgz +0 -0
  133. package/components/tryghost-oembed-service-5.35.1.tgz +0 -0
  134. package/components/tryghost-package-json-5.35.1.tgz +0 -0
  135. package/components/tryghost-public-resource-repository-5.35.1.tgz +0 -0
  136. package/components/tryghost-referrers-5.35.1.tgz +0 -0
  137. package/components/tryghost-security-5.35.1.tgz +0 -0
  138. package/components/tryghost-session-service-5.35.1.tgz +0 -0
  139. package/components/tryghost-settings-path-manager-5.35.1.tgz +0 -0
  140. package/components/tryghost-slack-notifications-5.35.1.tgz +0 -0
  141. package/components/tryghost-staff-service-5.35.1.tgz +0 -0
  142. package/components/tryghost-stats-service-5.35.1.tgz +0 -0
  143. package/components/tryghost-tiers-5.35.1.tgz +0 -0
  144. package/components/tryghost-update-check-service-5.35.1.tgz +0 -0
  145. package/components/tryghost-verification-trigger-5.35.1.tgz +0 -0
  146. package/components/tryghost-webmentions-5.35.1.tgz +0 -0
  147. /package/core/built/admin/assets/{chunk.502.c4afca88c98edad8b268.js.LICENSE.txt → chunk.502.800e1515996bcc900013.js.LICENSE.txt} +0 -0
@@ -70,17 +70,15 @@ module.exports = {
70
70
  if (!id) {
71
71
  return null;
72
72
  }
73
-
74
73
  const post = await models.Post.findOne({id: id.toHexString()});
75
74
 
76
75
  if (!post) {
77
76
  return null;
78
77
  }
79
-
80
78
  return {
81
79
  id: id,
82
80
  name: post.get('title'),
83
- type: 'post'
81
+ type: post.get('type')
84
82
  };
85
83
  }
86
84
  }
@@ -0,0 +1,136 @@
1
+ const {Milestone} = require('@tryghost/milestones');
2
+
3
+ /**
4
+ * @typedef {import('@tryghost/milestones/lib/MilestonesService').IMilestoneRepository} IMilestoneRepository
5
+ * @typedef {import('@tryghost/milestones/lib/MilestonesService')} Milestone
6
+ */
7
+
8
+ /**
9
+ * @implements {IMilestoneRepository}
10
+ */
11
+ module.exports = class BookshelfMilestoneRepository {
12
+ /** @type {Object} */
13
+ #MilestoneModel;
14
+
15
+ /** @type {import('@tryghost/domain-events')} */
16
+ #DomainEvents;
17
+
18
+ /**
19
+ * @param {object} deps
20
+ * @param {object} deps.MilestoneModel Bookshelf Model
21
+ * @param {import('@tryghost/domain-events')} deps.DomainEvents
22
+ */
23
+ constructor(deps) {
24
+ this.#MilestoneModel = deps.MilestoneModel;
25
+ this.#DomainEvents = deps.DomainEvents;
26
+ }
27
+
28
+ #modelToMilestone(model) {
29
+ return Milestone.create({
30
+ id: model.get('id'),
31
+ type: model.get('type'),
32
+ value: model.get('value'),
33
+ currency: model.get('currency'),
34
+ createdAt: model.get('created_at'),
35
+ emailSentAt: model.get('email_sent_at')
36
+ });
37
+ }
38
+
39
+ /**
40
+ * @param {import('@tryghost/milestones/lib/Milestone')} milestone
41
+ * @returns {Promise<void>}
42
+ */
43
+ async save(milestone) {
44
+ const data = {
45
+ id: milestone.id.toHexString(),
46
+ type: milestone.type,
47
+ value: milestone.value,
48
+ currency: milestone?.currency,
49
+ created_at: milestone?.createdAt,
50
+ email_sent_at: milestone?.emailSentAt
51
+ };
52
+
53
+ const existing = await this.#MilestoneModel.findOne({id: data.id}, {require: false});
54
+
55
+ if (!existing) {
56
+ await this.#MilestoneModel.add(data);
57
+ } else {
58
+ await this.#MilestoneModel.edit(data, {
59
+ id: data.id
60
+ });
61
+ }
62
+ for (const event of milestone.events) {
63
+ this.#DomainEvents.dispatch(event);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * @param {'arr'|'members'} type
69
+ * @param {string} [currency]
70
+ *
71
+ * @returns {Promise<import('@tryghost/milestones/lib/Milestone')|null>}
72
+ */
73
+ async getLatestByType(type, currency = 'usd') {
74
+ let milestone = null;
75
+
76
+ if (type === 'arr') {
77
+ milestone = await this.#MilestoneModel.findAll({filter: `currency:${currency}+type:arr`, order: 'created_at ASC, value DESC'}, {require: false});
78
+ } else {
79
+ milestone = await this.#MilestoneModel.findAll({filter: 'type:members', order: 'created_at ASC, value DESC'}, {require: false});
80
+ }
81
+
82
+ if (!milestone || !milestone?.models?.length) {
83
+ return null;
84
+ } else {
85
+ milestone = milestone.models?.[0];
86
+ }
87
+
88
+ return this.#modelToMilestone(milestone);
89
+ }
90
+
91
+ /**
92
+ * @returns {Promise<import('@tryghost/milestones/lib/Milestone')|null>}
93
+ */
94
+ async getLastEmailSent() {
95
+ let milestone = await this.#MilestoneModel.findAll({filter: 'email_sent_at:-null', order: 'email_sent_at ASC'}, {require: false});
96
+
97
+ if (!milestone || !milestone?.models?.length) {
98
+ return null;
99
+ } else {
100
+ milestone = milestone.models?.[0];
101
+ }
102
+
103
+ return this.#modelToMilestone(milestone);
104
+ }
105
+
106
+ /**
107
+ * @param {number} value
108
+ * @param {string} [currency]
109
+ *
110
+ * @returns {Promise<import('@tryghost/milestones/lib/Milestone')|null>}
111
+ */
112
+ async getByARR(value, currency = 'usd') {
113
+ // find a milestone of the ARR type by a given value
114
+ const milestone = await this.#MilestoneModel.findOne({type: 'arr', currency: currency, value: value}, {require: false});
115
+
116
+ if (!milestone) {
117
+ return null;
118
+ }
119
+ return this.#modelToMilestone(milestone);
120
+ }
121
+
122
+ /**
123
+ * @param {number} value
124
+ *
125
+ * @returns {Promise<import('@tryghost/milestones/lib/Milestone')|null>}
126
+ */
127
+ async getByCount(value) {
128
+ // find a milestone of the members type by a given value
129
+ const milestone = await this.#MilestoneModel.findOne({type: 'members', value: value}, {require: false});
130
+
131
+ if (!milestone) {
132
+ return null;
133
+ }
134
+ return this.#modelToMilestone(milestone);
135
+ }
136
+ };
@@ -1,10 +1,12 @@
1
- const MIN_DAYS_SINCE_IMPORTED = 7;
2
-
3
1
  module.exports = class MilestoneQueries {
4
2
  #db;
5
3
 
4
+ /** @type {number} */
5
+ #minDaysSinceImported;
6
+
6
7
  constructor(deps) {
7
8
  this.#db = deps.db;
9
+ this.#minDaysSinceImported = deps.minDaysSinceImported;
8
10
  }
9
11
 
10
12
  /**
@@ -31,10 +33,13 @@ module.exports = class MilestoneQueries {
31
33
  * @returns {Promise<boolean>}
32
34
  */
33
35
  async hasImportedMembersInPeriod() {
36
+ const importedThreshold = new Date();
37
+ importedThreshold.setDate(importedThreshold.getDate() - this.#minDaysSinceImported);
38
+
34
39
  const [hasImportedMembers] = await this.#db.knex('members_subscribe_events')
35
40
  .count('id as count')
36
41
  .where('source', '=', 'import')
37
- .where('created_at', '>=', MIN_DAYS_SINCE_IMPORTED);
42
+ .where('created_at', '>=', importedThreshold);
38
43
 
39
44
  return hasImportedMembers?.count > 0;
40
45
  }
@@ -1,4 +1,9 @@
1
1
  const DomainEvents = require('@tryghost/domain-events');
2
+ const logging = require('@tryghost/logging');
3
+ const models = require('../../models');
4
+ const BookshelfMilestoneRepository = require('./BookshelfMilestoneRepository');
5
+
6
+ const JOB_TIMEOUT = 1000 * 60 * 60 * 24 * (Math.floor(Math.random() * 4)); // 0 - 4 days;
2
7
 
3
8
  const getStripeLiveEnabled = () => {
4
9
  const settingsCache = require('../../../shared/settings-cache');
@@ -28,19 +33,23 @@ module.exports = {
28
33
  const db = require('../../data/db');
29
34
  const MilestoneQueries = require('./MilestoneQueries');
30
35
 
31
- const {
32
- MilestonesService,
33
- InMemoryMilestoneRepository
34
- } = require('@tryghost/milestones');
36
+ const {MilestonesService} = require('@tryghost/milestones');
35
37
  const config = require('../../../shared/config');
36
38
  const milestonesConfig = config.get('milestones');
37
39
 
38
- const repository = new InMemoryMilestoneRepository({DomainEvents});
39
- const queries = new MilestoneQueries({db});
40
+ const repository = new BookshelfMilestoneRepository({
41
+ DomainEvents,
42
+ MilestoneModel: models.Milestone
43
+ });
44
+
45
+ const queries = new MilestoneQueries({
46
+ db,
47
+ minDaysSinceImported: milestonesConfig?.minDaysSinceImported || 7
48
+ });
40
49
 
41
50
  this.api = new MilestonesService({
42
51
  repository,
43
- milestonesConfig, // avoid using getters and pass as JSON
52
+ milestonesConfig,
44
53
  queries
45
54
  });
46
55
  }
@@ -69,10 +78,39 @@ module.exports = {
69
78
  },
70
79
 
71
80
  /**
81
+ *
82
+ * @param {number} [customTimeout]
83
+ *
84
+ * @returns {Promise<object>}
85
+ */
86
+ async scheduleRun(customTimeout) {
87
+ const timeOut = customTimeout || JOB_TIMEOUT;
88
+
89
+ const today = new Date();
90
+ const msNow = today.getMilliseconds();
91
+ const newMs = msNow + timeOut;
92
+ const jobDate = today.setMilliseconds(newMs);
93
+
94
+ logging.info(`Running milestone emails job on ${new Date(jobDate).toString()}`);
95
+
96
+ return new Promise((resolve) => {
97
+ setTimeout(async () => {
98
+ const result = await this.run();
99
+ return resolve(result);
100
+ }, timeOut);
101
+ });
102
+ },
103
+
104
+ /**
105
+ * @param {number} [customTimeout]
106
+ * Only used temporary for testing purposes.
107
+ * Will be removed, after job scheduling implementation.
108
+ *
72
109
  * @returns {Promise<object>}
73
110
  */
74
- async initAndRun() {
111
+ async initAndRun(customTimeout) {
75
112
  await this.init();
76
- return await this.run();
113
+
114
+ return this.scheduleRun(customTimeout);
77
115
  }
78
116
  };
@@ -42,9 +42,8 @@ class NFTOEmbedProvider {
42
42
  headers['X-API-KEY'] = this.dependencies.config.apiKey;
43
43
  }
44
44
  const result = await externalRequest(`https://api.opensea.io/api/v1/asset/${transaction}/${asset}/?format=json`, {
45
- json: true,
46
45
  headers
47
- });
46
+ }).json();
48
47
  return {
49
48
  version: '1.0',
50
49
  type: 'nft',
@@ -57,14 +57,11 @@ class TwitterOEmbedProvider {
57
57
  }).join('&');
58
58
 
59
59
  try {
60
- const result = await externalRequest(`https://api.twitter.com/2/tweets/${tweetId}?${queryString}`, {
61
- responseType: 'json',
60
+ const body = await externalRequest(`https://api.twitter.com/2/tweets/${tweetId}?${queryString}`, {
62
61
  headers: {
63
62
  Authorization: `Bearer ${this.dependencies.config.bearerToken}`
64
63
  }
65
- });
66
-
67
- const body = JSON.parse(result.body);
64
+ }).json();
68
65
 
69
66
  oembedData.tweet_data = body.data;
70
67
  oembedData.tweet_data.includes = body.includes;
@@ -6,24 +6,36 @@ class PostsPublicServiceWrapper {
6
6
  }
7
7
 
8
8
  // Wire up all the dependencies
9
- const {Post} = require('../../models');
10
9
  const adapterManager = require('../adapter-manager');
11
10
  const config = require('../../../shared/config');
11
+ const EventAwareCacheWrapper = require('@tryghost/event-aware-cache-wrapper');
12
+ const EventRegistry = require('../../lib/common/events');
12
13
 
13
14
  let postsCache;
14
15
  if (config.get('hostSettings:postsPublicCache:enabled')) {
15
- postsCache = adapterManager.getAdapter('cache:postsPublic');
16
+ const cache = adapterManager.getAdapter('cache:postsPublic');
17
+ postsCache = new EventAwareCacheWrapper({
18
+ cache: cache,
19
+ resetEvents: ['site.changed'],
20
+ eventRegistry: EventRegistry
21
+ });
16
22
  }
17
23
 
18
- const {PublicResourcesRepository} = require('@tryghost/public-resource-repository');
19
-
20
- this.postsRepository = new PublicResourcesRepository({
21
- Model: Post,
22
- cache: postsCache
23
- });
24
+ let cache;
25
+ if (postsCache) {
26
+ // @NOTE: exposing cache through getter and setter to not loose the context of "this"
27
+ cache = {
28
+ get() {
29
+ return postsCache.get(...arguments);
30
+ },
31
+ set() {
32
+ return postsCache.set(...arguments);
33
+ }
34
+ };
35
+ }
24
36
 
25
37
  this.api = {
26
- browse: this.postsRepository.getAll.bind(this.postsRepository)
38
+ cache: cache
27
39
  };
28
40
  }
29
41
  }
@@ -6,24 +6,35 @@ class TagsPublicServiceWrapper {
6
6
  }
7
7
 
8
8
  // Wire up all the dependencies
9
- const {TagPublic} = require('../../models');
10
9
  const adapterManager = require('../adapter-manager');
11
10
  const config = require('../../../shared/config');
11
+ const EventAwareCacheWrapper = require('@tryghost/event-aware-cache-wrapper');
12
+ const EventRegistry = require('../../lib/common/events');
12
13
 
13
14
  let tagsCache;
14
15
  if (config.get('hostSettings:tagsPublicCache:enabled')) {
15
- tagsCache = adapterManager.getAdapter('cache:tagsPublic');
16
+ let tagsPublicCache = adapterManager.getAdapter('cache:tagsPublic');
17
+ tagsCache = new EventAwareCacheWrapper({
18
+ cache: tagsPublicCache,
19
+ resetEvents: ['site.changed'],
20
+ eventRegistry: EventRegistry
21
+ });
16
22
  }
17
23
 
18
- const {PublicResourcesRepository} = require('@tryghost/public-resource-repository');
19
-
20
- this.tagsPublicRepository = new PublicResourcesRepository({
21
- Model: TagPublic,
22
- cache: tagsCache
23
- });
24
-
24
+ let cache;
25
+ if (tagsCache) {
26
+ // @NOTE: exposing cache through getter and setter to not loose the context of "this"
27
+ cache = {
28
+ get() {
29
+ return tagsCache.get(...arguments);
30
+ },
31
+ set() {
32
+ return tagsCache.set(...arguments);
33
+ }
34
+ };
35
+ }
25
36
  this.api = {
26
- browse: this.tagsPublicRepository.getAll.bind(this.tagsPublicRepository)
37
+ cache: cache
27
38
  };
28
39
  }
29
40
  }
@@ -15,7 +15,8 @@ module.exports = {
15
15
  let count = 0;
16
16
 
17
17
  io.on(`connection`, (socket) => {
18
- debug(`[Websockets] Client connected`);
18
+ logging.info(`Websockets client connected (id: ${socket.id})`);
19
+
19
20
  // on connect, send current value
20
21
  socket.emit('addCount', count);
21
22
  // listen to to changes in value from client
@@ -176,7 +176,7 @@
176
176
  },
177
177
  "portal": {
178
178
  "url": "https://cdn.jsdelivr.net/ghost/portal@~{version}/umd/portal.min.js",
179
- "version": "2.24"
179
+ "version": "2.25"
180
180
  },
181
181
  "sodoSearch": {
182
182
  "url": "https://cdn.jsdelivr.net/ghost/sodo-search@~{version}/umd/sodo-search.min.js",
@@ -213,6 +213,9 @@
213
213
  "values": [100, 1000, 10000, 50000, 100000, 250000, 500000, 1000000]
214
214
  }
215
215
  ],
216
- "members": [100, 1000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000]
216
+ "members": [100, 1000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000],
217
+ "minDaysSinceImported": 7,
218
+ "minDaysSinceLastEmail": 14,
219
+ "maxPercentageFromMilestone": 0.1
217
220
  }
218
221
  }
@@ -21,7 +21,8 @@ const GA_FEATURES = [
21
21
  'audienceFeedback',
22
22
  'themeErrorsNotification',
23
23
  'emailStability',
24
- 'emailErrors'
24
+ 'emailErrors',
25
+ 'outboundLinkTagging'
25
26
  ];
26
27
 
27
28
  // NOTE: this allowlist is meant to be used to filter out any unexpected
@@ -36,8 +37,8 @@ const ALPHA_FEATURES = [
36
37
  'urlCache',
37
38
  'beforeAfterCard',
38
39
  'lexicalEditor',
39
- 'outboundLinkTagging',
40
- 'websockets'
40
+ 'websockets',
41
+ 'webmentionEmails'
41
42
  ];
42
43
 
43
44
  module.exports.GA_KEYS = [...GA_FEATURES];